我试图让JonesForth在开箱即用的最新MacBook上运行,只是使用Mac工具。
我开始将所有内容转换为 64 位并注意 Mac 汇编程序语法。
我有东西要组装,但我立即遇到了一个奇怪的分段错误:
/* NEXT macro. */
.macro NEXT
lodsq
jmpq *(%rax)
.endm
...
/* Assembler entry point. */
.text
.globl start
.balign 16
start:
cld
mov %rsp,var_SZ(%rip) // Save the initial data stack pointer in FORTH variable S0.
mov return_stack_top(%rip),%rbp // Initialise the return stack.
//call set_up_data_segment
mov cold_start(%rip),%rsi // Initialise interpreter.
NEXT // Run interpreter!
.const
cold_start: // High-level code without a codeword.
.quad QUIT
QUIT 通过宏 defword 定义如下:
.macro defword
.const_data
.balign 8
.globl name_$3
name_$3 :
.quad $4 // Link
.byte $2+$1 // Flags + length byte
.ascii $0 // The name
.balign 8 // Padding to next four-byte boundary
.globl $3
$3 :
.quad DOCOL // Codeword - the interpreter
// list of word pointers follow
.endm
// QUIT must not return (ie. must not call EXIT).
defword "QUIT",4,,QUIT,name_TELL
.quad RZ,RSPSTORE // R0 RSP!, clear the return stack
.quad INTERPRET // Interpret the next word
.quad BRANCH,-16 // And loop (indefinitely)
...more code
当我运行这个时,我在 NEXT 宏中第一次出现分段错误:
(lldb) run
There is a running process, kill it and restart?: [Y/n] y
Process 83000 exited with status = 9 (0x00000009)
Process 83042 launched: '/Users/klapauciusisgreat/jonesforth64/jonesforth' (x86_64)
Process 83042 stopped
* thread #1, stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x0000000100000698 jonesforth`start + 24
jonesforth`start:
-> 0x100000698 <+24>: jmpq *(%rax)
0x10000069a <+26>: nopw (%rax,%rax)
jonesforth`code_DROP:
0x1000006a0 <+0>: popq %rax
0x1000006a1 <+1>: lodsq (%rsi), %rax
Target 0: (jonesforth) stopped.
rax 确实指出了我认为是取消引用的地址 DOCOL:
(lldb) register read
General Purpose Registers:
rax = 0x0000000100000660 jonesforth`DOCOL
所以一个谜团是:
- 为什么 RAX 指向 DOCOL 而不是 QUIT?我的猜测是指令执行了一半,间接寻址的结果存储在 rax 中。有哪些好的文档指针?
- 为什么会有分段错误?
我在原始代码中注释掉了调用 brk 以设置数据段的原始段设置代码。另一个[实现]也根本没有调用它,所以我想我也可以忽略它。如何在 Catalina 上的 64 位二进制文件中使用系统调用设置分段权限有什么魔力吗?make命令几乎是标准的JonesForth命令:
jonesforth: jonesforth.S
gcc -nostdlib -g -static $(BUILD_ID_NONE) -o $@ $<
PS:是的,我可以让 JonesForth 在 Docker 镜像中完美运行,但这不是重点。我真的希望它在卡塔琳娜上以 64 位工作,开箱即用。
原始代码有类似的东西
mov $cold_start,%rsi
苹果汇编程序抱怨无法在 32 位二进制文件中使用 64 个即时寻址。
所以我尝试了
mov $cold_start(%rip),%rsi
但这也行不通。
所以我尝试了
mov cold_start(%rip),%rsi
它组装,但当然它会取消引用cold start
,这不是我需要的。
这样做的正确方法显然是
lea cold_start(%rip),%rsi
这似乎按预期工作。