How to access data from Position Independent Code (PIC) in ARM Assembly?
The Elf DATA follows text and the offset to data can be known at link time. You need to add the PC to an offset between known location and data to access the data. See ARM ELF and Linkers and loader chp8 by John Levine.
Obviously, if this is hosted by an OS and loader, you will need to use the conventions of the platform. The following is written for a bare metal system or places where you have the option to choose.
For example,
.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.
This works for PIC code with data following immediately. If you have many occurrences, you can create a macro to access the data. If there are a lot of references, it maybe easier to keep a register loaded with the beginning of the .data section. The static base with the compiler options -msingle-pic-base
and -mpic-register=
reg; static base is typically r9
. So the load time start of data is put in r9
once and only use str rx,[r9, #hwa_ext_reset-start_of_data]
. This is a tactic used by u-boot and you can even relocate the data sections (moving from iram to SDRAM, etc). However, it consumes an extra register.
If the .text
section on your bare metal system is writable, the simplest thing would be to move the variable to the .text
section. You can then use LDR/STR/ADR to access the data directly using PC relative addressing:
.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
Note that the hwa_ext_reset_hnd
not only has to be defined in the same section, it need to be defined in the same assembly file so the assembler can figure out the PC relative offset.
If your text section isn't writable then you can still use PC relative addressing to simply things:
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)