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

ARM平台链接器无法正确解析外部指针json_start问题求助

问题:ARM musl-gcc编译时json_start符号解析为偏移量而非PC相对地址

我使用arm-linux-musleabi-gcc (GCC) 9.4.0编译代码时,遇到json_start引用解析错误的问题——它被处理成了纯偏移量(比如0x4762),而非预期的PC相对访问地址(比如0x5114762)。

我的需求是将JSON内容嵌入二进制文件中。理想情况下会用#embed指令,但当前musl版本不支持;也考虑过.incbin,但不想为这一功能单独添加汇编文件,同时希望搞清楚问题的根源。

相关文件

file.h

#ifndef __FILE_H__
#define __FILE_H__
#include <stddef.h>

typedef size_t (*strlen_fn)(const char *s);
#define strlen ((strlen_fn)Strlen)

extern const unsigned char * json_start;
#endif

file.c

#include <file.h>

void *entry(void) __attribute__((section("\".entry\"")));
void do_stuff(unsigned char *, void *);

void *entry(void) {
    do_stuff((unsigned char *)json_start, entry);
}

void do_stuff(unsigned char *json_start, void *entry) {
    json_start[0] = 0;
    return;
}

file.json

{}

linker.ld

SECTIONS
{
    .text : 
    {
        *(.entry)
        *(.core)
        *(.text*)
        *(.rodata*)
        *(.data*)
        *(.bss*)
        *(.got*)
        *(COMMON)
    }
    /DISCARD/ : 
    {
        *(*)
    }
}

当前编译命令

rm -r build
mkdir -p ./build
arm-linux-musleabi-objcopy -I binary -B arm -O elf32-littlearm ./file.json ./build/json.o
arm-linux-musleabi-objcopy --redefine-sym _binary___file_json_start=json_start ./build/json.o
arm-linux-musleabi-gcc -o ./build/file.o -c -fPIE -fno-builtin -ffreestanding -march=armv5t -Os -I . file.c
arm-linux-musleabi-gcc -o ./build/file -nostdlib -pie -T linker.ld ./build/file.o ./build/json.o -lgcc

尝试过的其他方法

arm-linux-musleabi-gcc -r -o ./build/json.o -Wl,-b,binary file.json
arm-linux-musleabi-objcopy --redefine-sym _binary_file_json_start=json_start ./build/json.o

但效果不佳。

汇编代码对比

实际生成的汇编:

ldr r3,[r3,r2]
ldr r0,[r3,#0x0]
bl do_stuff

预期的汇编:

ldr r3,[r3,r2]
ldr r0,[r3,#0x0]
add r0, pc, r0
bl do_stuff

其中r0对应json_start。

更新发现

问题出在json_start被放入了GOT段,而我的链接脚本只是将GOT段打包进二进制,未对符号做地址修正。


解决方法

1. 调整链接脚本,单独处理二进制嵌入段

修改linker.ld,将二进制嵌入的JSON内容明确放到.rodata段,避免GOT介入:

SECTIONS
{
    .text : 
    {
        *(.entry)
        *(.core)
        *(.text*)
    }
    .rodata : {
        *(.rodata*)
        json_start = .;
        *(.data.bin)  /* 对应objcopy生成的二进制内容段 */
        json_end = .;
    }
    .data : {
        *(.data*)
    }
    .bss : {
        *(.bss*)
        *(COMMON)
    }
    /DISCARD/ : 
    {
        *(.got*)
        *(*)
    }
}

同时修改objcopy命令,指定段名:

arm-linux-musleabi-objcopy -I binary -B arm -O elf32-littlearm --rename-section .data=.rodata.bin,alloc,load,readonly,data,contents ./file.json ./build/json.o

这样JSON内容会直接被分配到只读数据段,json_start即为该段起始地址,无需通过GOT访问。

2. 关闭PIE模式,使用绝对/PC相对地址访问

如果不需要位置无关可执行文件,将编译和链接的PIE相关选项替换为非PIE:

arm-linux-musleabi-gcc -o ./build/file.o -c -fno-pie -fno-builtin -ffreestanding -march=armv5t -Os -I . file.c
arm-linux-musleabi-gcc -o ./build/file -nostdlib -no-pie -T linker.ld ./build/file.o ./build/json.o -lgcc

编译器会直接生成PC相对的符号访问指令,而非通过GOT跳转。

3. 强制json_start为绝对符号

在链接脚本的.text段内添加绝对符号声明,避免GOT重定位:

.text : 
{
    *(.entry)
    *(.core)
    *(.text*)
    *(.rodata*)
    *(.data*)
    json_start = ABSOLUTE(json_start);
    *(.bss*)
    *(COMMON)
}

链接器会将json_start解析为绝对地址,生成符合预期的PC相对访问指令。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:53:10