RISC-V汇编中全局指针(gp)值异常致地址加载错误排查
RISC-V汇编程序段错误排查:
la指令地址加载异常 环境与问题背景
在QEMU64的RISC-V Ubuntu模拟器环境下进行RISC-V汇编实验,编写了一个将字符串instr转换为大写并存储到outstr的程序,但运行时触发段错误。通过GDB调试发现,程序开头的la x5, outstr指令未正确加载outstr的实际地址。
汇编程序代码
.global _start _start: la x5, outstr la x6, instr loop: lb x7, 0(x6) addi x6, x6, 1 li x28, 'z' bgt x7, x28, cont li x28, 'a' blt x7, x28, cont addi x7, x7, ('A'-'a') cont: sb x7, 0(x5) addi x5, x5, 1 li x28, 0 bne x7, x28, loop li a0, 1 la a1, outstr sub a2, x5, a1 li a7, 64 ecall li a0, 0 li a7, 93 ecall .data instr: .asciz "String to conVErt xYz.\n" outstr: .fill 255, 1, 0
GDB反汇编结果
0x00000000000100e8 <+0>: addi t0,gp,-2024 0x00000000000100ec <+4>: auipc t1,0x1 0x00000000000100f0 <+8>: addi t1,t1,84 # 0x11140
问题细节
la x5, outstr被汇编为addi t0,gp,-2024,按指令逻辑计算得t0 = gp - 2024,但实际outstr的地址为0x11158,计算出的t0值为0x55555567c3ac(gp值为0x55555567cb94,计算逻辑符合指令,但地址与实际数据段地址不匹配),最终导致访问错误地址触发段错误。
所用Makefile
OBJS = chapter5_ToUppercase.o DEBUGFLAGS = -g %.o : %.S as $(DEBUGFLAGS) $< -o $@ chapter5_ToUppercase: $(OBJS) ld -o chapter5_ToUppercase $(OBJS)
错误原因与解决方法
原因
问题出在链接阶段:直接使用ld裸链接时,不会自动初始化RISC-V的全局指针(gp)。RISC-V汇编器对小范围地址的符号会生成基于gp的相对寻址指令(如addi t0,gp,-2024),但gp需要被正确设置到数据段的全局偏移表(GOT)附近才能让相对寻址生效。未初始化的gp指向的位置与实际数据段地址不匹配,导致计算出的outstr地址错误。
解决方法
使用gcc代替ld链接:gcc会自动处理
gp的初始化逻辑,修改Makefile中的链接规则:chapter5_ToUppercase: $(OBJS) gcc -nostdlib -o chapter5_ToUppercase $(OBJS)(
-nostdlib参数避免链接标准库,符合裸程序的需求)手动初始化gp(进阶):若坚持使用
ld,需要在_start开头添加gp初始化代码,通过auipc和addi指令将gp设置到正确的位置,或链接时通过-Ttext、-Tdata参数固定代码段和数据段的地址,确保gp相对寻址的偏移正确。
内容的提问来源于stack exchange,提问作者user12312425
相关产品推荐
相关产品推荐

