qrpnxz qrpnxz - 8 months ago 44
Linux Question

Why am I getting a segfault when I `ret'? (FASM)

Through some manipulation I have narrowed it down to a problem with the

op. I know
pushes the return address to the stack; is it illegal to pop it and push it back?

format ELF64 executable 3

entry start

segment readable executable

pop rcx ; argc
mov [argc],cl ; int -> ASCII
add [argc],'0'
push 1 argc 1
call sys_write

mov rdi,0
mov rax,60

sys_write: ; (fd,*buf,count)
pop r11
pop rdx rsi rdi
mov rax,1
push r11

segment readable writable

argc rb 1

Output is:

$ ./prog
1Segmentation fault
$ _


The syscall instruction clobbers the contents of R11 with the RFLAGS register, which means that after making a syscall the value you stored in R11 is overwritten. A solution might be to simply select an appropriate register that goes unmodified by a syscall. According to Intel (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf, page 4-668 Vol. 2B) syscall overwrites RCX, RIP, R11, and RFLAGS as part of its operation, but this leaves plenty of other options (I'd suggest the callee-saved registers such as R8 for consistency even though syscall isn't quite the same as a normal call). Depending on the specific system call you make you may also have to save and restore the stack pointer (RSP).