在x86汇编中实现简单print函数时遇段错误求助
错误分析
栈帧参数偏移计算错误
进入print函数后,32位环境下的栈帧结构(每个栈项4字节):[ebp]:保存的旧EBP值[ebp+4]:函数返回地址[ebp+8]:第一个参数msg(字符串地址)[ebp+12]:第二个参数len(字符串长度)
你代码中用[bp+4]和[bp+6]读取参数,拿到的是返回地址的部分无效数据,这是引发段错误的核心原因。
参数压栈顺序与方式错误
- C调用约定(cdecl)下,函数参数需从右往左压栈,
print(msg, len)应该先压入长度13,再压入字符串地址msg,你写反了顺序。 push [msg]是取msg地址指向的第一个字节('H'的ASCII码),而非msg本身的地址,应该直接push msg(msg是字符串的起始地址标签)。
- C调用约定(cdecl)下,函数参数需从右往左压栈,
系统调用参数寄存器对应错误
Linux 32位write系统调用(eax=4)的参数对应关系:ebx:文件描述符(1代表标准输出)ecx:字符串缓冲区的起始地址edx:字符串的长度
你代码中把长度放到ecx、地址放到edx,完全搞反,导致write尝试读取错误的内存区域。
ret指令清理栈的字节数错误
调用print时压入了两个4字节参数(共8字节),ret 4仅清理4字节,会导致栈指针不平衡,后续执行exit系统调用时栈状态异常。
修正后的代码
.global _start .intel_syntax noprefix .section .text # void print(char *msg, int len) print: push ebp mov ebp, esp mov ecx, [ebp+8] # 第一个参数:msg地址 mov edx, [ebp+12] # 第二个参数:长度len mov eax, 4 # write系统调用号 mov ebx, 1 # 标准输出文件描述符 int 0x80 pop ebp ret 8 # 清理两个4字节参数,共8字节 _start: push 13 # 先压入第二个参数:长度 push msg # 再压入第一个参数:msg地址 call print mov eax, 1 # exit系统调用号 mov ebx, 0 # 退出码0 int 0x80 .section .data msg: .ascii "Hello, world!\n"
编译运行验证
仍使用你原来的命令:
as test.asm --32 -o test.o gcc -m32 test.o -nostdlib
运行编译后的程序即可正常输出Hello, world!。
内容的提问来源于stack exchange,提问作者Leon Gurin
相关产品推荐
相关产品推荐

