I am in the middle of writting a compiler for a LISP interpreter I wrote a few months ago. My current approach is to generate assembly (nasm) and then compile + link with nasm and gcc. I'm on MacOS.
I'm currently debugging a rather odd segfault error. The snippet in question is pretty clean (for debugging purposes I'm indenting to keep track of the stack):
; Above this point, we do some math and stick the final result into `rax`
; hand written
push rbp
mov rbp, rsp
lea rsi, [0x101]
lea rdi, [rel dbg]
call _printf
mov rsp, rbp
pop rbp
; end hand written
push rax ; push result onto stack
; hand written
push rbp
mov rbp, rsp
lea rsi, [0x102]
lea rdi, [rel dbg]
call _printf
mov rsp, rbp
pop rbp
; end hand written
This particular line of code happens after an operation, the result of which we need to save for a later call (and so we put on the stack). However the output I get from this is:
101
zsh: segmentation fault ./bin
Which means that somehow I am segfaulting between these two printf calls, where there is only one instruction. I'll attach the whole source (which is generated and hard to read, sorry), but I don't mess with rsp
and I am definitely not running out of stack space.
Any thoughts?
(LISP source, in my wierd dialect - I know this code is broken, and should loop forever, but it isn't even getting that far)
(let (REC self n tot) (self self (- n 1) (* n tot)))
(let (fib n) (REC REC n 1))
(fib 5)
My compile step:
nasm my_prog.asm -o my_prog.o -f macho64
gcc my_prog.o -o bin
./bin
(Whole source file)
global _main
extern _printf
extern _fflush
section .text
__init:
ret
_REC:
; START CALL for [rel __local0]
push qword [rel __local0]
push qword [rel __local1]
push qword [rel __local2]
push rbp
mov rbp, rsp
; COMPUTE ARGS for [rel __local0]
mov [rel __local0], rdi
mov [rel __local1], rsi
mov [rel __local2], rdx
; START INLINE for sub
push rcx
; SETUP ARGS for sub (inline)
; MOV ARGS for sub (inline)
mov rax, [rel __local1]
mov rcx, 1
; START BODY for sub (inline)
sub rax, rcx
; RESTORE STATE after sub (inline)
pop rcx
; END INLINE for sub
; hand written
push rbp
mov rbp, rsp
lea rsi, [0x101]
lea rdi, [rel dbg]
call _printf
mov rsp, rbp
pop rbp
; end hand written
push rax ; push result onto stack
; hand written
push rbp
mov rbp, rsp
lea rsi, [0x102]
lea rdi, [rel dbg]
call _printf
mov rsp, rbp
pop rbp
; end hand written
; START INLINE for mul
; SETUP ARGS for mul (inline)
; MOV ARGS for mul (inline)
mov rax, [rel __local1]
mov rcx, [rel __local2]
; hand written
push rbp
mov rbp, rsp
lea rsi, [0x10]
lea rdi, [rel dbg]
call _printf
mov rsp, rbp
pop rbp
; end hand written
; START BODY for mul (inline)
mul rcx
; RESTORE STATE after mul (inline)
; hand written
push rbp
mov rbp, rsp
lea rsi, [rax + 10]
lea rdi, [rel fmt]
call _printf
mov rsp, rbp
pop rbp
; end hand written
; END INLINE for mul
; hand written
push rbp
mov rbp, rsp
mov rsi, rax
lea rdi, [rel fmt]
call _printf
mov rsp, rbp
pop rbp
; end hand written
push rax ; push result onto stack
; POSITION ARGS for [rel __local0]
mov rdi, [rel __local0]
pop r10 ; pop result
mov rsi, r10
pop r10 ; pop result
mov rdx, r10
call [rel __local0] ; make the actual call
mov rsp, rbp
pop rbp
pop qword [rel __local2]
pop qword [rel __local1]
pop qword [rel __local0]
; END CALL for [rel __local0]
ret
_fib:
; START CALL for REC
push qword [rel __local0]
push rbp
mov rbp, rsp
; COMPUTE ARGS for REC
mov [rel __local0], rdi
; POSITION ARGS for REC
lea rdi, [rel _REC]
mov rsi, [rel __local0]
mov rdx, 1
call _REC ; make the actual call
.__cleanup:
mov rsp, rbp
pop rbp
pop qword [rel __local0]
; END CALL for REC
ret
_main:
; call init
push rbp
mov rbp, rsp
call __init
mov rsp, rbp
pop rbp
; START CALL for printf
push rbp
mov rbp, rsp
; COMPUTE ARGS for printf
; START CALL for fib
push rbp
mov rbp, rsp
; COMPUTE ARGS for fib
; POSITION ARGS for fib
mov rdi, 5
call _fib ; make the actual call
mov rsp, rbp
pop rbp
; END CALL for fib
push rax ; push result onto stack
; POSITION ARGS for printf
lea rdi, [rel fmt]
pop r10 ; pop result
mov rsi, r10
call _printf ; make the actual call
mov rsp, rbp
pop rbp
; END CALL for printf
jmp _exit
_exit:
; say bye
push rbp
mov rbp, rsp
mov rdi, 0
call _fflush ; flush stdout
mov rsp, rbp
pop rbp
mov rax, 0x2000006 ; close
mov rdi, 1 ; stdout
syscall
; exit
mov rax, 0x2000001 ; exit
mov rdi, 0
syscall
section .bss
section .data
__local0: dq 0
__local1: dq 0
__local2: dq 0
__local3: dq 0
__local4: dq 0
__local5: dq 0
fmt: db "%d", 10, 0
dbg: db "%x", 10, 0
__exit_msg: db "Exiting now...", 10
.len equ $ - __exit_msg