小编典典

_start中RET上的nasm分段错误

linux

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位)。为什么会产生此错误?


阅读 340

收藏
2020-06-02

共1个答案

小编典典

因为ret不是 要退出的Linux,Windows或苹果机的程序的正确方法!!!!

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

在Linux / OS X上,堆栈指针指向指向的argc入口_start(有关进程启动环境的更多详细信息,请参见i386或x86-64 System
V ABI文档);内核在启动用户空间之前将命令行参数args放入用户空间堆栈内存中。(因此,如果您尝试这样做ret,则EIP / RIP = argc
=一个小整数,不是有效的地址。如果调试器在地址0x00000001或其他内容上显示错误,这就是原因。)


对于Windows而言,对于ExitProcessLinux而言是系统调用- 对于x86,使用int 80Husing
sys_exit,对于x64而言,使用syscallusing 60exit如果要链接到C库,则从C库进行调用。

32位Linux

mov     eax, sys_exit ; sys_exit = 1
xor     ebx, ebx
int     80H

64位Linux

mov     rax, 60
xor     rdi, rdi
syscall

视窗

push    0
call    ExitProcess

或Windows / Linux链接到C库

call    exit

exit(与原始退出系统调用或libc不同_exit),将首先刷新stdio缓冲区。如果printf从中_start使用exit,则即使退出stdout到文件(使stdout成为全缓冲而不是行缓冲),也要确保退出前已打印所有输出。

通常建议,如果使用libc函数,请编写一个main函数并与gcc链接,以便可以通过常规CRT启动函数调用它ret

定义main为某种东西_start并不会使其变得特别,main如果它不像main由a调用的C
函数_start那样准备在main返回后退出,那么使用标签就令人感到困惑。

2020-06-02