1

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.

Caspian Ahlberg
  • 934
  • 10
  • 19
  • 1
    You've stored the address of `lambda_1` at `f`. But then you try to `call f`, which results in it transferring control to address `f` and trying to execute the address of `lambda_1` as if it were code. If you want to fetch the address from `f` and transfer control there, i.e. an indirect call, do `call [f]`. – Nate Eldredge Nov 06 '20 at 00:01
  • But I don't understand why you are using `f` at all. Why not simply `lea rax, [lambda_1 + rip]` ; `push 2` and then `call rax`? – Nate Eldredge Nov 06 '20 at 00:02
  • @NateEldredge I was doing this because, in the Lisp code above, I was assigning the lambda expression to the name `f`. It could be terser, but I was simply naming a function above. – Caspian Ahlberg Nov 06 '20 at 01:23
  • 1
    Lisp is a dynamic language. Turning Lisp symbols into labels for fixed amounts of *static* storage isn't going to be viable in the general case, if you ever want to implement `eval`. But I guess for the subset of Lisp that can be easily ahead-of-time compiled, you could inefficiently do that instead of just remembering how `f` was defined calling that static function definition directly, like `call lamba_1`. (@NateEldredge: If you were going to optimize away `f`, you'd also optimize away the function pointer entirely and make a direct `call`, instead of using a register-indirect) – Peter Cordes Nov 06 '20 at 03:15
  • @PeterCordes: Sure. I was imagining that in general, the `lea` might be replaced by a more elaborate runtime lookup or computation to retrieve the address. But if this lookup ends up with the address in a register then there is no need to store it into memory. – Nate Eldredge Nov 06 '20 at 04:05
  • 1
    @NateEldredge: Oh right, I see `lea rax, [lambda_1 + rip]` was already there in the code. Yeah that suggestion makes more sense in that light. So RAX is `f`, instead of using static storage for it, but `f` still exists. – Peter Cordes Nov 06 '20 at 04:07

0 Answers0