我正在研究一个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