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

NASM汇编读取C函数参数及QEMU测试崩溃问题排查

32位自定义OS中C调用汇编函数readbyte的参数传递与地址访问问题

问题背景

我正在基于NASM开发简易32位操作系统,需要实现一个汇编函数readbyte,接收C程序传入的内存地址参数,读取对应地址的字节并返回。当前代码如下:

C代码(kernel.c)

extern int readbyte();

int main(void) {
  int x = readbyte(0xdeadbeef); // 尝试读取0xdeadbeef地址的数据
  return 0;
}

汇编代码(kernel_entry.asm)

[bits 32]
[extern main]
[extern readbyte]

call main

readbyte:
  ; 此处需要获取C传入的参数
  mov eax, [ecx] ; 尝试从指定地址读取字节
  ret ; 返回数据到C函数

目前通过eax返回数据的逻辑正常,但无法正确获取C传入的参数;按照建议修改为从栈中取参数后(mov ecx, [esp + 4]),程序在QEMU中出现崩溃,且发现传入少于4位的十六进制地址(如0xABC)时能正常运行,传入4位及以上(如0xABCD)则崩溃。

问题分析

  1. 调用约定与参数位置
    32位x86平台的C默认调用约定(cdecl)是参数从右到左压栈,第一个参数位于esp+4的位置(因为函数调用后,栈顶是返回地址,占4字节)。你修改后的参数获取逻辑是正确的,但崩溃的核心原因并非参数传递,而是地址访问合法性。

  2. 内存地址访问限制
    在自定义OS中,并非所有内存地址都能直接访问:

    • 低地址(如0xABC)属于实模式下的常规内存区域,切换到保护模式后通常仍可直接访问,因此不会触发异常;
    • 像0xdeadbeef、0xABCD这类地址,要么属于未被OS初始化的物理内存,要么是硬件保留区域、未映射的虚拟内存,直接访问会触发页错误或CPU异常,导致系统崩溃。
  3. 寄存器保护问题
    cdecl调用约定中,ebx、esi、edi、ebp属于被调用者保存寄存器,如果你的汇编函数修改了这些寄存器,必须先入栈保存,函数结束时恢复,否则会破坏调用者(C程序)的寄存器状态,引发未知错误。

解决方案

1. 修正汇编函数的参数处理与地址合法性检查

修改readbyte函数,正确获取参数、保护寄存器,并添加地址合法性校验:

[bits 32]
[extern main]

call main

readbyte:
    push ebx                ; 保护被调用者保存寄存器ebx
    mov ecx, [esp + 8]      ; 因为push了ebx,参数位置变为esp+8(4字节ebx + 4字节返回地址)
    
    ; 示例:检查地址是否在OS已初始化的可访问内存范围内(假设是0x0到0xFFFF)
    cmp ecx, 0xFFFF
    ja .invalid_addr        ; 地址超出范围则跳转到错误处理
    
    mov al, [ecx]           ; 读取1字节数据到al
    movzx eax, al           ; 将无符号字节扩展为32位int返回(若需处理有符号字节用movsx)
    pop ebx
    ret

.invalid_addr:
    mov eax, 0xFFFFFFFF     ; 返回错误码表示地址无效
    pop ebx
    ret

2. 使用合法的内存地址测试

在C代码中,传入OS已分配的合法内存地址(比如全局变量的地址),而非随机的高地址:

extern int readbyte(int addr);

int test_data = 0x12; // 位于OS的.data段,属于可访问内存

int main(void) {
  int x = readbyte((int)&test_data); // 传入合法地址
  return 0;
}

3. 检查OS的内存映射配置

如果需要访问高地址内存,必须确保:

  • 若未开启分页:仅能访问低1MB内存,超过的地址会触发异常;
  • 若开启分页:需在页表中添加对应地址的映射项,将虚拟地址映射到物理内存,并设置正确的读写权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:40:28