You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android x86 GAS汇编中调用C函数如何避免文本重分配?

解决Android NDK x86汇编调用C函数的文本重分配警告问题

我之前也踩过这个坑,其实这个警告的核心原因是:直接用call foo这种方式调用动态链接的C函数时,编译器需要修改.text段里的指令来完成地址重定位,导致.text段没法被多个进程共享(每个进程加载时都要改写指令)。Android从API23开始对共享库的内存共享效率要求更严格,所以会抛出这个警告,甚至可能编译失败。

下面给你几个可行的解决方案,按推荐程度排序:

1. 使用PLT(过程链接表)调用C函数(首推)

这是动态链接场景下调用外部函数的标准做法,完全避免修改.text段。在GAS x86语法里,只需要把原来的call foo改成:

call foo@PLT

PLT会通过GOT(全局偏移表)间接跳转到C函数的实际地址,所有重定位操作都发生在GOT(属于可写的动态节),.text段全程保持只读状态,完美符合Android对共享库内存共享的要求。

NDK的GAS和链接器会自动处理PLT与GOT的生成,你不需要手动配置额外的节或参数,改完指令重新编译就能消除警告。

2. 寄存器间接调用

如果不想用PLT,也可以先把C函数的地址加载到寄存器,再通过寄存器间接调用:

# 32位x86写法
movl $foo, %eax
call *%eax

# 64位x86写法
movq $foo, %rax
call *%rax

这种方式的重定位条目只会指向GOT,不会修改.text段里的指令,同样能避免文本重分配问题。不过这种写法不如PLT简洁,而且PLT是专门为动态链接优化过的,还是更推荐第一种方案。

3. 关于“移动函数到其他节”的误区

你提到能不能把汇编函数移到其他节,其实这个思路没必要——问题根本不在汇编函数所在的.text节,而是调用C函数时的重定位方式。就算把汇编函数移到其他节,只要还是直接call foo,依然会产生文本重定位的问题。所以优先调整调用方式,而非移动节。

最后验证一下:用call foo@PLT替换原有调用后,编译时的警告应该会消失,API23及以上版本也能正常编译通过,同时共享库的.text段依然保持可共享性,不会浪费内存。

内容的提问来源于stack exchange,提问作者Van der Deken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:20:08