C全局静态变量初始化是由链接器完成的?

标签 c gcc linker symbol-table

假设我们有:

f1.c

#include <stdio.h>
static int x = 10;

void f1() {
  printf("f1.c : %d\n", x);
}

主.c

extern void f1();
int main(int argc, char **argv) {
  f1();
  return 0;
}

我们将编译和读取两个 ELF 文件符号表(rel.ELF 和 exec ELF):

$> 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

通过读取可重定位对象,可以看到全局静态变量xValue(也就是地址)是0000000000000000文件 f1.o.
这意味着我们还没有初始化它,因为它仍然是一个 rel。 ELF 目标文件和链接器将处理此问题。

那么我的问题是,如果链接器在链接 0000000000601038 之后将已知地址处的 x 的值设置为 10,它是如何做到的?链接器从哪里获得信息以将值设置为 10 以及谁提供此信息 (f1.o?)?

最佳答案

0000000000000000(在目标文件 f1.o 中)是一个相对地址(静态变量的),因此是一个偏移量, 该文件还包含 relocation与其相关的指令。用于打印参数 x 的代码也有一些重定位(在一些加载机器指令上)。

在该目标文件中,您可能有一个 .data 部分。该部分应以包含 10 的单词(具有您在 f1.o 中观察到的 0 偏移量)开头。

阅读更多关于 linkers 的信息(我推荐 Levine 的 Linkers and loaders 书)。链接进程(获取 ELF 可执行文件)正在处理重定位指令。另请阅读有关 ELF 格式的更多信息,从 elf(5) 开始(在阅读了 ELF 维基页面之后)。也学习ABI规范(对于 Linux x86-64,请参阅 here 来自 this 答案)详细说明了可能的重定位指令。

您可能希望使用 gcc -Wall -S -fverbose-asm -O1 f1.c 编译您的 f1.c 然后查看生成的汇编程序文件 f1.s

您可能还想使用各种工具(如 readelf(1))检查目标文件 f1.o 和 ELF 可执行文件 a.outobjdump(1) .两者都接受许多选项(特别是 objdump-r 选项以显示重定位指令)。

Dynamic linking (属于 C standard library libc.*.so)在 ELF 可执行文件中引入了一些额外的复杂性。另见 ld-linux(8) (它在运行时开始时做一些链接工作)和 vdso(7) .您可能还想阅读 Drepper 的 How To Write Shared Libraries纸。

免费教科书 Operating Systems: Three Easy Pieces也可能值得一读(它解释了 process 是什么以及它的执行过程)。

关于C全局静态变量初始化是由链接器完成的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44962697/

相关文章:

c - 使用c语言发送向上向下箭头键以通过linux中的管道进行处理

c - 使用 GCC 编译 C 项目时使用了哪些默认库

apache - 使用 LLVM Plus 自定义 channel 和自定义库编译 Apache Server

c++ - std::unordered_map::emplace 问题与私有(private)/删除的复制构造函数

windows - MinGW g++ : Multiple definition of vsnprintf when using to_string

c++ - 在不加载 DLL 的情况下使用函数?

visual-studio-2008 - "LNK2022: metadata operation failed"把我逼疯了

c - 不使用数组来反转数字的程序

c - 如何在c程序中获取使用system()启动的进程的PID

c - 为什么在c语言中EOF IS -1?