_start中RET上的nasm分段错误 [英] Nasm segmentation fault on RET in _start

查看:86
本文介绍了_start中RET上的nasm分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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,Windows或Mac上程序的正确方法! >

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

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


对于Windows,它是ExitProcess,对于Linux,是系统调用- int 80H使用sys_exit(对于x86)或syscall使用60(对于64Bit)或从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链接,以便由普通的CRT启动函数调用,您可以ret进行调用.

main定义为_start的内容并没有什么特别之处,如果它不像_start所调用的C main函数那样,则会混淆使用main标签准备在main返回后退出.

section .text
     global _start
_start:
     nop
main:
     mov eax, 1
     mov ebx, 2
     xor eax, eax
     ret

I compile with these commands:

nasm -f elf main.asm
ld -melf_i386 -o main main.o

When I run the code, Linux throw a segmentation fault error

(I am using Linux Mint Nadia 64 bits). Why this error is produced?

解决方案

Because ret is NOT the proper way to exit a program in Linux, Windows, or Mac!!!!

_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).

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.)


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 bit Linux

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

64 bit Linux

mov     rax, 60
xor     rdi, rdi
syscall

Windows

push    0
call    ExitProcess


Or Windows/Linux linking against the C Library

call    exit

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).

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.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆