- 所谓重定位就是把一块数据从这个地址移动到另外一个地址,怎么确定这块数据的源、目的、长度呢?
- 想要重定位.data段和.rodata段,就要知道两段源(起始地址)、目的(目的地址:链接地址)、长度(结束地址)
- 怎么确定源(加载地址)和目的地址(链接地址)?

- 从链接脚本中可以获取_start、_rodata_start的链接地址
- 编写代码时可以直接获取_start的加载地址(因为_start是在汇编文件.s中指定的),但无法直接获取_rodata_start的加载地址
- 所有在链接脚本中定义的参数都是用的链接地址
- _start链接地址与加载地址的偏差就等于_rodata_start链接地址与加载地址的偏差,从而可以算出_rodata_start的加载地址
怎么获取_start的加载地址和链接地址?
- _start参数是在汇编文件中指定的,当使用ldr伪指令获取时得到的是链接地址,当使用adr伪指令获取时得到的是基于PC+offset的加载地址(adr取出当前标号的地址)
用ADR伪指令获得当前代码(当前代码位于加载地址处)的地址:
.text.global _start_start:......adr r0, _start
adr是伪指令,它最终要转换为真实的指令。它怎么获得
_start代码的当前所处地址呢?实际上,adr r0, _start指令的本质是r0 = pc - offset,offset是在链接时就确定了- offset链接时确定,因此当程序还位于加载地址处时得到的_start地址就是其加载地址了
用LDR伪指令确定链接地址
.text.global _start_start:......ldr r0, =_start
ldr是伪指令,它最终要转换为真实的指令。它怎么获得
_start的链接地址呢?_start的链接地址在链接时,由链接脚本确定。
在链接脚本里可以定义各类符号,在代码里读取这些符号的值
修改链接脚本
SECTIONS {. = 0xC0200000; /* 对于STM32MP157设置链接地址为0xC0200000, 对于IMX6ULL设为0x80200000 */. = ALIGN(4);.text :{*(.text)}. = ALIGN(4);__rodata_start = .;.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);__bss_start = .;.bss : { *(.bss) *(.COMMON) }__bss_end = .;}
修改start.S
.text.global _start_start:ldr r0, =__data_start /* r0 : 目的: 链接地址 *//* 计算data段的当前地址:* _start的链接地址 - _start的当前地址 = __rodata_start的链接地址 - rodata段的当前地址* data段的当前地址 = __rodata_start的链接地址 - (_start的链接地址 - _start的当前地址)*/ldr r0, =__rodata_startldr r2, =_start /* link addr */adr r3, _start /* load addr */sub r2, r2, r3sub r1, r0, r2 /* r1 : 源 */ldr r3, =__bss_startsub r2, r3, r0 /* r2: 长度 */bl memcpy /* r0: 目的, r1: 源, r2:长度 */
