在32位编译反汇编结果中定位"Hello"字符串及指令疑问
OS-dev代码反汇编疑问解答
问题背景
正在学习Nick Blundell所著《OS-dev》书籍的5.1.4节,对一段C代码的反汇编结果存在两个疑问:
编写的C代码(string.c)
void my_function() { char* str = "Hello"; }
编译、链接、反汇编命令
在64位Linux环境下以32位模式操作:
- 编译:
gcc -ffreestanding -fno-pie -m32 -c string.c -o string.o
- 链接:
ld -m elf_i386 -o string.bin -Ttext 0x0 --oformat binary string.o
- 反汇编:
ndisasm -b 32 string.bin > string.dis
得到的反汇编结果
00000000 55 push ebp 00000001 89E5 mov ebp,esp 00000003 83EC10 sub esp,byte +0x10 00000006 C745FC00100000 mov dword [ebp-0x4],0x1000 0000000D 90 nop 0000000E C9 leave 0000000F C3 ret
疑问:
- 编译器分配了16字节栈空间,但反汇编结果里找不到"Hello"字符串的位置
- 不理解第4行
mov dword [ebp-0x4],0x1000指令的作用
解答
1. 找不到"Hello"字符串的原因
你使用ld链接时指定了--oformat binary,这个参数会让链接器只输出可执行的.text段内容。而C语言中的字符串常量"Hello"默认被编译器放在.rodata(只读数据段)中,不属于.text段。二进制输出模式下,非.text段的内容不会被打包到string.bin里,所以反汇编结果里自然看不到它。
要验证这一点,可以直接反汇编目标文件查看所有段:
objdump -d -M intel -m i386 string.o
或者用readelf -S string.o查看目标文件的段信息,就能在.rodata段里找到"Hello\0"的内容。
2. 第4行指令的作用
这条指令是给栈上的str变量赋值:ebp-0x4是str在栈帧中的位置,0x1000是"Hello"字符串在最终程序中的内存地址。
因为你链接时用了-Ttext 0x0,指定.text段从0x0地址开始,而.rodata段默认会被链接器放在.text段之后,所以字符串的起始地址被分配到了0x1000(这个地址可能因编译器/链接器版本略有不同)。
另外,栈上分配16字节(sub esp,0x10)是因为gcc的16字节栈对齐规则——32位模式下,编译器会强制栈帧对齐到16字节边界,即使只需要4字节存放指针,也会额外分配空间满足对齐要求。末尾的nop指令也是为了让函数指令序列符合对齐规范。
内容的提问来源于stack exchange,提问作者Alexander the Great
相关产品推荐
相关产品推荐

