为什么从_start segfault返回?

时间:2016-09-18 06:47:13

标签: assembly stack system-calls exit

我尝试将代码放在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

但是为什么弹出堆栈帧和设置的基本帧指针到前一帧的基数这样的结尾会导致分段错误?

确实,退出系统调用会优雅地退出。

2 个答案:

答案 0 :(得分:3)

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

这就是:

  

$ gdb ./main
  [...]
  程序接收信号SIGSEGV,分段故障   0x0000000000000001在?? ?? ()
  
  (gdb)x / gx $ rsp-8
  0x7fffffffe650:0x0000000000000001

所以,很可能你的程序运行完毕,但堆栈上的第一件事就是0x0000000000000001。 RET将其弹出到RIP寄存器中,然后将其分段,因为该地址未映射。

我没有在Linux上编写很多代码,但我敢打赌使用退出系统调用需要_start。你可以返回一个有用的地址的唯一方法是,如果内核在某个地方放置一个可以为你做这个的函数。

答案 1 :(得分:3)

根据ABI 1 _start条目的堆栈是

Stack at entry on _start

没有"返回地址"。
退出流程的唯一方法是SYS_EXIT

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

1 部分 3.4.1初始堆栈和注册状态