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

关于链接脚本中位置计数器赋值的技术咨询(附测试代码)

搞懂链接脚本里的位置计数器——以你的代码为例

嘿,我来帮你把这个位置计数器的问题掰扯清楚,咱们结合你写的代码和链接脚本一步步分析,你就能明白它在输出段里的工作逻辑了。

先明确核心规则

链接脚本里的.就是咱们说的位置计数器,它的作用是跟踪当前正在处理的内存地址。这里要注意两个关键场景:

  • 如果是在所有输出段定义之外(或者刚进入段定义的开头),它是全局的位置计数器,管着整个可执行文件的地址进度;
  • 如果是在某个输出段内部,它就只负责当前这个段的地址位置,修改它只会影响当前段里后续内容的地址,不会波及外面。

逐行拆解你的test.lds链接脚本

先把你的链接脚本贴出来,咱们逐行看:

SECTIONS {
 . = 0x10;          # 第一步:把全局位置计数器直接设成0x10
 label_1 = .;       # 第二步:给label_1绑定当前的全局位置值,也就是0x10
 custom_section : { # 第三步:定义一个叫custom_section的输出段
  . = 0x20;         # 第四步:把这个段内部的位置计数器重置为0x20
  label_2 = . ;     # 第五步:label_2绑定到当前段内的位置计数器值——0x20
  label_3 = ABSOLUTE(.) ; # 第六步:用ABSOLUTE强制把当前位置转成绝对地址,还是0x20
  *(.text) ;        # 第七步:把所有输入文件的.text段内容放到当前位置(从0x20开始)
 }
}

每个符号的地址为啥是这样?

  • label_1: 它是在全局位置计数器被设为0x10的时候赋值的,所以它的绝对地址就是0x10,这和你用nm看到的结果完全一致。
  • label_2: 在custom_section内部,咱们把段内的位置计数器改成了0x20,此时赋值label_2 = .,这里的.指的就是当前输出段的虚拟内存地址(VMA),所以label_2的绝对地址也是0x20。要记住:这个值是固定的,后续哪怕修改段内的位置计数器,label_2也不会变——它只记录赋值那一刻的位置。
  • label_3: ABSOLUTE(.)的作用是强制把位置计数器的值转换成绝对内存地址,而不是相对于当前段的偏移。在你的例子里,因为段内的位置计数器本身就是绝对地址0x20,所以label_3和label_2的地址完全一样。那什么时候这个关键字有用?比如如果你的段用AT()指定了加载地址(LMA)和虚拟地址(VMA)不一样,此时.在段内是VMA,ABSOLUTE(.)会直接返回这个VMA的绝对地址,而如果不加的话,某些场景下可能会被解析为段内的偏移量。
  • _start: 你写的test.s里的.text段会被放到custom_section的当前位置(也就是0x20开始),而_start是.text段的入口,所以它的地址就是0x20——因为你的.text段里只有那几条指令,没有其他内容,起始地址正好就是位置计数器的值。

容易踩的误区

你可能会纳闷:为啥在custom_section里改.不会影响全局的位置计数器?因为段内的位置计数器是局部专属的,修改它只会改变当前段后续内容的地址,不会影响段外的全局进度。举个例子,如果你的.text段大小是8字节(假设那三条mov和int指令占8字节),那custom_section结束后,全局位置计数器会变成0x20 + 8 = 0x28,这时候如果再定义一个label_4 = .,它的地址就是0x28。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:59:25