如何从 ARM 汇编中的位置独立代码 (PIC) 访问数据?
How to access data from Position Independent Code (PIC) in ARM Assembly?
我正在使用 GCC 选项 -mpic-data-is-text-relative
和 -fpic
生成与位置无关的代码。这适用于我的 C 代码。
但是我也有需要使用PIC的汇编代码。问题是我找不到关于如何实现这一目标的例子。是否有一些 ARM GCC 汇编关键字,我需要设置自己的 GOT table 还是有什么巧妙的技巧?
我正在尝试使用 PIC 从我的代码中访问一个变量:
.section .data @HWA_SWI_HND_DATA, "w"
hwa_ext_reset_hnd:
.word 0x00000000
.section .text @HWA_SWI_HND_CODE, "x"
.code 32
.list
.global hwa_reset_cb_attach
hwa_reset_cb_attach:
ldr r1, =hwa_ext_reset_hnd
str r0, [r1]
bx lr
如上文 ldr r1, =hwa_ext_reset_hnd
调用所示,我希望此地址提取为 PIC。
Elf 数据跟在文本之后,数据的偏移量可以在 link 时获知。您需要将 PC 添加到已知位置和数据之间的偏移量才能访问数据。参见 ARM ELF and Linkers and loader chp8 by John Levine。
显然,如果这是由 OS 和加载程序托管的,您将需要使用平台的约定。以下是针对裸机系统或您可以选择的地方编写的。
例如,
.global hwa_reset_cb_attach
hwa_reset_cb_attach:
adr r2, 1f ; pc relative value of label '1'
ldr r1, [r2] ; offset between label and data to r1
add r1, r1, r2 ; pc relative '1' label + offset there
str r0, [r1] ; store to corrected address.
bx lr
1: .word hwa_ext_reset_hnd-. ; offset from here to data fixed at link.
这适用于紧随其后的数据的 PIC 代码。如果多次出现,您可以创建一个宏来访问数据。如果有很多引用,将寄存器加载到 .data 部分的开头可能会更容易。具有编译器选项 -msingle-pic-base
和 -mpic-register=
reg 的 static base; 静态基础 通常是 r9
。所以数据的加载时间开始放在r9
一次并且只使用str rx,[r9, #hwa_ext_reset-start_of_data]
。这是 u-boot 使用的策略,您甚至可以 重新定位 数据部分(从 iram 移动到 SDRAM 等)。但是,它会占用一个额外的寄存器。
如果裸机系统上的 .text
部分是可写的,最简单的方法是将变量移动到 .text
部分。然后,您可以使用 LDR/STR/ADR 使用 PC 相对寻址直接访问数据:
.section .text @HWA_SWI_HND_CODE, "xw"
.code 32
hwa_ext_reset_hnd:
.word 0x00000000
.global hwa_reset_cb_attach
hwa_reset_cb_attach:
str r0, hwa_ext_reset_hnd
bx lr
注意 hwa_ext_reset_hnd
不仅要在同一个段中定义,还需要在同一个汇编文件中定义,这样汇编程序才能计算出 PC 相对偏移量。
如果您的文本部分不可写,那么您仍然可以使用 PC 相对寻址来处理简单的事情:
hwa_reset_cb_attach:
ldr r1, _offset_hwa_ext_reset_hnd
_base_hwa_ext_reset_hnd:
str r0, [pc, r1]
bx lr
_offset_hwa_ext_reset_hnd:
.word hwa_ext_reset_hnd - (_base_hwa_ext_reset_hnd + 8)
我正在使用 GCC 选项 -mpic-data-is-text-relative
和 -fpic
生成与位置无关的代码。这适用于我的 C 代码。
但是我也有需要使用PIC的汇编代码。问题是我找不到关于如何实现这一目标的例子。是否有一些 ARM GCC 汇编关键字,我需要设置自己的 GOT table 还是有什么巧妙的技巧?
我正在尝试使用 PIC 从我的代码中访问一个变量:
.section .data @HWA_SWI_HND_DATA, "w"
hwa_ext_reset_hnd:
.word 0x00000000
.section .text @HWA_SWI_HND_CODE, "x"
.code 32
.list
.global hwa_reset_cb_attach
hwa_reset_cb_attach:
ldr r1, =hwa_ext_reset_hnd
str r0, [r1]
bx lr
如上文 ldr r1, =hwa_ext_reset_hnd
调用所示,我希望此地址提取为 PIC。
Elf 数据跟在文本之后,数据的偏移量可以在 link 时获知。您需要将 PC 添加到已知位置和数据之间的偏移量才能访问数据。参见 ARM ELF and Linkers and loader chp8 by John Levine。
显然,如果这是由 OS 和加载程序托管的,您将需要使用平台的约定。以下是针对裸机系统或您可以选择的地方编写的。
例如,
.global hwa_reset_cb_attach
hwa_reset_cb_attach:
adr r2, 1f ; pc relative value of label '1'
ldr r1, [r2] ; offset between label and data to r1
add r1, r1, r2 ; pc relative '1' label + offset there
str r0, [r1] ; store to corrected address.
bx lr
1: .word hwa_ext_reset_hnd-. ; offset from here to data fixed at link.
这适用于紧随其后的数据的 PIC 代码。如果多次出现,您可以创建一个宏来访问数据。如果有很多引用,将寄存器加载到 .data 部分的开头可能会更容易。具有编译器选项 -msingle-pic-base
和 -mpic-register=
reg 的 static base; 静态基础 通常是 r9
。所以数据的加载时间开始放在r9
一次并且只使用str rx,[r9, #hwa_ext_reset-start_of_data]
。这是 u-boot 使用的策略,您甚至可以 重新定位 数据部分(从 iram 移动到 SDRAM 等)。但是,它会占用一个额外的寄存器。
如果裸机系统上的 .text
部分是可写的,最简单的方法是将变量移动到 .text
部分。然后,您可以使用 LDR/STR/ADR 使用 PC 相对寻址直接访问数据:
.section .text @HWA_SWI_HND_CODE, "xw"
.code 32
hwa_ext_reset_hnd:
.word 0x00000000
.global hwa_reset_cb_attach
hwa_reset_cb_attach:
str r0, hwa_ext_reset_hnd
bx lr
注意 hwa_ext_reset_hnd
不仅要在同一个段中定义,还需要在同一个汇编文件中定义,这样汇编程序才能计算出 PC 相对偏移量。
如果您的文本部分不可写,那么您仍然可以使用 PC 相对寻址来处理简单的事情:
hwa_reset_cb_attach:
ldr r1, _offset_hwa_ext_reset_hnd
_base_hwa_ext_reset_hnd:
str r0, [pc, r1]
bx lr
_offset_hwa_ext_reset_hnd:
.word hwa_ext_reset_hnd - (_base_hwa_ext_reset_hnd + 8)