x86 NASM汇编调用divide过程ebp访问参数异常问题咨询
问题概述
我正在编写x86汇编(NASM)程序,核心功能是从用户侧获取被除数和除数,再调用自定义过程完成除法运算,将结果存入EAX寄存器后打印输出。我使用Paul Carter开发的asm_io.inc库实现C语言I/O功能。我使用以下命令编译运行程序:nasm -f win32 source.asmgcc 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
相关产品推荐
相关产品推荐

