assembly RET in _start上的Nasm分段错误

qyyhg6bp  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(136)
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位)。为什么会产生这个错误?

7qhs6swi

7qhs6swi1#

因为ret不是在Linux、Windows或Mac中退出程序的正确方式!!!!

_start不是函数,堆栈上没有返回地址因为没有要返回的用户空间调用方。用户空间中的执行从此处(在静态可执行文件中)的进程入口点开始。(或者使用动态链接,它在动态链接器完成后跳到此处,但结果相同)。

在Linux / OS X上,堆栈指针指向_start入口上的argc(有关进程启动环境的更多详细信息,请参见i386或x86-64 System V ABI文档);内核在启动用户空间之前将命令行参数放入用户空间堆栈内存。(因此,如果您确实尝试ret,EIP/RIP = argc =一个小整数,而不是一个有效的地址。如果您的调试器在地址0x00000001或其他位置显示错误,这就是原因。)
对于Windows,它是ExitProcess,Linux是系统调用-int 80H(使用sys_exit),对于x86或使用syscall(使用60)(对于64位),或者从C库调用exit(如果您链接到它)。

32位Linux(i386)
%define  SYS_exit  1   ; call number __NR_exit from <asm/unistd_32.h>

mov     eax, SYS_exit  ; use the NASM macro we defined earlier
xor     ebx, ebx       ; ebx = 0  exit status
int     80H            ; _exit(0)
64位Linux(amd 64)
mov     rax, 60        ; SYS_exit aka __NR_exit from asm/unistd_64.h
xor     rdi, rdi       ; edi = 0  first arg to 64-bit system calls
syscall                ; _exit(0)

(In GAS你实际上可以通过#include <sys/syscall.h><asm/unistd.h>来获得你要组装.S的模式的正确数字,但是NASM不能很容易地使用C预处理器(参见Polygot include file for nasm/yasm and C以获得提示)。

32位Windows(x86)
push    0
call    ExitProcess

或Windows/Linux链接到C库

; pass an int exit_status as appropriate for the calling convention
; push 0   /  xor edi,edi  /  xor ecx,ecx
call    exit

(Or对于32位x86 Windows,为call _exit,因为C名称前面会加上下划线,这与x86-64 Windows不同。如果Windows有POSIX _exit函数,则该函数为call __exit。)
Windows x64的调用约定包括调用者必须保留的影子空间,但是exit不会返回,所以可以让它在返回地址上方的空间上步进。此外,除了32位Windows之外,在call exit之前的调用约定要求16字节堆栈对齐,但是对于像exit()这样的简单函数,通常不会实际崩溃。

call exit(与原始退出系统调用或libc _exit不同)将首先刷新stdio缓冲区。如果您从_start使用了printf,请使用exit确保在退出前打印所有输出,即使stdout被重定向到文件(使stdout成为全缓冲区,而不是行缓冲区)。

如果使用libc函数,通常建议您编写一个main函数并与gcc链接,以便由您可以ret调用的正常CRT启动函数调用它。
另请参阅

main定义为_start福尔斯的东西并没有使它变得特别,只是如果它不像_start调用的C main函数那样,在main返回后准备退出,那么使用main标签会让人感到困惑。

相关问题