assembly 为什么我不能在ARM64 MacOS上的.text部分组装绝对地址?

blmhpbnm  于 2022-11-13  发布在  Mac
关注(0)|答案(1)|浏览(216)

我在汇编中使用clang 13.1.6和MacOS Monterey 12.5在ARM 64 M1 Pro笔记本电脑上编写。
如果我试图在.text节中使用.dword/.xword,并将标签的地址作为其值,我的程序在启动时崩溃,并出现bus error
最小可重现示例:

.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进行汇编和链接,没有错误或警告,但是在运行时立即出现总线错误,显然在到达我的实际代码之前。

* 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中。这也是总线错误。
等效代码在ARM 64 Linux上运行良好。
为什么会这样?我该如何解决它?

1aaf6o9v

1aaf6o9v1#

ARM 64 MacOS似乎不支持文本部分中的绝对地址。据我所知,动态链接器试图应用重定位/修复来将dest的实际运行时地址存储到vector中,但由于.text已经被Map为只读而崩溃。
因此,如果你有一个对象需要用标签或其他对象的地址初始化,那么你需要把它放在一个数据节中,即使它是只读的。这就是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 __DATA,__const之后。后一部分在运行时也是只读的,但显然在重定位完成时被Map为读写。
而且根本不能使用ldr x1, =label,如果label在文本部分,则使用adradrp / add来生成x1中的地址,否则根据需要从全局偏移表中加载它。
如果链接器能够检测到这一点并向您发出警告,而不是继续构建一个神秘崩溃的可执行文件,那就太好了。

相关问题