我正在努力学习ARM64。我在苹果M1上组装。
我正在尝试分配我可以写入的内存。我一直收到以下错误:
ld: Absolute addressing not allowed in arm64 code but used in '_main' referencing 'foo'
程序很简单:
// foo.s
.global _main
.align 2
_main:
ldr x0, =foo
.data
foo: .zero 8
我用这个脚本来编译它:
#!/bin/bash
as foo.s -o foo.o &&
ld foo.o -o foo
-arch arm64
-syslibroot `xcrun -sdk macosx --show-sdk-path`
-lSystem
经过一些谷歌搜索,我尝试设置-no_pie
为ld,但结果是:
ld: warning: -no_pie ignored for arm64
我不太清楚这是怎么回事。
感谢更新:这里有一个SO问题可以解释这个问题。
我应用了这个修复并编写了这个快速程序来测试它是否有效:
.global _main
.align 2
_main:
// Set x0 to the memory address of foo.
adrp x0, foo@PAGE
add x0, x0, foo@PAGEOFF
// Store 123 in foo.
mov x1, 123
str x1, [x0]
// Load the contents of foo into x2.
ldr x2, [x0]
// Exit with a status code set to foo.
mov x0, x2
mov x16, 1
svc 0
.data
foo: .zero 8
它返回退出状态123,正如我所期望的。
您在.data
部分中使用.zero
分配了内存。现在你只需要加载它的地址就可以访问它了。
最好编写与位置无关的代码,而不是试图禁用它。因此,与其尝试加载绝对地址,不如相对于程序计数器访问它们。
在中等大小的程序中(小于1兆字节的代码加上静态数据),可以使用
将foo
的地址加载到x0
中。adr x0, foo
adr
指令在程序计数器pc
的值上增加一个直接常数,并将结果留在目标寄存器中。汇编器和链接器可以确定adr
指令的地址和foo
的地址之间的差异,并将该差异编码为adr
指令的直接地址。
对于更大的程序,其中地址的差异可能高达4gb左右,您使用adrp
的组合来获得高位,add
或带有偏移量的加载/存储。参见ARM汇编中ADRP和ADRL指令的语义是什么?