1

我正在编写一个针对 x86_64 的 Lisp 编译器。我目前的目标是实现特殊形式lambda。我最近发现您可以获取标签的地址,将其存储在寄存器中,然后从中调用它:

lea rax, [f + rip]
call rax

凉爽的!这有很大的潜力。但是我在做的测试中遇到了一个错误:

当我给我的编译器这个时,

(define f (lambda (x) (+ x 1)))
(display_num (f 2))

它产生了这个。

    .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

起初这似乎没问题。运行时出现总线错误:

$ make run
./out/test
make: *** [run] Bus error: 10

嗯!诡异的。接下来我通过 LLDB 运行它:

(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

它说它在这里失败了,

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

但我在我的代码中没有看到这样的行。我完全糊涂了。有谁知道这里发生了什么,为什么我会遇到总线错误,以及我需要调整什么才能使我的代码正常工作?我正在使用 Clang 在 MacOS 上进行组装。

4

0 回答 0