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

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地址错误。

解决方法

  1. 使用gcc代替ld链接:gcc会自动处理gp的初始化逻辑,修改Makefile中的链接规则:

    chapter5_ToUppercase: $(OBJS)
            gcc -nostdlib -o chapter5_ToUppercase $(OBJS)
    

    (-nostdlib参数避免链接标准库,符合裸程序的需求)

  2. 手动初始化gp(进阶):若坚持使用ld,需要在_start开头添加gp初始化代码,通过auipc和addi指令将gp设置到正确的位置,或链接时通过-Ttext、-Tdata参数固定代码段和数据段的地址,确保gp相对寻址的偏移正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 09:50:01