NASM自定义print函数打印EAX二进制位时出现段错误问题
段错误原因排查与修复方案
核心问题原因
- 非法修改栈指针ESP:打印逻辑中
mov esp,printDD_var_save直接改写了栈寄存器,导致后续恢复寄存器、执行ret指令时,栈指针指向的是你定义的字符缓冲区而非原始栈位置,读取的返回地址和寄存器值全部非法,直接触发段错误。获取缓冲区地址完全不需要修改ESP,直接计算有效地址赋值给ECX即可。 - 缓冲区越界写入:写入字符时使用了
dword(4字节)操作数,每次写操作会覆盖当前偏移后4个字节的内存,当esi遍历到28以上时,写入位置已经超出你预留的32字节缓冲区范围,会破坏后续内存数据。存储单个ASCII字符只需用byte(1字节)操作数即可。 - 栈操作顺序不匹配:入栈顺序是
push ebx -> push ecx -> push edx -> push esi -> push esp,栈是后进先出结构,出栈顺序应该完全反过来,你当前的出栈顺序和入栈顺序完全不对应,就算没有修改ESP的问题,恢复的寄存器值也是错误的。另外你没有用到保存的ESP值,完全不需要额外push/pop ESP。
修复后代码
;传入参数:待打印值存在eax寄存器 ;需要提前定义:printDD_var_save resb 32,newline db 0xA printDD_start: push ebx push ecx push edx push esi mov esi,0 printDD: cmp esi,31 jg printDD_printStart test eax,1 jz printDD_zero printDD_one: mov byte [printDD_var_save + esi],49 inc esi shr eax,1 jmp printDD printDD_zero: mov byte [printDD_var_save + esi],48 inc esi shr eax,1 jmp printDD printDD_printStart: mov esi,31 printDD_print: cmp esi,0 jl printDD_exit ; 直接计算要打印的字符地址赋值给ecx,完全不碰esp lea ecx, [printDD_var_save + esi] mov eax,4 mov ebx,1 mov edx,1 int 80h dec esi jmp printDD_print printDD_exit: mov eax,4 mov ebx,1 mov ecx,newline mov edx,1 int 80h ; 出栈顺序和入栈严格相反 pop esi pop edx pop ecx pop ebx ret
优化提示:如果追求性能可以一次性打印32个字符,不需要循环32次调用write系统调用,修改打印逻辑直接传入printDD_var_save地址、长度32即可,运行效率会高很多。
内容的提问来源于stack exchange,提问作者kmer14
相关产品推荐
相关产品推荐

