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位)。为什么会产生此错误?
因为ret是 不是 要退出的Linux,Windows或苹果机的程序的正确方法!!!!
ret
_start 不是函数,因为没有要返回的用户空间调用程序, 所以堆栈上没有返回地址 。用户空间中的执行在进程入口点从此处开始(在静态可执行文件中)。(或者使用动态链接,它在动态链接器完成后跳到此处,但结果相同)。
_start
在Linux / OS X上,堆栈指针指向指向的argc入口_start(有关进程启动环境的更多详细信息,请参见i386或x86-64 System V ABI文档);内核在启动用户空间之前将命令行参数args放入用户空间堆栈内存中。(因此,如果您尝试这样做ret,则EIP / RIP = argc =一个小整数,不是有效的地址。如果调试器在地址0x00000001或其他内容上显示错误,这就是原因。)
argc
0x00000001
对于Windows而言,对于ExitProcessLinux而言是系统调用- 对于x86,使用int 80Husing sys_exit,对于x64而言,使用syscallusing 60;exit如果要链接到C库,则从C库进行调用。
ExitProcess
int 80H
sys_exit
syscall
60
exit
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成为全缓冲而不是行缓冲),也要确保退出前已打印所有输出。
_exit
printf
通常建议,如果使用libc函数,请编写一个main函数并与gcc链接,以便可以通过常规CRT启动函数调用它ret。
main
定义main为某种东西_start并不会使其变得特别,main如果它不像main由a调用的C 函数_start那样准备在main返回后退出,那么使用标签就令人感到困惑。