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

如何让ARM64平台GCC不为其他目标文件符号生成GOT条目

解决ARM64平台GCC生成冗余GOT条目的问题

问题根源

ARM64架构的BL分支指令仅支持±128MB的PC相对寻址范围,远小于x86_64的±2GB。GCC默认会假设跨目标文件的函数可能超出这个范围,因此自动生成通过GOT(全局偏移表)的间接调用;而同一文件内的函数地址可确定,就直接使用PC相对寻址。

解决办法

针对你的环境(Apple M1上的Ubuntu 20.04.5 LTS,GCC 9.4.0),可以用以下几个编译/链接选项消除这类冗余GOT条目:

1. 添加-mno-long-calls编译选项

这个选项会强制GCC为所有函数调用生成PC相对的BL指令,跳过GOT的间接调用。链接时如果函数真的超出128MB范围会报错,但绝大多数程序都不会碰到这个限制。

编译命令示例:

gcc -mno-long-calls 1.c 2.c -o output

2. 使用-fno-plt编译选项

禁用PLT(过程链接表)后,GCC会直接从GOT加载函数地址调用,而链接器处理同一可执行文件内的函数时,会自动优化掉GOT条目,替换为直接的PC相对调用。同时这个选项还能提升程序启动速度,避免PLT的延迟绑定开销。

编译命令示例:

gcc -fno-plt 1.c 2.c -o output

3. 优化符号可见性

如果你的函数仅在当前可执行文件内部使用,可以添加-fvisibility=hidden将所有符号默认设为隐藏,仅给需要对外暴露的函数加上__attribute__((visibility("default")))标记。编译器知道这些隐藏符号不会被外部模块引用,就会直接生成PC相对调用,完全不需要GOT代理。

示例代码(2.c中定义target):

__attribute__((visibility("default")))
void target() {
    // 函数实现
}

编译命令:

gcc -fvisibility=hidden 1.c 2.c -o output

验证生效方法

用objdump反编译可执行文件,检查调用target的指令是否为直接的bl target,而非通过GOT加载地址的指令:

objdump -d output | grep -A5 -B5 target

如果输出中出现bl target,说明冗余GOT条目已经被成功消除。

内容的提问来源于stack exchange,提问作者user2828102

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:30:41