You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解读ELF文件中ABS符号的值及链接相关技术问题

关于libc.a中ABS符号_nl_current_LC_COLLATE_used的疑问

我在查看libc.a文件中的符号时,发现了一些ABS符号,例如_nl_current_LC_COLLATE_used。以下是readelf对libc.a文件的输出:

File: libc.a(setlocale.o)

Symbol table '.symtab' contains 77 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
    39: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _nl_current_LC_COLLATE_used
   ...


File: libc.a(uselocale.o)

Symbol table '.symtab' contains 34 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
     6: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _nl_current_LC_COLLATE_used
   ...
   

File: libc.a(lc-collate.o)

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
     1: 0000000000000002     0 NOTYPE  GLOBAL DEFAULT  ABS _nl_current_LC_COLLATE_used
   ...

重定位信息如下:

File: libc.a(setlocale.o)

Relocation section '.rela.text' at offset 0x1b98 contains 124 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
...
00000000000009a3  0000002700000009 R_X86_64_GOTPCREL      0000000000000000 _nl_current_LC_COLLATE_used - 5
...


Relocation section '.rela.data.rel.ro' at offset 0x2738 contains 13 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
...
0000000000000098  0000002700000001 R_X86_64_64            0000000000000000 _nl_current_LC_COLLATE_used + 0
...


File: libc.a(uselocale.o)

Relocation section '.rela.text' at offset 0x838 contains 29 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
...
0000000000000029  0000000600000009 R_X86_64_GOTPCREL      0000000000000000 _nl_current_LC_COLLATE_used - 5
...

该符号是两次R_X86_64_GOTPCREL重定位和一次R_X86_64_64重定位的目标,这意味着需要该符号的地址,因此它必须在进程内存中定义。

该符号在3个文件中出现:两次作为WEAK UNDEFINED符号,一次作为值为2的ABS符号,且无其他定义。当编译简单的helloworld.c并链接libc.a时,必须使用该符号的定义生成最终二进制,但该符号无关联节,仅值为2。

根据ELF规范,SHN_ABS表示对应引用的绝对值,即引用该节的符号已有绝对值,不受重定位影响。但2并非该符号的绝对地址,查看libc源码可知,_nl_current_LC_COLLATE_used通过宏和asm指令定义为值为2的const整数。

我存在以下疑问:

  • 最终二进制中,值2存储在哪里?是否由链接器创建新数据节存储所有ABS符号的值?
  • 若如此,链接器如何确定每个ABS符号值的大小?此处源码显示值2应存储为64位整数,但.symtab的size字段为0。
  • 链接器如何判断该符号应存储在只读还是可读写数据节?

解答

1. 值2的存储位置

链接器不会为这类ABS符号创建新的数据节。因为这个符号本质是一个编译期确定的常量值,而非需要分配内存的变量。处理重定位时,链接器会直接将符号的绝对值(也就是2)代入到对应的引用位置:

  • 对于R_X86_64_64这类直接寻址的重定位,会直接把2写入到目标地址;
  • 对于R_X86_64_GOTPCREL这类需要地址的重定位,这里的逻辑是源码将该常量当作“伪地址”使用,链接器会把2作为该符号的"地址"值完成计算,不需要额外存储,直接替换重定位后的结果。

2. 符号大小的确定

.symtab里的size字段为0,是因为这类ABS符号没有关联到实际的节数据,只是一个纯符号值,所以不需要记录大小。链接器会通过两个上下文信息推断大小:

  • 重定位类型:比如R_X86_64_64是64位重定位,说明需要处理的是64位数据;
  • 源码定义:从libc源码的宏和汇编定义可以明确这是一个64位整数,链接器在处理时会遵循这个定义。

3. 只读/可读写节的判断

这类ABS符号本身不是内存中的变量,而是编译时固定的常量,所以不会被放到任何数据节里。因为_nl_current_LC_COLLATE_used是const整数,所有引用它的地方都会被直接替换成固定值2,运行时不存在可修改的存储。如果是可修改的ABS符号(非常见场景),链接器才会将其分配到可读写数据节,但这里显然不属于这种情况。


内容的提问来源于stack exchange,提问作者Orel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 20:24:51