section .text
global _start
_start:
nop
main:
mov eax, 1
mov ebx, 2
xor eax, eax
ret
我用这些命令编译:
nasm -f elf main.asm
ld -melf_i386 -o main main.o
当我运行代码时,Linux抛出了分段错误错误
(我正在使用Linux Mint Nadia 64位)。为什么会产生这个错误?
答案 0 :(得分:8)
因为ret
不是在Linux,Windows或Mac中退出程序的正确方法!!!!
_start
不是函数,堆栈上没有返回地址,因为没有用户空间调用者返回。用户空间中的执行在此处(在静态可执行文件中)在进程入口点开始。 (或者使用动态链接,它在动态链接器完成后跳转到此处,但结果相同)。
在Linux / OS X上,堆栈指针在argc
的条目上指向_start
(有关流程启动环境的更多详细信息,请参阅i386或x86-64 System V ABI doc);在启动用户空间之前,内核将命令行参数放入用户空间堆栈内存中。 (所以,如果你尝试ret
,EIP / RIP = argc =一个小整数,而不是一个有效的地址。如果你的调试器在地址0x00000001
或其他地方显示错误,那就是原因。)
对于Windows,它是ExitProcess
,Linux是系统调用 -
int 80H
使用sys_exit
,使用syscall
,使用60
使用exit
获取64位,或者如果要链接到C库则调用mov eax, sys_exit ; sys_exit = 1
xor ebx, ebx
int 80H
。< / p>
32位Linux
mov rax, 60
xor rdi, rdi
syscall
64位Linux
push 0
call ExitProcess
<强>窗强>
call exit
或Windows / Linux链接到C库
exit
_exit
(与原始退出系统调用或libc printf
不同)将首先刷新stdio缓冲区。如果您使用_start
中的exit
,请使用main
确保在退出之前打印所有输出,即使将stdout重定向到文件(使stdout完全缓冲,而不是行 - 缓冲)。
通常建议如果你使用libc函数,你编写一个ret
函数并与gcc链接,这样就可以通过普通的CRT启动函数调用它,你可以main
到。
将_start
定义为main
落入的内容并不会使其变得特别,如果它不像C main
那么使用_start
标签会让人感到困惑由main
调用的函数,准备在{{1}}返回后退出。