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

x86 NASM汇编调用divide过程ebp访问参数异常问题咨询

问题概述

我正在编写x86汇编(NASM)程序,核心功能是从用户侧获取被除数和除数,再调用自定义过程完成除法运算,将结果存入EAX寄存器后打印输出。我使用Paul Carter开发的asm_io.inc库实现C语言I/O功能。我使用以下命令编译运行程序:
nasm -f win32 source.asm
gcc source.obj driver.c asm_io.obj

问题描述

目前遇到的问题是:我向名为divide的自定义过程传入两个参数,尝试通过间接寻址方式访问参数(例如通过[ebp + 8]读取第一个参数),但最终读取到的是内存地址而非参数值。我已尝试调试但未定位到问题,请问我的代码存在什么错误导致结果异常?我的代码如下:

%include "asm_io.inc"

segment .data
        prompt1 db "Enter a dividend: ", 0
        prompt2 db "Enter a divisor: ", 0        
        answer1 db " divided by ", 0
        answer2 db " equals ", 0

segment .bss
        dividend resd 1
        divisor  resd 1

segment .text
        global  _asm_main
_asm_main:
        enter   0,0
        pusha

        mov     eax, prompt1
        call    print_string
        call    read_int
        mov     [dividend], eax

        mov     eax, prompt2
        call    print_string
        call    read_int
        mov     [divisor], eax

        mov     eax, [dividend]
        call    print_int

        mov     eax, answer1
        call    print_string

        mov     eax, [divisor]
        call    print_int

        mov     eax, answer2
        call    print_string

        push    dword dividend
        push    dword divisor
        call    divide
        add     esp, 8
        
        call    print_int

        popa
        mov     eax, 0
        leave                     
        ret
divide:
        push    ebp
        mov     ebp, esp

        mov     eax, [ebp + 8]
        div     dword [ebp + 4]

        pop     ebp
        ret
问题解答

错误原因

  • 参数传递错误:NASM语法中直接写标签名dividend/divisor获取的是变量的内存地址,你实际需要传递的是变量中存储的数值,需要加方括号取址获取值。
  • 栈参数偏移计算错误:CDECL调用约定下,进入divide过程后栈布局为:[ebp+0]为保存的旧ebp值、[ebp+4]为call指令压入的返回地址,传入的参数从[ebp+8]开始,你错误使用了[ebp+4]读取参数,拿到的是无效的返回地址值。
  • div指令使用不规范:32位无符号除法div的被除数是EDX:EAX组成的64位值,执行除法前未清零EDX会导致高位存在垃圾值,最终运算结果异常。
  • 参数传递顺序错误:CDECL约定参数从右向左压栈,要完成被除数 / 除数运算,应该先压除数,再压被除数,你当前的压栈顺序颠倒,即使偏移正确也会拿到错误的运算数。

修复后的代码

调用部分修改

; 替换原有的push参数代码
push    dword [divisor]   ; 先压右参数:除数
push    dword [dividend]  ; 再压左参数:被除数
call    divide
add     esp, 8

divide过程修改

divide:
        push    ebp
        mov     ebp, esp
        push    edx         ; 保存调用方的EDX寄存器值

        mov     eax, [ebp + 8]   ; 取被除数
        xor     edx, edx         ; 清零EDX,构造64位无符号被除数EDX:EAX
        div     dword [ebp + 12] ; 除以除数,商自动存入EAX,余数存入EDX

        pop     edx         ; 恢复调用方的EDX寄存器值
        pop     ebp
        ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 17:18:04