我在 ARM64 M1 Pro 笔记本电脑上使用 clang 13.1.6 和 MacOS Monterey 12.5 编写汇编代码。
如果我尝试在 .text
部分使用 .dword
/.xword
并将标签的地址作为其值,我的程序在启动时崩溃并出现总线错误
。
最小可重现示例:
.text
.balign 4
.global _main
_main:
// accepted method to load from static address
adrp x1, vector@GOTPAGE
ldr x1, [x1, #vector@GOTPAGEOFF]
// now x1 contains the address of vector
ldr x2, [x1]
// now x2 should contain the address of dest
br x2
dest:
mov x0, #0
ret
vector:
.xword dest
这使用 cc reloc.s -o reloc
进行组装和链接,没有错误或警告,但在运行时立即出现总线错误,显然在到达我的实际代码之前。 lldb
的回溯如下:
* thread #1, stop reason = EXC_BAD_ACCESS (code=2, address=0x100003fb0)
frame #0: 0x000000010001da54 dyld`invocation function for block in dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const + 60
dyld`invocation function for block in dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const:
-> 0x10001da54 <+60>: str x19, [x20]
0x10001da58 <+64>: ldp x29, x30, [sp, #0x20]
0x10001da5c <+68>: ldp x20, x19, [sp, #0x10]
0x10001da60 <+72>: add sp, sp, #0x30
Target 0: (a.out) stopped.
(lldb) bt
* thread #1, stop reason = EXC_BAD_ACCESS (code=2, address=0x100003fb0)
* frame #0: 0x000000010001da54 dyld`invocation function for block in dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const + 60
frame #1: 0x0000000100040fd4 dyld`invocation function for block in dyld3::MachOLoaded::fixupAllChainedFixups(Diagnostics&, dyld_chained_starts_in_image const*, unsigned long, dyld3::Array<void const*>, void (void*, void*) block_pointer) const + 424
frame #2: 0x0000000100041080 dyld`dyld3::MachOLoaded::walkChain(Diagnostics&, dyld3::MachOLoaded::ChainedFixupPointerOnDisk*, unsigned short, bool, unsigned int, void (dyld3::MachOLoaded::ChainedFixupPointerOnDisk*, bool&) block_pointer) const + 104
frame #3: 0x00000001000412b0 dyld`dyld3::MachOLoaded::forEachFixupInSegmentChains(Diagnostics&, dyld_chained_starts_in_segment const*, bool, void (dyld3::MachOLoaded::ChainedFixupPointerOnDisk*, dyld_chained_starts_in_segment const*, bool&) block_pointer) const + 208
frame #4: 0x0000000100040e04 dyld`dyld3::MachOLoaded::forEachFixupInAllChains(Diagnostics&, dyld_chained_starts_in_image const*, bool, void (dyld3::MachOLoaded::ChainedFixupPointerOnDisk*, dyld_chained_starts_in_segment const*, bool&) block_pointer) const + 96
frame #5: 0x0000000100040d98 dyld`dyld3::MachOLoaded::fixupAllChainedFixups(Diagnostics&, dyld_chained_starts_in_image const*, unsigned long, dyld3::Array<void const*>, void (void*, void*) block_pointer) const + 120
frame #6: 0x000000010001da0c dyld`invocation function for block in dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const + 136
frame #7: 0x000000010001d788 dyld`dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const + 204
frame #8: 0x0000000100021574 dyld`dyld4::JustInTimeLoader::applyFixups(Diagnostics&, dyld4::RuntimeState&, dyld4::DyldCacheDataConstLazyScopedWriter&, bool) const + 604
frame #9: 0x000000010000d904 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 1928
frame #10: 0x000000010000d06c dyld`start + 488
崩溃似乎发生在动态链接器内部,根本不在我的代码中。
具有相同行为的更简单示例是:
.text
.balign 4
.global _main
_main:
ldr x1, =dest
br x1
dest:
mov x0, #0
ret
这里 ldr x1, =dest
应该类似地将 dest
的地址组装到文字池中(.text
中的附近位置) > 部分)并从那里加载到 x1
。这也是总线错误。
等效代码在 ARM64 Linux 上运行良好。
这是为什么,我该如何解决?
最佳答案
ARM64 MacOS 似乎不支持文本部分中的绝对地址。据我所知,动态链接器尝试应用重定位/修复将 dest
的实际运行时地址存储到 vector
中,但由于 .text< 而崩溃
已映射为只读。
所以如果你有一个对象需要用标签或其他对象的地址初始化,那么你需要把它放在一个数据段中,即使它是只读的。这就是 clang 在编译 C/C++ 代码时所做的事情。例如,如果你用 C 编写
const int i = 42;
const int * const ptr1 = &i;
const int * const ptr2 = NULL;
const int * const ptr3 = (const int *)0xdeadbeefcafed00dUL;
然后 i、ptr2、ptr3
前面都有 .section __TEXT,__const
,但是 ptr1
前面有 .section __数据,__常量
。后一部分在运行时也是只读的,但显然在重定位完成时被映射为读写。
而且您根本无法使用 ldr x1, =label
。如果 label
在文本部分中,则根据需要使用 adr
或 adrp/add
在 x1
中生成地址,或以其他方式从全局偏移表中适本地加载它。
如果链接器能够检测到这一点并警告您,而不是继续构建神秘崩溃的可执行文件,那就太好了。
关于macos - 为什么我不能在 ARM64 MacOS 上的 .text 部分组装绝对地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73382860/