ARM64位置无关汇编全局变量访问问题:函数迁移后失效如何解决?
macOS ARM64汇编迁移内存后正确访问全局变量的方案
问题根源
你遇到的问题本质是PC相对寻址的局限性:adrp/ldr(或汇编优化后的adrp/add)是基于当前指令的PC值计算全局变量地址的。当你把函数用memcpy复制到其他内存位置后,PC的基准位置完全改变,原来预计算的相对偏移自然失效,导致全局变量地址加载错误。
正确解决方法
1. 通过全局偏移表(GOT)间接访问
GOT是进程启动时被系统填充的地址表,其中存储着全局变量的绝对地址,与函数的运行位置无关。使用GOT访问的汇编代码示例:
; 获取全局变量在GOT中的条目地址 adrp x0, _global_var@GOTPAGE ldr x0, [x0, _global_var@GOTPAGEOFF] ; 从GOT条目中读取全局变量的绝对地址 ldr x0, [x0] ; 此时x0中就是_global_var的正确地址,可直接读写
不管函数被迁移到内存的哪个位置,只要GOT的位置不变(进程生命周期内固定),就能正确拿到全局变量地址。
2. 基于静态基址(SB)寻址
对于小数据全局变量(通常是数据段中的小变量),可以使用静态基址寻址,它依赖的是程序静态段的基址而非当前函数的PC:
adrp x0, _global_var@SB add x0, x0, _global_var@SBOFF ; x0即为_global_var的地址
这种方式同样不受函数迁移的影响,因为静态段基址在进程启动后固定(即使开启ASLR,也是整个静态段偏移,相对关系不变)。
3. 编译时生成位置无关代码
如果你用Clang编译汇编代码,务必添加-fpic或-fPIC选项,强制编译器生成位置无关的代码逻辑,自动处理全局变量的寻址问题,避免手动编写PC相对的寻址指令。
补充说明
你看到ldr被汇编成add是汇编器的正常优化:当全局变量的页内偏移为0时,ldr [x0, #0]等价于直接把x0的值作为地址,汇编器会优化为add x0, x0, #0(或直接保留x0),但这不会改变PC相对寻址的本质,所以迁移后依然出错。
内容的提问来源于stack exchange,提问作者swineone
相关产品推荐
相关产品推荐

