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

QEMU-RISCV64运行未知错误:调用RISC-V汇编函数程序冻结

RISC-V64汇编函数调用问题排查与修复

问题描述

我开发了一个程序,用来获取传入的第二个参数首字符,判断它是大写还是小写字母。现在调用另一个文件里的RISC-V64汇编函数时出了问题:汇编代码本该返回0、1、2给C文件里的int result变量,但实际没生效;而且汇编单独测试是好的,编译没错误,但运行时程序卡住,像在等输入。

相关代码

ARQUIVO.C

#include <stdio.h>

extern int verificando(char*);

int main(int argc, char *argv[]){

    argc = 3;
    argv[1] = "maracuja";
    argv[2] = "Graviola";
    
    int result;
    
    result = verificando(&(argv[2][0]));
    
    if (result == 0){
        printf("\n%s: Primeiro caracter da segunda string eh minusculo.\n", argv[2]);
    }else if (result == 1){
        printf("\n%s: Primeiro caracter da segunda string eh maiusculo.\n", argv[2]);
    }else if (result == 2){
        printf("\nNao existe uma segunda string.\n");
    }else {
        printf("\nErro\n");
    }
    
    return 0;
}

ARQUIVO.S

.global verificando

verificando:
    #ascii
    li t5, 65
    li t6, 90
    li t3, 97
    li t4, 122

    # carrega o primeiro caracter do segundo argumento em t1 e verifica
    lb t1, 0(a0)
    jal verifica
    

verifica:
    bge t6, t1, maiuscula 
    bge t1, t3, minuscula 
    bge t3, t1, erro 

maiuscula:

    bge t1, t5, maiuscula_2 
    bge t1, t3, minuscula 
    bge t5, t1, erro 

minuscula:
    bge t4, t1, minuscula_2 

    li a0, 2
    ret
   


maiuscula_2: # returns 1
    li a0, 1
    ret

minuscula_2: # returns 0
    li a0, 0
    ret

erro: # returns 2
    li a0, 2
    ret

MAKEFILE

default:
    riscv64-linux-gnu-gcc -static arquivo.s arquivo.c -o arquivo.x
run: default
    qemu-riscv64-static arquivo.x
clean:
    rm -rf *.x

问题分析与修复

1. 汇编函数无法返回导致程序冻结

verificando函数中使用jal verifica调用子过程,verifica执行ret后会回到jal verifica的下一行,但verificando中该位置没有任何返回指令(ret),导致函数无法正常返回给C调用者,程序因此陷入等待状态。

修复方式:移除冗余的jal verifica调用,将判断逻辑直接整合到verificando函数中,确保函数最终能通过ret返回。

2. 分支逻辑冗余且存在逻辑漏洞

原汇编的分支判断存在多余跳转,可能导致逻辑混乱。简化后的判断逻辑应该:

  • 先检查字符是否属于大写字母范围(ASCII 65-90),是则返回1
  • 否则检查是否属于小写字母范围(ASCII 97-122),是则返回0
  • 其他情况返回2

修复后的汇编代码

.global verificando

verificando:
    # 加载ASCII范围常量
    li t5, 65  # 'A'的ASCII码
    li t6, 90  # 'Z'的ASCII码
    li t3, 97  # 'a'的ASCII码
    li t4, 122 # 'z'的ASCII码

    # 加载第一个字符到t1
    lb t1, 0(a0)

    # 判断是否为大写字母
    bge t1, t5, check_upper_bound
    j check_lower

check_upper_bound:
    ble t1, t6, return_upper
    j check_lower

check_lower:
    bge t1, t3, check_lower_bound
    j return_error

check_lower_bound:
    ble t1, t4, return_lower
    j return_error

return_upper:
    li a0, 1
    ret

return_lower:
    li a0, 0
    ret

return_error:
    li a0, 2
    ret

3. C代码的优化建议

直接修改argc和argv的做法不符合规范,测试时可以直接传入目标字符串,避免潜在的内存问题:

#include <stdio.h>

extern int verificando(char*);

int main() {
    char *target_str = "Graviola";
    int result = verificando(target_str);
    
    if (result == 0){
        printf("\n%s: Primeiro caracter da segunda string eh minusculo.\n", target_str);
    }else if (result == 1){
        printf("\n%s: Primeiro caracter da segunda string eh maiusculo.\n", target_str);
    }else if (result == 2){
        printf("\nNao existe uma segunda string.\n");
    }else {
        printf("\nErro\n");
    }
    
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 00:50:20