_start 中 RET 上的 Nasm 分段错误 [英] Nasm segmentation fault on RET in _start
问题描述
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抛出一个segmentation fault错误
When I run the code, Linux throw a segmentation fault error
(我使用的是 Linux Mint Nadia 64 位).为什么会产生这个错误?
(I am using Linux Mint Nadia 64 bits). Why this error is produced?
推荐答案
因为 ret
不是 在 Linux、Windows 或 Mac 中退出程序的正确方法!!!!
Because ret
is NOT the proper way to exit a program in Linux, Windows, or Mac!!!!
_start
不是函数,栈上没有返回地址,因为没有用户空间调用者要返回.用户空间中的执行从这里开始(在静态可执行文件中),在进程入口点.(或者是动态链接,动态链接结束后就跳到这里了,结果一样)
_start
is not a function, there is no return address on the stack because there is no user-space caller to return to. Execution in user-space started here (in a static executable), at the process entry point. (Or with dynamic linking, it jumped here after the dynamic linker finished, but same result).
在 Linux/OS X 上,堆栈指针指向 _start
入口处的 argc
(有关更多详细信息,请参阅 i386 或 x86-64 System V ABI 文档)进程启动环境);内核在启动用户空间之前将命令行参数放入用户空间堆栈内存中.(因此,如果您确实尝试 ret
,EIP/RIP = argc = 一个小整数,而不是有效地址.如果您的调试器在地址 0x00000001
或其他地方显示错误,这就是为什么.)
On Linux / OS X, the stack pointer is pointing at argc
on entry to _start
(see the i386 or x86-64 System V ABI doc for more details on the process startup environment); the kernel puts command line args into user-space stack memory before starting user-space. (So if you do try to ret
, EIP/RIP = argc = a small integer, not a valid address. If your debugger shows a fault at address 0x00000001
or something, that's why.)
对于 Windows,它是 ExitProcess
而 Linux 是系统调用 -int 80H
使用 sys_exit
,对于 x86 或使用 syscall
使用 60
对于 64Bit 或调用 exit
来自 C 库(如果您要链接到它).
For Windows it is ExitProcess
and Linux is is system call -
int 80H
using sys_exit
, for x86 or using syscall
using 60
for 64Bit or a call to exit
from the C Library if you are linking to it.
32 位 Linux
mov eax, sys_exit ; sys_exit = 1
xor ebx, ebx
int 80H
64 位 Linux
mov rax, 60
xor rdi, rdi
syscall
Windows
push 0
call ExitProcess
<小时>
或针对 C 库的 Windows/Linux 链接
call exit
exit
(与原始退出系统调用或 libc _exit
不同)将首先刷新 stdio 缓冲区.如果您使用 _start
中的 printf
,请使用 exit
确保在退出之前打印所有输出,即使 stdout 被重定向到文件(使标准输出全缓冲,而不是行缓冲).
exit
(unlike a raw exit system call or libc _exit
) will flush stdio buffers first. If you used printf
from _start
, use exit
to make sure all output is printed before you exit, even if stdout is redirected to a file (making stdout full-buffered, not line-buffered).
一般建议如果你使用libc函数,你写一个main
函数并与gcc链接,这样它就会被普通的CRT启动函数调用,你可以ret
.
It's generally recommended that if you use libc functions, you write a main
function and link with gcc so it's called by the normal CRT start functions which you can ret
to.
将 main
定义为 _start
落入的东西并没有使它特别,如果使用 main
标签只是令人困惑不像一个由 _start
调用的 C main
函数,它准备在 main
返回后退出.
Defining main
as something that _start
falls through into doesn't make it special, it's just confusing to use a main
label if it's not like a C main
function called by a _start
that's prepared to exit after main
returns.
这篇关于_start 中 RET 上的 Nasm 分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!