NASM汇编中函数调用内pop指令失效的原因及解决方法?
问题原因与解决方法
核心问题
call指令执行时会自动将返回地址压入栈顶,所以你执行push keystring+0x7c00后,栈内的顺序是:
- 栈顶:返回地址(
call指令的下一条指令地址) - 栈顶+4:你push的字符串指针
此时直接pop ecx拿到的是返回地址,而非字符串指针,自然无法正确打印。
解决方法
方法1:暂存返回地址再取出参数
先弹出返回地址暂存,取出参数后再把返回地址压回栈顶,保证ret能正确返回:
push keystring+0x7c00 call PrintString jmp $ ;====functions==== PrintString: pop eax ; 弹出返回地址到eax暂存 pop ecx ; 弹出字符串参数到ecx push eax ; 将返回地址重新压回栈顶,让ret正常工作 mov ah, 0x0e LoopHead: mov al, [ecx] test al, al ; 检查当前字符是否为结束符0 jz PrintEnd ; 是结束符就退出循环 int 0x10 ; BIOS中断打印字符 inc ecx ; 指针移到下一个字符 jmp LoopHead PrintEnd: ret ;====variables==== keystring: db "Press any key...", 0 ;====padding==== times 510-($-$$) db 0 db 0x55, 0xAA
方法2:通过栈偏移直接访问参数
利用栈偏移读取参数,最后用ret 4清理栈上的参数:
push keystring+0x7c00 call PrintString jmp $ ;====functions==== PrintString: mov ecx, [esp+4] ; 直接从栈中读取参数(返回地址在esp,参数在esp+4位置) mov ah, 0x0e LoopHead: mov al, [ecx] test al, al jz PrintEnd int 0x10 inc ecx jmp LoopHead PrintEnd: ret 4 ; 返回时同时弹出栈上的4字节参数,清理栈空间 ;====variables==== keystring: db "Press any key...", 0 ;====padding==== times 510-($-$$) db 0 db 0x55, 0xAA
额外说明
原代码中的循环逻辑存在问题:add bl, [ecx]的判断方式错误,应该直接检查当前字符是否为字符串结束符0,用test al, al配合jz指令是更标准的字符串遍历写法。
内容的提问来源于stack exchange,提问作者Humanagon
相关产品推荐
相关产品推荐

