为什么从 _start 段错误返回?

Why does returning from _start segfault?

我试过不把代码放在main函数里,而是直接放到_start:

    segment .text
    global _start
_start:
    push rbp
    mov rbp, rsp
    ; ... program logic ...
    leave
    ret

编译:

yasm -f elf64 main.s
ld -o main main.o

运行:

./main
Segmentation fault(core dumped)

我看完了,离开是

mov esp,ebp
pop ebp

但为什么弹出堆栈帧的这种尾声和指向前一帧基的设置基帧指针会导致分段错误?

确实,进行退出系统调用可以正常退出。

LEAVE 指令被定义为不会导致任何异常,因此它不可能是您的错误来源。你应该使用 GDB。调试器在解决这类问题方面非常有用。

事情是这样的:

$ gdb ./main
[...]
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000001 in ?? ()

(gdb) x /gx $rsp-8
0x7fffffffe650: 0x0000000000000001

所以,很可能你的程序运行完成了,但是堆栈上的第一件事就是0x0000000000000001。 RET 将其弹出到 RIP 寄存器中,然后由于该地址未映射而出现段错误。

我没有在 Linux 上写很多代码,但我敢打赌 _start 是使用退出系统调用所必需的。您可能 return 到有用地址的唯一方法是,如果内核在某处放置一个函数可以为您执行此操作。

根据ABI1_start 入口处的栈是

没有"return address".
退出进程的唯一方法是通过 SYS_EXIT

xorl %edi, %edi   ;Error code
movl , %eax    ;SYS_EXIT
syscall

1 部分 3.4.1 初始堆栈和寄存器状态.