C语言静态链接中static与非static函数的重定位差异疑问
问题解答
这是C语言的全局符号规则和编译链接的分工特性决定的,核心原因如下:
- 首先明确
gcc -c的作用:仅完成编译、汇编步骤,生成可重定位目标文件,不执行链接操作,不会解析和绑定最终的符号地址。 - 非static修饰的全局函数默认是外部链接属性,符合C标准的全局符号覆盖规则:即使该函数在当前源文件有完整定义,链接阶段也允许被其他目标文件、动态库中的同名全局函数覆盖(也就是符号插入特性)。所以编译器在汇编阶段不能直接确定foo的最终地址,必须给call指令预留重定位空位,由后续链接阶段根据最终的符号绑定结果填充正确的地址偏移,你看到的第一段汇编中
e8 00 00 00 00就是预留的待重定位位置。 - static修饰的函数是内部链接属性,仅在当前编译单元(也就是你这个.c文件编译出来的目标文件)可见,不可能被外部的同名符号覆盖,所以汇编阶段就能直接计算出foo相对于call指令的固定偏移,直接填充到指令中,不需要后续重定位,你看到的第二段汇编中
e8 e4 ff ff ff就是已经计算好的相对偏移,可以直接定位到当前文件内的foo函数入口。
补充说明:你可以尝试给gcc添加-fno-semantic-interposition参数编译非static版本的代码,这个参数会告诉编译器假设当前文件的全局函数不会被外部覆盖,这种情况下编译器也会直接填充call的偏移,不需要重定位。
内容的提问来源于stack exchange,提问作者john
相关产品推荐
相关产品推荐

