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

RISC-V汇编中execve系统调用失败返回242错误码排查

问题背景
  • 开发环境:从GitHub获取RISC-V工具链,使用以下命令完成配置:
./configure /opt/rv32
./configure --prefix=/opt/rv32 --with-arch=rv32ia --with-abi=ilp32
  • 运行环境:通过qemu-user提供的qemu-riscv32命令运行编译生成的32位RISC-V二进制程序。
  • 目标:手写汇编代码实现execve系统调用,启动/bin/sh。
对照实现(C版本)

首先编写了功能等价的C代码作为对照,代码如下:

#include <unistd.h>

char *args[] = {"/bin/sh", 0x0};

int main()
{
    execve(args[0], args, 0x0);
}

使用-static参数静态编译后,对二进制文件反汇编得到核心汇编逻辑:

00010530 <main>:
   10530:   ff010113            addi    sp,sp,-16
   10534:   00112623            sw  ra,12(sp)
   10538:   00812423            sw  s0,8(sp)
   1053c:   01010413            addi    s0,sp,16
   10540:   a9418793            addi    a5,gp,-1388 # 85df0 <args>
   10544:   0007a703            lw  a4,0(a5)
   10548:   00000613            li  a2,0
   1054c:   a9418593            addi    a1,gp,-1388 # 85df0 <args>
   10550:   00070513            mv  a0,a4
   10554:   304160ef            jal ra,26858 <__execve>
   10558:   00000793            li  a5,0
   1055c:   00078513            mv  a0,a5
   10560:   00c12083            lw  ra,12(sp)
   10564:   00812403            lw  s0,8(sp)
   10568:   01010113            addi    sp,sp,16
   1056c:   00008067            ret

00026858 <__execve>:
   26858:   0dd00893            li  a7,221
   2685c:   00000073            ecall
   26860:   fffff8b7            lui a7,0xfffff
   26864:   00a8e463            bltu    a7,a0,2686c <__execve+0x14>
   26868:   00008067            ret
   2686c:   71d0406f            j   2b788 <__syscall_error>

该C程序无论是否添加-static编译参数都可以正常运行。

手写汇编版本与问题现象

参照反汇编结果编写的手写汇编代码如下:

.globl _start
.section .text

_start:
    # execve syscall
    la a0, shell # Pointer to '/bin/sh'
    la a1, addr # Pointer to the arraythat contains '/bin/sh'
    sw a0, 0(a1)
    mv a2, x0 # No environment variables are needed
    li a7, 0xDD # 221
    ecall
    # exit syscall
    li a7, 0x5D # 93
    ecall

.section .rodata
shell: .string "/bin/sh"
.section .data
addr: .space 4

使用以下命令编译汇编代码:

riscv32-unknown-linux-gnu-gcc -c syscall.s && riscv32-unknown-linux-gnu-ld syscall.o -o syscall

运行时execve系统调用失败,返回错误码242,在标准errno列表中找不到242对应的错误说明。

问题成因与修复方案

核心错误原因

  1. argv数组不符合系统调用规范
    POSIX标准明确要求,execve的第二个参数argv是一个以NULL指针结尾的字符串指针数组,数组长度至少为2(第一个元素是程序路径,最后一个元素是NULL哨兵)。
    你的代码中addr: .space 4仅预留了4字节空间,仅够存储1个32位指针,完全没有位置存放必须的末尾NULL值;你仅向该地址写入了/bin/sh的指针,后续内存值是未定义的非0值,内核遍历argv列表时读不到终止标记,会访问非法内存地址,触发EFAULT(错误码14,含义是坏地址)错误。

  2. 错误码242的来源
    RISC-V架构Linux系统调用的错误返回规则为:ecall返回后,如果a0寄存器的值落在[-4095, -1]区间(无符号32位表示为0xFFFFF001 ~ 0xFFFFFFFF),代表系统调用失败,返回值的绝对值就是errno。
    你看到的242是错误返回值-EFAULT(补码为0xFFFFFFF2)被截断低8位后的结果(0xF2=242),自然无法在errno表中找到242对应的条目。反汇编代码中__execve函数的判断逻辑lui a7,0xfffff; bltu a7,a0 <__syscall_error>就是在做这个错误区间判断。

修复后的可运行代码

直接在定义argv数组时完成初始化,避免运行时写入出错,同时保证数组以NULL结尾:

.globl _start
.section .text

_start:
    # execve系统调用,调用号221
    la a0, shell      # a0 = 待执行程序路径"/bin/sh"
    la a1, argv       # a1 = argv参数数组首地址
    mv a2, x0         # a2 = envp = NULL,不传入环境变量
    li a7, 221
    ecall

    # execve仅在调用失败时返回,执行exit退出,调用号93
    li a0, 1          # 退出码1代表执行失败
    li a7, 93
    ecall

.section .rodata
shell: .string "/bin/sh"
argv:  .word shell   # argv[0] = 程序路径指针
       .word 0       # argv数组必须以NULL指针作为结尾标记

使用原编译命令重新编译后即可正常运行,成功启动/bin/sh。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:09:21