2. 链接脚本定制内存布局
任务说明
为 RISC-V 裸机程序编写自定义链接脚本,把 .text、.data、.bss 分别放到三个互不重叠的固定地址,再用 objdump 反汇编确认各段起始地址与脚本一致。
本案例用最小可复现的裸机程序验证链接脚本,不依赖前序章节代码。目标内存布局:
.text起始0x80000000(代码段).data起始0x80010000(已初始化数据).bss起始0x80020000(未初始化数据)
环境与依赖
- RISC-V 工具链:
riscv64-unknown-elf-gcc、riscv64-unknown-elf-objdump(或riscv32-*,本案例用 64 位)。 - 无需真实硬件,验证只依赖反汇编输出。
关键文件
link.ld 定义内存布局,start.S 提供入口并引用各段符号,main.c 提供 .data 与 .bss 变量。
/* link.ld */
ENTRY(_start)
MEMORY
{
TEXT (rx) : ORIGIN = 0x80000000, LENGTH = 64K
DATA (rw) : ORIGIN = 0x80010000, LENGTH = 64K
BSS (rw) : ORIGIN = 0x80020000, LENGTH = 64K
}
SECTIONS
{
.text : {
*(.text._start)
*(.text*)
} > TEXT
.data : {
*(.data*)
} > DATA
.bss : {
*(.bss*)
*(COMMON)
} > BSS
}
/* start.S */
.section .text._start
.globl _start
_start:
la t0, _data_start
la t1, _bss_start
la t2, _bss_end
1: bgeu t1, t2, 2f
sd zero, 0(t1)
addi t1, t1, 8
j 1b
2: j 2b
/* main.c */
int g_init = 0x1234; /* 放入 .data */
int g_zero; /* 放入 .bss */
const int g_const = 7; /* 放入 .text(只读) */
void _start(void);
构建与验证
riscv64-unknown-elf-gcc -nostdlib -T link.ld \
-o demo.elf start.S main.c
riscv64-unknown-elf-objdump -h demo.elf
在 objdump -h 输出中检查各段 VMA:.text 应为 0x80000000,.data 应为 0x80010000,.bss 应为 0x80020000。若三者地址与脚本一致且互不重叠,即判定通过。
段布局示意
常见问题
- 若
.data未出现在预期地址,检查是否被*(.data*)之外的规则抢先匹配。 - 若
.bss为空,确认g_zero未被优化掉(本案例未开优化,默认保留)。 - 链接报
region overflow时,说明段大小超过LENGTH,按需调大。