关于链接脚本中位置计数器赋值的技术咨询(附测试代码)
搞懂链接脚本里的位置计数器——以你的代码为例
嘿,我来帮你把这个位置计数器的问题掰扯清楚,咱们结合你写的代码和链接脚本一步步分析,你就能明白它在输出段里的工作逻辑了。
先明确核心规则
链接脚本里的.就是咱们说的位置计数器,它的作用是跟踪当前正在处理的内存地址。这里要注意两个关键场景:
- 如果是在所有输出段定义之外(或者刚进入段定义的开头),它是全局的位置计数器,管着整个可执行文件的地址进度;
- 如果是在某个输出段内部,它就只负责当前这个段的地址位置,修改它只会影响当前段里后续内容的地址,不会波及外面。
逐行拆解你的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
相关产品推荐
相关产品推荐

