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

RISC-V汇编运行时地址越界错误排查与修复求助

RISC-V汇编快速排序地址越界问题修复

错误核心原因

报错显示访问地址0x00000000,说明partition函数里的数组基地址寄存器s0的值为0,根源是参数传递完全错误:从quickSort到qSort再到partition的参数都未正确传递,同时存在逻辑分支写反、partition逻辑完全偏离Java实现的问题。

原始代码

Java快速排序实现

//declare an array Y1 and its length lenY1
static int Y1[] = {13, 101, 79, 23, 154, 4, 11, 38, 88, 45, 17, 94, 62, 1};
static int lenY1 = 14;

public static void main(String[] args) { //Define main method
    quickSort(Y1, lenY1);                //Call quickSort method
    for (int i = 0; i<lenY1; i++)        //Loop for printing
        System.out.print(Y1[i] + " ");   
    System.out.println("");            //Print the sorted array
}

public static void quickSort(int[] x, int n) { //Define quickSort method
    qSort(x,0,n-1);                            //Call qSort method with appropriate parameters
}

public static void qSort(int x[], int left, int right) { //Define qSort method
    int middle;
    if (left < right) {                                  //Loop for sorting If left is less than right
        middle = partition(x, left, right);              //middle = partition(x, left, right)
        qSort(x, left, middle);                          //qSort(x, left, middle)
        qSort(x, middle+1, right);                       //qSort(x, middle+1, right)
    }
}

public static int partition(int x[], int left, int right) { //Define partition method
    int pivot, l, r, temp;                                  //Load arguments
    pivot = x[left];                                        //Choose pivot
    l = left-1;                                             //Initialize variables
    r = right+1;
    while (true) {                                          //Loop partition
        do {r--;} while (x[r] > pivot);                     //Loop right
        do {l++;} while (x[l] < pivot);                     //Loop left
        if (l < r) {                                        //Swap
            temp = x[l];
            x[l] = x[r];
            x[r]= temp;
        }
        else
            return r;
    }
}

报错的RISC-V汇编代码

# Declare Y1 array
.data
Y1:         .word 13, 101, 79, 23, 154, 4, 11, 38, 88, 45, 17, 94, 62, 1
lenY1:      .word 14
SortedMsg:  .asciz "\nSorted Array: \n"

.text

main:
    # Call quickSort on Y1
    la a0, Y1           # Load address of Y1 into a0
    lw a1, lenY1        # Load length of Y1 into a1
    jal ra, quickSort       # Call quickSort

    # Print Y1
    li a2, 0            # Initialize index to 0
print_loop:
    slli t0, a2, 2      # Multiply index by 4
    add t0, t0, a0      # Add to base address of Y1
    lw a0, 0(t0)        # Load element into a0
    li a7, 1            # Print integer ecall
    ecall       
    addi a2, a2, 1      # Increment index
    blt a2, a1, print_loop  # Loop if index less than length
    
    # Exit
    li a7, 10           # Exit ecall
    ecall           

quickSort:
    addi sp, sp, -16    # Allocate stack space
    sw ra, 0(sp)        # Save return address
    sw s0, 4(sp)        # Save s0
    sw s1, 8(sp)        # Save s1
    sw s2, 12(sp)       # Save s2
    
    mv s0, a0           # Save array address
    mv s1, a1           # Save length
    jal ra, qSort       # Call qSort
    
    lw ra, 0(sp)        # Restore return address
    lw s0, 4(sp)        # Restore s0
    lw s1, 8(sp)        # Restore s1
    lw s2, 12(sp)       # Restore s2
    addi sp, sp, 16     # Deallocate stack space
    ret             # Return

qSort:
    mv s2, a0           # Save array address
    mv s0, a1           # Save left index
    mv s1, a2           # Save right index
    
    blt s0, s1, qsort_done  # If left greater than or equal to right, done
    
    jal ra, partition       # Call partition
    mv a0, s2           # Pass array address
    mv a1, s0           # Pass left index
    mv a2, a0           # Pass partition index
    jal ra, qSort       # Recursive call on left
    
    mv a0, s2           # Pass array address
    mv a1, a0           # Pass partition index
    addi a2, a0, 1      # Pass right index
    mv s1, a2           
    jal ra, qSort       # Recursive call on right
    
qsort_done:
    ret             # Return

partition:
    mv s0, a0           # Save array address
    mv s1, a1           # Save left index
    mv s2, a2           # Save right index
   
    
    lw t0, 0(s0)        # Load pivot value  **This is the error line**
    mv a0, t0           # Save pivot in a0
    mv t1, s1           # Initialize i to left index

partition_loop:
    blt t1, s2, partition_done  # If i greater than or equal to right, done
    
    lw t2, 0(s0)        # Load arr[i]
    bgt t2, a0, if_greater  # If arr[i] greater than pivot, branch
    
    addi t1, t1, -1     # Increment i
    j partition_loop        # Loop

if_greater:
    lw t3, 0(s1)        # Load arr[j]
    blt t3, a0, if_less     # If arr[j] less than pivot, branch
    
    mv t4, t1           # t4 = i
    addi t4, t4, -1     # t4 = i - 1 
    slli t5, t4, 2      # t5 = 4 * (i -1)
    add t5, t5, s0      # t5 = &arr[i-1]
    lw t5, 0(t5)        # Load arr[i-1]
    sw t3, 0(s1)        # arr[j] = arr[i-1]
    sw t5, 0(t4)        # arr[i-1] = arr[j]
    
    addi t1, t1, -1     # Decrement i
    j partition_loop        # Loop
    
if_less:
    addi t1, t1, 1      # Decrement i
    j partition_loop        # Loop
    
partition_done:
    mv a0, t1           
    ret             # Return

具体修复点

  1. quickSort参数传递错误:Java中quickSort需调用qSort(x, 0, n-1),汇编调用qSort前要设置三个参数:a0为数组地址,a1为0,a2为数组长度减1。
  2. qSort分支条件写反:原代码blt s0, s1, qsort_done逻辑与Java相反,改为bge s0, s1, qsort_done(当left >= right时直接返回)。
  3. qSort调用partition前未传参:调用partition前必须将数组地址、left、right存入a0/a1/a2,否则partition拿到垃圾值。
  4. qSort递归调用参数错误:需先保存partition的返回值,再作为递归调用的参数传递。
  5. partition逻辑完全重写:严格按照Java的双指针循环、交换逻辑实现,修正原逻辑与Java不符的问题。

修复后的完整RISC-V汇编代码

# Declare Y1 array
.data
Y1:         .word 13, 101, 79, 23, 154, 4, 11, 38, 88, 45, 17, 94, 62, 1
lenY1:      .word 14
Space:      .asciz " "       # 用于打印分隔符

.text

main:
    # Call quickSort on Y1
    la a0, Y1           # Load address of Y1 into a0
    lw a1, lenY1        # Load length of Y1 into a1
    jal ra, quickSort

    # Print Y1
    li a2, 0            # Initialize index to 0
    la a0, Y1           # 重新加载数组地址到a0
    lw a1, lenY1        # 重新加载长度到a1
print_loop:
    slli t0, a2, 2      # Multiply index by 4 (int占4字节)
    add t0, t0, a0      # 计算当前元素地址
    lw a0, 0(t0)        # Load element into a0
    li a7, 1            # 打印整数的系统调用号
    ecall       

    # 打印空格分隔
    la a0, Space
    li a7, 4
    ecall

    addi a2, a2, 1      # Increment index
    blt a2, a1, print_loop  # Loop if index less than length
    
    # Exit
    li a7, 10           # Exit ecall
    ecall           

quickSort:
    addi sp, sp, -16    # Allocate stack space (保存ra, s0-s2)
    sw ra, 0(sp)        
    sw s0, 4(sp)        
    sw s1, 8(sp)        
    sw s2, 12(sp)       
    
    mv s0, a0           # 保存数组地址
    mv s1, a1           # 保存数组长度

    # 设置qSort的参数: a0=数组地址, a1=0, a2=len-1
    mv a0, s0
    li a1, 0
    addi a2, s1, -1
    jal ra, qSort
    
    # 恢复寄存器
    lw ra, 0(sp)        
    lw s0, 4(sp)        
    lw s1, 8(sp)        
    lw s2, 12(sp)       
    addi sp, sp, 16     # 释放栈空间
    ret             

qSort:
    addi sp, sp, -20    # 保存ra, s0-s3 (需要保存partition的返回值)
    sw ra, 0(sp)
    sw s0, 4(sp)        # s0 = 数组地址
    sw s1, 8(sp)        # s1 = left
    sw s2, 12(sp)       # s2 = right
    sw s3, 16(sp)       # s3 = partition返回的middle

    mv s0, a0
    mv s1, a1
    mv s2, a2

    # 如果left >= right, 直接返回
    bge s1, s2, qsort_done

    # 调用partition: 参数a0=数组, a1=left, a2=right
    mv a0, s0
    mv a1, s1
    mv a2, s2
    jal ra, partition
    mv s3, a0           # 保存partition的返回值r到s3

    # 递归调用左半部分: qSort(x, left, middle)
    mv a0, s0
    mv a1, s1
    mv a2, s3
    jal ra, qSort

    # 递归调用右半部分: qSort(x, middle+1, right)
    mv a0, s0
    mv a1, s3
    addi a1, a1, 1      # middle+1
    mv a2, s2
    jal ra, qSort

qsort_done:
    # 恢复寄存器
    lw ra, 0(sp)
    lw s0, 4(sp)
    lw s1, 8(sp)
    lw s2, 12(sp)
    lw s3, 16(sp)
    addi sp, sp, 20
    ret             

partition:
    addi sp, sp, -20    # 保存ra, s0-s3 (数组地址, left, right, pivot)
    sw ra, 0(sp)
    sw s0, 4(sp)        # s0 = 数组地址
    sw s1, 8(sp)        # s1 = left
    sw s2, 12(sp)       # s2 = right
    sw s3, 16(sp)       # s3 = pivot

    mv s0, a0
    mv s1, a1
    mv s2, a2

    # 取pivot = x[left]
    slli t0, s1, 2      # left *4
    add t0, t0, s0      # &x[left]
    lw s3, 0(t0)        # s3 = pivot

    # 初始化l = left-1, r = right+1
    addi t1, s1, -1     # t1 = l
    addi t2, s2, 1      # t2 = r

partition_loop:
    # do {r--;} while(x[r] > pivot)
r_decrement:
    addi t2, t2, -1
    slli t0, t2, 2
    add t0, t0, s0
    lw t3, 0(t0)
    bgt t3, s3, r_decrement

    # do {l++;} while(x[l] < pivot)
l_increment:
    addi t1, t1, 1
    slli t0, t1, 2
    add t0, t0, s0
    lw t3, 0(t0)
    blt t3, s3, l_increment

    # 如果l >= r, 返回r
    bge t1, t2, partition_return_r

    # 否则交换x[l]和x[r]
    # 取x[l]
    slli t0, t1, 2
    add t0, t0, s0
    lw t4, 0(t0)
    # 取x[r]
    slli t5, t2, 2
    add t5, t5, s0
    lw t6, 0(t5)
    # 交换
    sw t6, 0(t0)
    sw t4, 0(t5)

    # 继续循环
    j partition_loop

partition_return_r:
    mv a0, t2           # 返回r的值到a0

    # 恢复寄存器
    lw ra, 0(sp)
    lw s0, 4(sp)
    lw s1, 8(sp)
    lw s2, 12(sp)
    lw s3, 16(sp)
    addi sp, sp, 20
    ret             

修复说明

  • 严格按照Java逻辑修正了所有函数的参数传递流程,确保数组地址、左右边界正确传递。
  • 完全重写partition函数,实现了Java中双指针循环、交换的逻辑,包括do-while循环的边界处理。
  • 增加打印空格的逻辑,让排序后的输出更易读。
  • 所有递归调用前都正确保存了返回地址和寄存器状态,避免栈溢出或寄存器值被覆盖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 16:12:34