NASM代码打印db字节变量为整数时输出大值的原因
问题分析与解决方案
核心问题
- 参数传递错误:
- 原代码
push dword n1是把n1的内存地址压入栈,而printf的%d需要实际的32位整数值,因此输出的是随机的地址数值。 - 改成
push dword [n1]时,由于n1是db(仅1字节),读取dword会从n1地址开始读取4个字节,把后续msg的前3个字符也包含进去,导致得到错误的四字节值。
- 原代码
- 栈未正确清理:
32位x86的cdecl调用约定中,printf属于调用者清理栈的函数,原代码调用后未手动恢复栈指针,可能引发栈不平衡问题。
正确修正方案
方案1:使用dd定义标准32位变量
直接将n1定义为4字节的双字类型,匹配%d的参数要求:
%include "io.inc" section .data n1 dd 2 ; 定义32位整数,匹配%d的参数类型 msg db 'Number is: %d',10,0 ; 修正拼写错误 section .text extern printf global main main: push ebp mov ebp, esp push dword [n1] ; 传递n1的实际数值 push msg call printf add esp, 8 ; 手动清理栈:两个4字节参数,共8字节 mov esp, ebp pop ebp ret
方案2:从单字节变量扩展为32位值传递
若必须保留db定义,需将单字节值扩展为完整的32位整数后再压栈:
%include "io.inc" section .data n1 db 2 msg db 'Number is: %d',10,0 section .text extern printf global main main: push ebp mov ebp, esp xor eax, eax ; 清空eax寄存器 mov al, [n1] ; 将单字节n1的值放入eax的低8位 push eax ; 压入完整的32位eax(已自动扩展为00000002) push msg call printf add esp, 8 ; 清理栈空间 mov esp, ebp pop ebp ret
关键注意事项
- 类型严格匹配:
printf的%d格式符对应32位int类型,必须传递4字节的整数值,禁止传递地址或不完整的内存读取结果。 - 调用栈维护:cdecl约定下,调用者必须手动清理参数栈,否则会破坏栈结构,导致后续执行异常。
内容的提问来源于stack exchange,提问作者leo
相关产品推荐
相关产品推荐

