为何C语言Hello World目标文件反汇编后无printf与字符串?
我用gcc Hello.c -c Hello.o将C源码编译为目标文件,再通过objdump -D -Mamd64 ./Hello.o >> a.s反汇编生成a.s文件,但在结果里看不到"Hello, World!"字符串,也找不到printf相关的汇编代码。
C源码
#include <stdio.h> int main(void) { printf("Hello, World!"); return 0; }
反汇编文件内容
./Hello.o: file format pe-i386 Disassembly of section .text: 00000000 <_main>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 e4 f0 and $0xfffffff0,%esp 6: 83 ec 10 sub $0x10,%esp 9: e8 00 00 00 00 call e <_main+0xe> e: c7 04 24 00 00 00 00 movl $0x0,(%esp) 15: e8 00 00 00 00 call 1a <_main+0x1a> 1a: b8 00 00 00 00 mov $0x0,%eax 1f: c9 leave 20: c3 ret 21: 90 nop 22: 90 nop 23: 90 nop Disassembly of section .rdata: 00000000 <.rdata>: 0: 48 dec %eax 1: 65 6c gs insb (%dx),%es:(%edi) 3: 6c insb (%dx),%es:(%edi) 4: 6f outsl %ds:(%esi),(%dx) 5: 2c 20 sub $0x20,%al 7: 57 push %edi 8: 6f outsl %ds:(%esi),(%dx) 9: 72 6c jb 77 <.rdata+0x77> b: 64 21 00 and %eax,%fs:(%eax) ... Disassembly of section .rdata$zzz: 00000000 <.rdata$zzz>: 0: 47 inc %edi 1: 43 inc %ebx 2: 43 inc %ebx 3: 3a 20 cmp (%eax),%ah 5: 28 4d 69 sub %cl,0x69(%ebp) 8: 6e outsb %ds:(%esi),(%dx) 9: 47 inc %edi a: 57 push %edi b: 2e 6f outsl %cs:(%esi),(%dx) d: 72 67 jb 76 <.rdata$zzz+0x76> f: 20 47 43 and %al,0x43(%edi) 12: 43 inc %ebx 13: 2d 36 2e 33 2e sub $0x2e332e36,%eax 18: 30 2d 31 29 20 36 xor %ch,0x36202931 1e: 2e 33 2e xor %cs:(%esi),%ebp 21: 30 00 xor %al,(%eax) ... Disassembly of section .eh_frame: 00000000 <.eh_frame>: 0: 14 00 adc $0x0,%al 2: 00 00 add %al,(%eax) 4: 00 00 add %al,(%eax) 6: 00 00 add %al,(%eax) 8: 01 7a 52 add %edi,0x52(%edx) b: 00 01 add %al,(%ecx) d: 7c 08 jl 17 <.eh_frame+0x17> f: 01 1b add %ebx,(%ebx) 11: 0c 04 or $0x4,%al 13: 04 88 add $0x88,%al 15: 01 00 add %eax,(%eax) 17: 00 1c 00 add %bl,(%eax,%eax,1) 1a: 00 00 add %al,(%eax) 1c: 1c 00 sbb $0x0,%al 1e: 00 00 add %al,(%eax) 20: 04 00 add $0x0,%al 22: 00 00 add %al,(%eax) 24: 21 00 and %eax,(%eax) 26: 00 00 add %al,(%eax) 28: 00 41 0e add %al,0xe(%ecx) 2b: 08 85 02 42 0d 05 or %al,0x50d4202(%ebp) 31: 5d pop %ebp 32: c5 0c 04 lds (%esp,%eax,1),%ecx 35: 04 00 add $0x0,%al ...
原因及解决办法
1. 目标文件未完成链接,printf是外部引用
-c参数只做编译不链接,生成的目标文件里只会保留对printf的调用占位,不会包含printf的实现代码。你看到的call 00000000是链接前的占位地址,链接阶段才会替换成printf的真实地址。
2. 字符串存在但被当成指令解析
"Hello, World!"的ASCII码是48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21,对应你反汇编结果里.rdata节的前13个字节。但objdump -D会把所有节都当成代码段解析,所以把字符串字节翻译成了dec、insb这些无关指令。要查看原始字符串,用objdump -s Hello.o,它会以字节和ASCII形式显示各节内容。
3. 指令集参数不匹配
你的目标文件是32位PE格式(pe-i386),但反汇编时用了-Mamd64(64位x86语法),导致指令显示异常。应该用32位语法参数,比如-Mi386或-Mintel。
正确操作步骤
生成可执行文件(包含链接):
gcc Hello.c -o Hello.exe反汇编可执行文件:
objdump -D -Mi386 Hello.exe >> a.s这样就能看到printf的调用逻辑(如果是动态链接会显示PLT stub,静态链接则会包含完整的printf实现),同时字符串也会在对应数据节中正确显示。
查看目标文件的字符串和符号:
若只想看目标文件里的字符串和符号引用,不用反汇编代码:objdump -s -t Hello.o-s显示各节的字节和ASCII内容,-t显示符号表,能看到printf是未定义的外部符号。
内容的提问来源于stack exchange,提问作者rahulc0dy

