为何GCC会在函数开头插入callq指令?附代码编译反汇编示例
为什么GCC会在函数开头插入
callq指令? 咱们先看看你提供的代码和反汇编结果,再一步步拆解背后的原因:
代码示例
int foo(void); int __attribute__((noinline)) xxx(int a) { return a+3; } int my_main(void) { int pos; pos = foo(); if (pos) return 1; return xxx(3); }
编译命令
gcc -O3 -g -c main.c
关键反汇编结果
Disassembly of section .text: 0000000000000000 <xxx>: 0: 8d 47 03 lea 0x3(%rdi),%eax 3: c3 retq 0000000000000010 <my_main>: 10: 48 83 ec 08 sub $0x8,%rsp 14: e8 00 00 00 00 callq 19 <my_main+0x9>
这个callq其实是GCC为外部未定义函数foo()生成的PLT(过程链接表)占位调用,核心逻辑如下:
foo只做了声明但没有实现,属于外部符号,在编译阶段GCC根本不知道它的实际内存地址。- 你看到的
e8 00 00 00 00是临时占位的机器码,反汇编显示的callq 19 <my_main+0x9>只是当前指令地址(0x14)加上指令长度(5字节)得到的临时偏移,并不是最终要调用的真实地址。 - 等到链接阶段(不管是静态链接还是动态链接),链接器会把这个占位的偏移修正为指向PLT中对应
foo的条目,程序运行时PLT会负责动态解析foo的实际地址并完成调用。
简单来说,这个callq就是对应代码里pos = foo();这行调用,只是因为foo是外部函数,编译阶段只能先生成占位的调用指令,等链接时再补全真实地址。
如果foo是在同一个编译单元里定义的,或者链接时静态链接了包含foo的目标文件,GCC会直接生成指向foo的直接调用指令,就不会出现这种占位的callq了。
内容的提问来源于stack exchange,提问作者Changbin Du
相关产品推荐
相关产品推荐

