LDR doesn't work correctly due Apple's thoughts about security, but how I can load, for example this:
.data
.align 4
.mynumber: .quad 0x123456789ABCDEF0
I know about ADRP, but I'm not sure that I understand how it works.
I have already done this(ADRP, @PAGE, @PAGEOFF was taken from other sources):
.global _start
.text
_start:
ADRP X2, arr1@PAGE
ADD X2, X2, arr1@PAGEOFF
mov X0, #0 // Use 0 return code
mov X16, #1 // System call number 1 terminates this program
svc #0x80 // Call kernel to terminate the program
.data
.align 4
arr1: .FILL 10, 4, 0
mynumber: .quad 0x123456789ABCDEF0
myoctaword: .octa 0x12345678876543211234567887654321
Loading "data by label" works perfectly fine:
ldr x0, label
label:
.8byte 0x0123456789abcdef
What doesn't work on Darwin is ldr x0, =...
, because that's syntactic sugar for this:
ldr x0, addrof_label
label:
.8byte 0x0123456789abcdef
addrof_label:
.8byte label
And since label
is a statically encoded address, it would need to be rebased by the dynamic linker, which crashes the process when attempted, since the __TEXT
segment is both mapped as r-x
and codesigned.
(Update: since Xcode 15.0, Apple is using a new linker whose behaviour is different, but still wrong. See this answer for more details. The solution below still applies.)
For getting the address of some labels, you can use adr
:
adr x0, label
label:
.8byte 0x0123456789abcdef
But this will only work in a ±1MiB range, and additionally the toolchain will only let you do this within the same segment, i.e. __TEXT
. For the general case, adrp+add
is the way to go:
adrp x0, label@PAGE
add x0, x0, label@PAGEOFF
.data
label:
.8byte 0x0123456789abcdef
But you can use .loh AdrpAdd ...
directives to have the linker fix this back up into adr+nop
if the resulting offset is in range:
L1:
adrp x0, label@PAGE
L2:
add x0, x0, label@PAGEOFF
.loh AdrpAdd L1, L2
.data
label:
.8byte 0x0123456789abcdef
The same can be done with adrp+ldr
if necessary, and likewise .loh AdrpLdr ...
can turn that into just a PC-relative ldr
if in range.