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

在MIPS平台用GCC编译汇编函数时,如何避免“CALL16 reloc not against global symbol”错误

MIPS交叉编译中CALL16重定位错误的原因与解决方案

首先来看你提供的原始代码:

__asm__ ( "f_asm:\n" "jr $ra\n" "nop\n" );
void f(void) __asm__("f_asm");
int main(void) { f(); return 0; }

编译时遇到的错误:

/usr/lib/gcc-cross/mips-linux-gnu/6/../../../../mips-linux-gnu/bin/ld: /tmp/ccjejLxv.o: CALL16 reloc at 0x2c not against global symbol
/tmp/ccjejLxv.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status

为什么必须添加.globl f_asm?

这个错误的核心原因和MIPS架构的重定位规则直接相关:

  • 当你在C代码中声明void f(void) __asm__("f_asm");时,编译器会把对f()的调用翻译为MIPS的jal f_asm指令,这条指令依赖的是CALL16重定位(R_MIPS_CALL16)。
  • MIPS的CALL16重定位是专门为全局符号设计的——这类符号可以跨目标文件访问,甚至能通过PLT(过程链接表)调用动态库中的符号。
  • 但你在__asm__块里定义的f_asm标签默认是局部符号(仅在当前目标文件内可见,未对外暴露),链接器发现CALL16重定位指向了非全局符号,就会抛出错误,因为它无法为局部符号处理这种跨模块风格的重定位。

添加.globl f_asm后,你把f_asm标记为全局符号,完全符合CALL16重定位的要求,链接器就能正常处理这个跳转了。

能不能用非全局符号实现?

当然可以!只要避免使用CALL16重定位,改用局部符号支持的PC相对重定位即可,最简洁的方案是:

将函数声明为static

把C函数声明为static,这样f_asm会被编译器标记为局部符号,此时调用f()时会生成使用PC相对重定位(R_MIPS_PC16)的跳转指令,不需要依赖全局符号:

static void f(void) __asm__("f_asm");
__asm__ (
    "f_asm:\n"
    "jr $ra\n"
    "nop\n"
);
int main(void) { f(); return 0; }

这种方式下,f_asm是局部符号,跳转仅依赖当前目标文件内的相对地址计算,链接器不会再要求它必须是全局的。

总结一下:CALL16重定位强制要求目标是全局符号,而局部符号需要用PC相对重定位来处理,通过static声明就能让编译器自动切换重定位类型,完美规避这个错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:13:48