_start中RET的Nasm分段错误

时间:2013-11-04 00:34:45

标签: linux assembly x86 nasm

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位)。为什么会产生这个错误?

1 个答案:

答案 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}}返回后退出。