【问题标题】:Nasm segmentation fault on RET in _start_start 中 RET 上的 Nasm 分段错误
【发布时间】:2013-11-14 14:46:58
【问题描述】:
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 位)。为什么会产生这个错误?

【问题讨论】:

  • 返回码应该不是这样的(Linux):mov eax, 1 mov ebx, 0 int 80h 在我看来,由于最后一行中的ret,您会遇到分段错误。

标签: linux assembly x86 nasm


【解决方案1】:

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

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

在 Linux / OS X 上,堆栈指针指向 argc 进入 _start(有关进程启动环境的更多详细信息,请参阅 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

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

或 Windows/Linux 链接到 C 库

call    exit

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

如果您使用 libc 函数,一般建议您编写一个 main 函数并与 gcc 链接,这样它就会被您可以 ret 到的普通 CRT 启动函数调用。

main 定义为_start 落入的东西并不会使它特别,如果它不像由_start 调用的C main 函数,那么使用main 标签只会令人困惑准备在main 返回后退出。

【讨论】:

  • @maxiperez 根本不是一个愚蠢的问题:)。它表明程序不仅仅是一个“主要”功能,而且它们以不同的方式与操作系统交互。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-10
  • 2014-01-31
相关资源
最近更新 更多