Assembly 为什么从_返回时会启动segfault?
我试图将代码不放在main函数中,而是直接放在Assembly 为什么从_返回时会启动segfault?,assembly,stack,system-calls,exit,Assembly,Stack,System Calls,Exit,我试图将代码不放在main函数中,而是直接放在\u 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 运行: 我读了,离开了 mov esp,ebp pop ebp 但是,为什么对弹出堆栈帧的这种尾声和
\u 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
运行:
我读了,离开了
mov esp,ebp
pop ebp
但是,为什么对弹出堆栈帧的这种尾声和指向前一帧的基帧的set base frame指针会导致分割错误呢
事实上,发出退出系统调用可以优雅地退出。LEAVE指令被定义为不会导致任何异常,因此它不能成为您的故障源。您应该使用GDB。调试器在解决这类问题方面是无价的 情况就是这样: $gdb./main
[…]
程序接收信号SIGSEGV,分段故障。
0x0000000000000001英寸??()
(gdb)x/gx$rsp-8
0x7FFFFFE650:0x0000000000000001 因此,您的程序很可能运行完成,但堆栈上的第一件事是0x0000000000000001
RET
将其弹出到RIP
寄存器中,然后它会出现故障,因为该地址未映射
我在Linux上写的代码不多,但我敢打赌使用exit系统调用需要\u start
。您可能返回到有用地址的唯一方法是,如果内核将一个函数放在某个可以为您执行此操作的位置。根据1,在\u start
上的条目处的堆栈是
没有“回信地址”。退出流程的唯一方法是通过
SYS\u exit
xorl %edi, %edi ;Error code
movl $60, %eax ;SYS_EXIT
syscall
1第3.4.1节初始堆栈和寄存器状态。
\u start
不是由内核调用的,您不能从中返回。您能详细说明一下吗?我认为这是普通的例行公事。如何正确地“返回/退出”it?通过退出系统呼叫?是的,在提出问题之前,我使用了gdb并在main.s:7 7 ret(gdb)n 0x0000000000000001中显示了6 leave(gdb)n_start()??()
没有发布,因为不知道“?”是什么意思。我也考虑将rip设置为内存中的未映射位置,但是,如果能够准确地知道,那就太好了。这意味着地址不在有效的模块中。因为GDB不知道它属于哪个模块,所以它会打印“?”。这里需要注意的关键是0x0000000000000001不是有效的可执行地址。当RIP指向无效或不可执行的地址时,它通常是由RET指向错误地址或间接JMP或调用错误地址引起的。如果是RET,就像这里的情况一样,堆栈顶部下面的8个字节将匹配RIP。如果是JMP或调用,有时寄存器会与RIP匹配。确实,您可能会期望堆栈上的第一个值为1,因为这是Linux传递argc
值的地方,并且在没有任何参数的情况下调用的程序的argc
值为1。关于参数的有用提示。所以要得到argc和argv,应该分别使用ebp+8和ebp+16堆栈偏移量?这回答了我的问题。
xorl %edi, %edi ;Error code
movl $60, %eax ;SYS_EXIT
syscall