I am writing a Lisp compiler that targets x86_64. My current goal is to implement the special form lambda
. I recently discovered that you can take the address of a label, store it in a register, and call it from that:
lea rax, [f + rip]
call rax
Cool! That has a lot of potential. But I am getting an error in a test I did:
When I give my compiler this,
(define f (lambda (x) (+ x 1)))
(display_num (f 2))
it yields this.
.global _main
.text
_main:
call _begin_gc
and rsp, -16
jmp after_lambda_1
lambda_1:
push rbp
mov rbp, rsp
push 1 # push argument to +
push [rbp + 16] # push argument to +
call plus
add rsp, 16 # discard 2 local arguments
mov rbp, rsp
pop rbp
ret
after_lambda_1:
lea rax, [lambda_1 + rip]
mov [f + rip], rax
push 2 # push argument to f
call f
add rsp, 8 # discard 1 local argument
push rax # result of f
call display_num
add rsp, 8 # discard 1 local argument
and rsp, -16
call _end_gc
xor rdi, rdi
mov rax, 0x2000001
syscall
.data
f:
.quad 0
That seemed okay at first. I got a bus error when running it though:
$ make run
./out/test
make: *** [run] Bus error: 10
Hm! weird. I ran it through LLDB next:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x100008050)
* frame #0: 0x0000000100008050 test`f
frame #1: 0x0000000100003d9c test`after_lambda_1 + 21
frame #2: 0x0000000100003d67 test`main + 5
frame #3: 0x00007fff72c13cc9 libdyld.dylib`start + 1
frame #4: 0x00007fff72c13cc9 libdyld.dylib`start + 1
It says that it failed here,
test`f:
-> 0x100008050 <+0>: jo 0x10000808f ; gc + 55
0x100008052 <+2>: add byte ptr [rax], al
0x100008054 <+4>: add dword ptr [rax], eax
0x100008056 <+6>: add byte ptr [rax], al
but I don't see a line that looks like that in my code. I am utterly confused. Does anyone know what is happening here, why I am getting a bus error, and what I need to tweak to make my code functional? I am assembling on MacOS with Clang.