假设我们有:一层c#include <stdio.h>static int x = 10;void f1() { printf("f1.c : %d\n", x);}主cextern void f1();int main(int argc, char **argv) { f1(); return 0;}我们将编译并读取两个ELF文件symboltables(rel。精灵和执行精灵):$> gcc -c *.c$> readelf -s f1.o | grep x Num: Value Size Type Bind Vis Ndx Name 5: 0000000000000000 4 OBJECT LOCAL DEFAULT 3 x$> gcc *.o$> readelf -s a.out | grep x Num: Value Size Type Bind Vis Ndx Name 38: 0000000000601038 4 OBJECT LOCAL DEFAULT 25 x我可以看到全局静态变量Value在读取可重定位对象文件x时0000000000000000(也称为地址)。这意味着我们还没有初始化它,因为它仍然是rel。ELF对象文件和链接器会处理这个问题。所以我的问题是,如果链接器是在链接f1.o后在已知地址将x的值设置为10的链接器,它是如何做到的?链接器从何处获取信息以将值设置为10,以及谁提供此信息(0000000000601038?)? 最佳答案 值0000000000000000(在对象文件f1.o中)是(静态变量的)相对地址,偏移量也是,该文件还包含与其相关的relocation指令。使参数x打印的代码也有一些重定位(在某些加载机器指令上)。在该对象文件中,可能有一个.data部分。该部分应该以一个包含10的单词开头(具有您在f1.o中观察到的0偏移量)。阅读更多关于linkers的内容(我推荐Levine的Linkers and loaders书)。链接过程(获取ELF可执行文件)正在处理重定位指令。阅读更多关于ELF格式的内容,从elf(5)开始(在阅读了ELFwikipage之后)。还要研究ABI规范(对于Linux x86-64,请参见here中的this答案),该规范详细说明了可能的重新定位指令。您可能需要用f1.c编译gcc -Wall -S -fverbose-asm -O1 f1.c文件,然后查看发出的汇编文件f1.s您可能还希望使用各种工具(如readelf(1)和objdump(1))检查对象文件f1.o和ELF可执行文件a.out。两者都接受许多选项(特别是-r选项到objdump以显示重新定位指令)。Dynamic linking(AA> )在ELF可执行文件中引入了一些额外的复杂性。另请参见C standard library(它在运行时开始时执行一些链接作业)和ld-linux(8)。您可能还想阅读Dreper的vdso(7)论文。免费提供的教科书How To Write Shared Libraries也值得一读(它解释了什么是Operating Systems: Three Easy Pieces以及如何执行)。关于c - C全局静态变量初始化是由链接器完成的吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44962697/
10-14 16:44