我正在研究一个Forth编译器,JonesForth,它是在GAS中为Linux编写的 . 我的计划是重写它,在MASM32中进行一些小的改动,作为一种方法来提高我对Forth内部机制的理解并重新学习汇编编程(我上次在20世纪80年代早期在6509处理器上使用汇编) .
我对汇编代码本身很好,我想我理解GAS宏实际上做了些什么 . 但我很难将它们转换为MASM宏(可能是因为我在MASM宏上仍然有点粗略) .
这是琼斯写的(我的评论添加在方括号中):
[link ard DOCOL是预先定义的......]
内置词---------------------------------------------- ------------------------
还记得我们的字典条目( Headers )吗?让我们将这些与代码字和数据字结合在一起,看看如何:DOUBLE DUP;真的看起来在记忆中 .
pointer to previous word
^
|
+--|------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+
| LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT |
+---------+---+---+---+---+---+---+---+---+------------+--|---------+------------+------------+
^ len pad codeword |
| V
LINK in next word Points to codeword of DUP
最初我们不能只写“:DOUBLE DUP;” (即那个文字字符串)在这里,因为我们还没有任何东西可以读取字符串,在空格处分解,解析每个单词等等 . 所以我们必须使用GNU定义内置单词汇编程序数据构造函数(如.int,.byte,.string,.ascii等 - 如果您不确定它们,请在GAS信息页面中查找它们) .
漫长的方式是:
.int <link to previous word>
.byte 6 // Length
.ascii "DOUBLE" // String
.byte 0 // Padding
DOUBLE: .int DOCOL // Codeword
.int DUP // Pointer to codeword of DUP
.int PLUS // Pointer to codeword of +
.int EXIT // Pointer to codeword of EXIT
这将变得非常繁琐,所以在这里我定义一个汇编器宏,以便我可以写:
defword "DOUBLE",6,,DOUBLE
.int DUP,PLUS,EXIT
而且我会得到完全相同的效果 .
不要太担心这个宏的确切实现细节 - 这很复杂!
.macro defword name, namelen, flags=0, label
.section .rodata
.align 4
.globl name_\label
name_\label :
.int link // Link
.set link,name_\label
.byte \flags+\namelen // Flags + length byte
.ascii "\name" // The name
.align 4 // Padding to next 4 byte boundary
.globl \label
\label :
.int DOCOL // Codeword - the interpreter
// List of word pointers follow
.endm
同样,我想用一种方法来编写用汇编语言编写的单词 . 开始时会有很多这样的事情,因为,在有足够的“基础设施”能够开始编写Forth单词之前,一切都必须从汇编开始,而且我还想用汇编语言定义一些常见的Forth单词以获得速度,即使我可以在Forth写它们 .
这就是DUP在内存中的样子:
Pointer to previous word
^
|
+--|------+---+---+---+---+------------+
| LINK | 3 | D | U | P | code_DUP ---------------------> Points to the assembly
+---------+---+---+---+---+------------+ code used to write DUP,
^ Len Codeword which ends with NEXT.
|
LINK in next word
同样,为了简化编写头文件,我将编写一个名为defcode的汇编器宏 . 与上面的defword一样,不要担心宏的复杂细节 .
.macro defcode name, namelen, flags=0, label
.section .rodata
.align 4
.globl name_\label
name_\label :
.int link // Link
.set link,name_\label
.byte \flags+\namelen // Flags + length byte
.ascii "\name" // The name
.align 4 // Padding to next 4 byte boundary
.globl \label
\label :
.int code_\label // Codeword
.text
.globl code_\label
code_\label : // Assembler code follows
.endm
[示例...(TCFA,INCR4和EXIT是预定义的地址标签,NEXT是预定义的MACRO)]
defword ">DFA",4,,TDFA
.int TCFA // >CFA (Get code field address)
.int INCR4 // 4+ (Add 4 to it to get to next word)
.int EXIT // EXIT (Return from FORTH word)
defcode "DROP",4,,DROP
pop %eax // Drop top of stack
NEXT