arm64 macho 将标签存储在部分外部的寄存器中
arm64 macho store label in register from outside of section
我有为 Mac m1 (arm64 macho) 编译的汇编代码:
.text
.globl main
.p2align 2
main:
stp x29, x30, [sp, -16]!
add x29, sp, 0 mov x2, #6
adrp x1, _fmt@PAGE
add x1, x1, _fmt@PAGEOFF
mov x0, #1
adrp x3, _write@PAGE
add x3, x3, _write@PAGEOFF
blr x3
mov w0, #0
ldp x29, x30, [sp], #16
ret
/* end function main */
.balign 8
_fmt:
.ascii "Hello\n"
失败:
final section layout:
__TEXT/__text addr=0x100003F88, size=0x00000030, fileOffset=0x00003F88, type=1
__TEXT/__unwind_info addr=0x100003FB8, size=0x00000048, fileOffset=0x00003FB8, type=22
__DATA/__data addr=0x100004000, size=0x00000006, fileOffset=0x00004000, type=0
ld: ARM64 ADRP out of range (-4294979584 max is +/-4GB): from main (0x100003F88) to _write@0x00000000 (0x00000000) in 'main' from test.o for architecture arm64
我相信发生这种情况是因为 _write
指令引用了写系统调用,该系统调用直到 link 时间才可用,这意味着汇编程序不知道要放入什么_write
的地址,它被写为 0x00000000
。 (有错请指正)
我错了。 (感谢@user3124812)
烦人的是,如果我调用 bl _write
而没有先将其放入寄存器,则不会发生这种情况。
例如:
.text
.globl main
.p2align 2
main:
stp x29, x30, [sp, -16]!
add x29, sp, 0 mov x2, #6
adrp x1, _fmt@PAGE
add x1, x1, _fmt@PAGEOFF
mov x0, #1
bl _write
mov w0, #0
ldp x29, x30, [sp], #16
ret
/* end function main */
.data
.balign 8
_fmt:
.ascii "Hello\n"
这有效并打印 Hello
后跟一个换行符。
为什么我不能在打印前将标签位置存储在寄存器中?它似乎适用于我的部分中的标签
未在与引用它们的代码相同的共享对象中定义的符号的值未知。因此,您必须像这样从全局偏移量 table (GOT) 加载此类地址:
adrp x0, _write@GOTPAGE
ldr x0, [x0, _write@GOTPAGEOFF]
这会将 _write
的地址加载到 x0
中。此类代码也可用于在与引用相同的共享对象中定义的符号,但在这种情况下,直接访问它们可能更容易。
当您直接使用 bl
调用一个函数时,链接器使调用转到过程链接 table (PLT),它持有一个跳转到实际函数的跳线。因此,直接调用有效。
我有为 Mac m1 (arm64 macho) 编译的汇编代码:
.text
.globl main
.p2align 2
main:
stp x29, x30, [sp, -16]!
add x29, sp, 0 mov x2, #6
adrp x1, _fmt@PAGE
add x1, x1, _fmt@PAGEOFF
mov x0, #1
adrp x3, _write@PAGE
add x3, x3, _write@PAGEOFF
blr x3
mov w0, #0
ldp x29, x30, [sp], #16
ret
/* end function main */
.balign 8
_fmt:
.ascii "Hello\n"
失败:
final section layout:
__TEXT/__text addr=0x100003F88, size=0x00000030, fileOffset=0x00003F88, type=1
__TEXT/__unwind_info addr=0x100003FB8, size=0x00000048, fileOffset=0x00003FB8, type=22
__DATA/__data addr=0x100004000, size=0x00000006, fileOffset=0x00004000, type=0
ld: ARM64 ADRP out of range (-4294979584 max is +/-4GB): from main (0x100003F88) to _write@0x00000000 (0x00000000) in 'main' from test.o for architecture arm64
我相信发生这种情况是因为 _write
指令引用了写系统调用,该系统调用直到 link 时间才可用,这意味着汇编程序不知道要放入什么_write
的地址,它被写为 0x00000000
。 (有错请指正)
我错了。 (感谢@user3124812)
烦人的是,如果我调用 bl _write
而没有先将其放入寄存器,则不会发生这种情况。
例如:
.text
.globl main
.p2align 2
main:
stp x29, x30, [sp, -16]!
add x29, sp, 0 mov x2, #6
adrp x1, _fmt@PAGE
add x1, x1, _fmt@PAGEOFF
mov x0, #1
bl _write
mov w0, #0
ldp x29, x30, [sp], #16
ret
/* end function main */
.data
.balign 8
_fmt:
.ascii "Hello\n"
这有效并打印 Hello
后跟一个换行符。
为什么我不能在打印前将标签位置存储在寄存器中?它似乎适用于我的部分中的标签
未在与引用它们的代码相同的共享对象中定义的符号的值未知。因此,您必须像这样从全局偏移量 table (GOT) 加载此类地址:
adrp x0, _write@GOTPAGE
ldr x0, [x0, _write@GOTPAGEOFF]
这会将 _write
的地址加载到 x0
中。此类代码也可用于在与引用相同的共享对象中定义的符号,但在这种情况下,直接访问它们可能更容易。
当您直接使用 bl
调用一个函数时,链接器使调用转到过程链接 table (PLT),它持有一个跳转到实际函数的跳线。因此,直接调用有效。