Nasm segmentation fault on RET in _start
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 64-bit or a call to exit
from the C Library if you are linking to it.
32-bit Linux (i386)
%define SYS_exit 1 ; call number __NR_exit from <asm/unistd_32.h>
mov eax, SYS_exit ; use the NASM macro we defined earlier
xor ebx, ebx ; ebx = 0 exit status
int 80H ; _exit(0)
64-bit Linux (amd64)
mov rax, 60 ; SYS_exit aka __NR_exit from asm/unistd_64.h
xor rdi, rdi ; edi = 0 first arg to 64-bit system calls
syscall ; _exit(0)
(In GAS you can actually #include <sys/syscall.h>
or <asm/unistd.h>
to get the right numbers for the mode you're assembling a .S
for, but NASM can't easily use the C preprocessor.
See Polygot include file for nasm/yasm and C for hints.)
32-bit Windows (x86)
push 0
call ExitProcess
Or Windows/Linux linking against the C Library
; pass an int exit_status as appropriate for the calling convention
; push 0 / xor edi,edi / xor ecx,ecx
call exit
(Or for 32-bit x86 Windows, call _exit
, because C names get prepended with an underscore, unlike in x86-64 Windows. The POSIX _exit
function would be call __exit
, if Windows had one.)
Windows x64's calling convention includes shadow space which the caller has to reserve, but exit
isn't going to return so it's ok to let it step on that space above its return address. Also, 16-byte stack alignment is required by the calling convention before call exit
except for 32-bit Windows, but often won't actually crash for a simple function like exit()
.
call 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.
See also
- Syscall implementation of exit()
- How come _exit(0) (exiting by syscall) prevents me from receiving any stdout content?
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.
How to solve segmentation fault of certain instructions of assembly code?
I think probably this question is a duplicate, but anyway, there is one problem in your code.
.global _start
.text
_start:
call _sum
subq $0x8, %rsp
popq %rax
ret # <-- return to where?
_sum:
ret
A main
in C has to can return because _start
eventually calls main
, but here, you are writing _start
directly. It returns to nowhere if you put a ret
.
In place of ret
, put this instead.
movl $60, %eax # syscall number for sys_exit
movl $0, %edi # or whatever value you want your process
# to return with from 0 to 255;
# xor %edi, %edi is usually better if you want 0
syscall
Leave a comment if it still crashes.
BTW, I was assuming your platform is Linux (because of the AT&T syntax..). The syscalls can be different for a different platform.
I am getting segmentation fault - assembly
Two bugs:
; moving length
mov ecx, eax
; moving syscall num and out desc
mov eax, 4
mov ebx, [stdout]
; syscall
int 0x80
Referring to Linux system call conventions, the write
system call needs the buffer pointer in ecx
and the length in edx
. You have the length in ecx
and the buffer pointer is nowhere at all. Make it:
mov edx, eax
mov ecx, dword [ebp+8]
mov eax, 4
mov ebx, [stdout]
int 0x80
Next, look at:
cmp [ebx+eax], byte 0x00
inc eax
jne loop1
The inc
instruction sets the zero flag according to its output. So your jne
doesn't branch on the result of the cmp
, but rather on whether eax
was incremented to zero (i.e. wrapped around). So your loop will iterate far too many times.
The jne
needs to be immediately after the cmp
, with no other flag-modifying instructions in between. There are several ways you could rewrite. One would be:
mov eax, -1
loop1:
inc eax
cmp byte [ebx+eax], 0x00
jne loop1
Note this eliminates the need for the extra dec eax
at the end.
After fixing these, the program works for me.
Related Topics
How to Change the Root Directory of an Apache Server
Nasm Segmentation Fault on Ret in _Start
Use Sudo With Password as Parameter
How to Open a New Tab in Gnome Terminal from Command Line
What Is the Maximum Size of a Linux Environment Variable Value
Free Git Server With Web Gui a La Bitbucket/Github
How to Count Lines in a Document
How to Get the Process Id to Kill a Nohup Process
What Killed My Process and Why
How to Recursively Grep All Directories and Subdirectories
Is There Any API For Determining the Physical Address from Virtual Address in Linux
Split One File into Multiple Files Based on Delimiter
How to Get Cmake to Find My Alternative Boost Installation
The Bash Command :(){ :|:& };: Will Spawn Processes to Kernel Death. Can You Explain the Syntax
Linux Command to Print Directory Structure in the Form of a Tree