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

关于指向只读数据的指针变量的重定位机制、.data.rel.local节作用及GOT相关疑问

关于指向只读数据的指针变量的重定位机制、.data.rel.local节作用及GOT相关疑问

我来一步步拆解你遇到的这些问题,先从变量的本质差异说起,再结合你的代码、反汇编结果逐个解释概念和流程。

一、先明确两个变量的本质差异

你的代码里两个全局/静态变量的核心区别,直接决定了它们的存储位置和重定位方式:

  • static int order = 5;:这是一个已初始化的非const数值变量,它的初始值5是编译时就能确定的固定值,不需要链接阶段修改,所以直接放在.data节。
  • char *and_the = "DDD";:这是一个可写的指针变量,它本身需要存储一个地址值——也就是只读数据段.rodata中字符串"DDD"的内存地址。但这个地址在编译阶段是完全未知的,必须等到链接阶段才能确定,所以这个指针变量的初始值需要链接器来填充,这就涉及到重定位逻辑。

二、.data.rel.local 节到底是什么?

我们把它和普通.data节做对比,就能快速理解:

  • .data:存储已初始化、且初始值不需要链接时修改的全局/静态变量(比如order,值是5,编译时就确定,链接时不需要改动)。
  • .data.rel.local:存储**已初始化、但初始值是需要链接时解析的地址(即需要重定位),且重定位仅影响当前模块(本地)**的变量。简单说:这些变量本身是可写的,但它们的初始值只是个“占位符”,需要链接器把真实的内存地址填进去,而且这个重定位操作只和当前模块内的符号有关,不需要涉及其他模块的PLT/GOT。

你的and_the就属于这种:它是可写的指针变量,初始值要指向.rodata的"DDD",但这个地址编译时未知,所以暂时把它放在.data.rel.local节,等链接时填充真实地址。(链接完成后,.data.rel.local会被合并到.data节,所以你在最终可执行文件里看到and_the在.data里)

三、and_the的重定位流程(结合你的反汇编)

我们分编译、链接、运行三个阶段看:

  1. 编译阶段:
    编译器不知道.rodata中"DDD"的最终地址,所以给and_the分配一块8字节的内存(x86_64指针长度),初始值填0,放在.data.rel.local节。同时生成访问and_the的指令:

    2b: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 32 <main+0x32>
    2e: R_X86_64_REX_GOTPCRELX and_the-0x4
    

    这里的R_X86_64_REX_GOTPCRELX是x86_64的优化重定位类型,编译器先按“通过GOT访问”的通用逻辑生成指令,因为它无法提前预知链接时是否能优化成直接访问。

  2. 链接阶段:

    • 链接器先确定.rodata中"DDD"的最终地址,把这个地址写入.data.rel.local里and_the对应的内存位置。
    • 同时,链接器发现and_the是当前模块的符号(指向的.rodata也是本模块内的),所以对R_X86_64_REX_GOTPCRELX重定位做折叠优化:不需要真的走GOT,直接计算出and_the在.data节的地址相对于当前指令的RIP偏移,把指令里的0x0替换成正确的偏移量。
  3. 运行阶段:
    执行mov 0x0(%rip),%rax时,会直接从.data节的and_the变量中读取到.rodata里"DDD"的地址,然后把这个地址传给printf,就可以打印字符串了。

四、解答你最困惑的问题:为什么需要.data里的and_the符号?

你混淆了and_the变量和GOT的作用:

  • and_the本身是一个可写的指针变量——你完全可以在代码里加一句and_the = "Hello World";来修改它的值,这就要求必须有一块可写的内存(也就是.data里的and_the)来存储这个指针值。
  • GOT的作用通常是跨模块访问外部符号(比如你调用printf时用的R_X86_64_PLT32 printf-0x4,就是通过PLT+GOT来调用外部标准库的函数)。但对于and_the这种本模块内的可写指针变量,根本不需要GOT来存储地址——and_the自己的内存就是用来存.rodata地址的地方。

那为什么反汇编里会出现GOT相关的重定位?因为编译时编译器无法提前知道链接时能不能做优化,所以先按通用的GOT访问逻辑生成指令,链接器会根据符号的实际情况(本地/外部)来决定是否优化成直接访问。

再对比order和and_the的重定位差异

  • order:是数值变量,直接存储值5,访问时需要通过RIP相对寻址找到它在.data的地址,所以重定位是R_X86_64_PC32 .data-0x4,用来计算order相对于当前指令的偏移。
  • and_the:是指针变量,需要存储另一个地址(.rodata的"DDD"),所以它自己的内存需要链接时填充值,访问时先读这个变量里的地址,再去.rodata取字符串。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 07:04:49