如何从 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=regstatic 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)