How to access data from Position Independent Code (PIC) in ARM Assembly?

2

I am using the GCC options -mpic-data-is-text-relative and -fpic to generate position independent code. This works fine for my C code.

But I also have assembly code that needs to use PIC. The problem is I cannot find an example on how to achieve this. Are there some ARM GCC assembly keywords, do I need to set up my own GOT table or are there any neat tricks?

I'm trying to reach a variable from my code using 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

As seen above in the ldr r1, =hwa_ext_reset_hnd call I want this address fetch to be PIC.

assembly
arm
asked on Stack Overflow Oct 26, 2015 by Henrik • edited Oct 28, 2015 by artless noise

2 Answers

3

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.

answered on Stack Overflow Oct 28, 2015 by artless noise • edited Feb 26, 2020 by artless noise
2

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)
answered on Stack Overflow Oct 28, 2015 by Ross Ridge

User contributions licensed under CC BY-SA 3.0