【问题标题】:C global static variable initialization is done by linker?C全局静态变量初始化是由链接器完成的吗?
【发布时间】:2017-12-11 06:36:03
【问题描述】:

假设我们有:

f1.c

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

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

main.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

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

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

【问题讨论】:

  • 这里的Value是变量x地址,不是x的值
  • @ChrisDodd 是的,我已经注意到,在最初的问题中已经不是混淆了,我明白它听起来像是我的意思是因为它没有被初始化。跨度>

标签: c gcc linker symbol-table


【解决方案1】:

该段存储具有特定值的静态存储持续时间变量,称为.data(这是 ELF 标准使用的名称,但其他链接器也倾向于使用相同的名称)。

如何设置这些变量取决于目标系统。

  • 在基于 RAM 的系统(例如 PC)上,整个 .data 段被预先初始化为可执行文件的一部分,并与程序一起加载到 RAM 中。
  • 在基于 ROM 的系统(例如带有闪存的微控制器)上,.data 无法提前初始化。相反,在调用 main() 之前,它会通过一些启动代码(“CRT”)从 ROM 复制到 RAM。所以它实际上是在运行时设置的,这意味着在此类系统上程序启动时总是存在延迟。为了摆脱延迟,通常有一个非标准的启动替代方案(“最小”),它完全跳过静态存储持续时间变量的初始化。

【讨论】:

    【解决方案2】:

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

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

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

    您可能想用gcc -Wall -S -fverbose-asm -O1 f1.c 编译您的f1.c,然后查看发出的汇编文件f1.s

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

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

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

    【讨论】:

      猜你喜欢
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多