The support in GAS for the ARM literal-loading syntax is entirely
hopeless.
* It unnecessarily refuses to allow expressions involving external
symbols as literal values (e.g., `ldr r0, =_GLOBAL_OFFSET_TABLE_ -
. - 12'). I've checked: if you modify GAS to remove the pointless
check, then it produces the right result.
* It doesn't use the enhanced expression evaluator which understands
relocation annotations (so you can't say `ldr r0, =foo(GOT)').
Indeed, this evaluator is internal to the handler for `.word' and
friends. Fixing this would be rather hard work, and involve
uprating the literal-pool machinery quite a bit.
Instead, use the new subsection-based fake literal pool handling
machinery `_LIT' and `_ENDLIT' and some per-macro symbols with awful
names.
This also removes the magic knowledge which the previous version of the
`ldgot' had about the right PC offset, which would have been wrong for
Thumb code.
// Maybe load GOT address into GOT.
.macro ldgot cond=, got=GOTREG
#if WANT_PIC
- ldr\cond \got, =_GLOBAL_OFFSET_TABLE_ - . - 12
+ ldr\cond \got, .L$_ldgot$\@
+.L$_ldgot_pc$\@:
add\cond \got, pc, \got
+ _LIT
+ .balign 4
+.L$_ldgot$\@:
+ .word _GLOBAL_OFFSET_TABLE_ - .L$_ldgot_pc$\@ - 8
+ _ENDLIT
#endif
.endm
// Load address of external symbol ADDR into REG, maybe using GOT.
.macro leaext reg, addr, cond=, got=GOTREG
#if WANT_PIC
- ldr\cond \reg, =\addr(GOT)
+ ldr\cond \reg, .L$_leaext$\@
ldr\cond \reg, [\got, \reg]
+ _LIT
+ .balign 4
+.L$_leaext$\@:
+ .word \addr(GOT)
+ _ENDLIT
#else
ldr\cond \reg, =\addr
#endif