colorful rat Ratfactor.com > Dave's Repos

nasmjf

A NASM assembler port of JONESFORTH
git clone http://ratfactor.com/repos/nasmjf/nasmjf.git

nasmjf/devlog/log11.txt

Download raw file: devlog/log11.txt

1 I find it hard to believe that I've discovered a 2 bug in JonesFORTH, but it seems to me that my fix 3 of simply removing FETCH from colon so that the 4 word header that receives the HIDDEN flag is the 5 one being compiled, not the previous one in the 6 linked list (dictionary). 7 8 !!!!!!!!!!!!!!!!!!!! Update !!!!!!!!!!!!!!!!!!!! 9 ! In log19.txt, I realize that my variable ! 10 ! handling is wrong. Variables should leave ! 11 ! their addresses on the stack, not their ! 12 ! values! We need FETCH to get the value from ! 13 ! the address! ! 14 !!!!!!!!!!!!!!!!!!!! Update !!!!!!!!!!!!!!!!!!!! 15 16 17 So unless I discover otherwise, I've changed it 18 from 19 20 21 dd LATEST, FETCH, HIDDEN ; Make the word hidden while it's being compiled. 22 23 to 24 25 dd LATEST, HIDDEN ; Make the word hidden while it's being compiled. 26 27 (gdb) break code_LATEST 28 Breakpoint 2 at 0x804939d: file nasmjf.asm, line 772. 29 (gdb) c 30 Continuing. 31 : FIVE 5 ; 32 33 Breakpoint 2, code_LATEST () at nasmjf.asm:772 34 772 push dword [var_%4] 35 27 lodsd ; NEXT: Load from memory into eax, inc esi to point to next word. 36 28 jmp [eax] ; Jump to whatever code we're now pointing at. 37 code_HIDDEN () at nasmjf.asm:636 38 636 pop edi ; Dictionary entry, first byte is link 39 637 add edi, 4 ; Move to name/flags byte. 40 41 If my fix works, then the word "FIVE" that is being compiled 42 will be the one we're hiding until compilation is complete: 43 44 (gdb) x/bx $edi 45 0x804e004: 0x04 46 (gdb) x/bt $edi 47 0x804e004: 00000100 48 (gdb) x/4c $edi+1 49 0x804e005: 70 'F' 73 'I' 86 'V' 69 'E' 50 51 Yup, looks good! And the hidden flag? 52 53 638 xor [edi], word F_HIDDEN ; Toggle the HIDDEN bit in place. 54 (gdb) x/bt $edi 55 0x804e004: 00100100 56 57 Looks good also. 58 59 Next, let's implement BRANCH! 60 Turns out, it's another crazy simple "hack" with 61 the esi register (like LIT), this time, adding an 62 offset to esi itself to change which word NEXT 63 should execute next. 64 65 (gdb) break code_BRANCH 66 Breakpoint 2 at 0x804904e: file nasmjf.asm, line 237. 67 (gdb) c 68 Continuing. 69 : FIVE 5 ; 70 71 Breakpoint 2, code_BRANCH () at nasmjf.asm:237 72 237 add esi, [esi] ; add the offset to the instruction pointer 73 74 The line above is the entirety of BRANCH! 75 So before that line executes, esi should point 76 to the next "word" in the definition of QUIT, which 77 is actually not a word at all, but an offset to 78 add to the current value of esi itself. 79 80 So we should see QUIT + <some offset> in esi 81 82 (gdb) info sym $esi 83 QUIT + 20 in section .data of /home/dave/nasmjf/nasmjf 84 85 And the value at esi should be our negative offset, -8. 86 87 (gdb) p *$esi 88 $2 = -8 89 90 What will -8 branch to? Here's the entire definition 91 of QUIT: 92 93 DEFWORD "QUIT",4,0,QUIT 94 dd R0 ; push R0 (addr of top of return stack) 95 dd RSPSTORE ; store R0 in return stack pointer (ebp) 96 dd INTERPRET ; interpret the next word 97 dd BRANCH,-8 ; and loop (indefinitely) 98 99 esi was pointing at the "double" (4 bytes) containing 100 the value -8. Every word linked here is also 4 bytes. 101 102 esi points to -8 (QUIT + 20) 103 esi-4 points to BRANCH (QUIT + 16) 104 esi-8 points to INTERPRET (QUIT + 12) 105 106 So BRANCH here makes a conditionless loop over INTERPRET. 107 108 (gdb) info sym $esi 109 QUIT + 12 in section .data of /home/dave/nasmjf/nasmjf 110 27 lodsd ; NEXT: Load from memory into eax, inc esi to point to next word. 111 28 jmp [eax] ; Jump to whatever code we're now pointing at. 112 code_INTERPRET () at nasmjf.asm:244 113 244 call _WORD ; Returns %ecx = length, %edi = pointer to word. 114 115 This is getting exciting. So we shoud be able to compile 116 a word and then execute it. Let's see if my "FIVE" literal 117 works: 118 119 (gdb) c 120 Continuing. 121 FIVE 122 PARSE ERROR: FIVE 123 124 Oh no! It didn't find FIVE. So something in the 125 compilation of ": FIVE 5 ;" isn't quite right yet. 126 127 Wait a dang second. 128 129 I've removed the FETCH so it's no longer setting the 130 wrong word header to hidden during compilation. But 131 I didn't make the same change in SEMICOLON (;) to 132 unhide the correct word! 133 134 dd LATEST, FETCH, HIDDEN ; Unhide word now that it's been compiled. 135 136 Removing the FETCH so we have 137 138 dd LATEST, HIDDEN ; Unhide word now that it's been compiled. 139 140 and let's see what happens. 141 142 (gdb) break code_INTERPRET 143 Breakpoint 2, code_INTERPRET () at nasmjf.asm:244 144 (gdb) c 145 Continuing. 146 : FIVE 5 ; 147 148 Breakpoint 2, code_INTERPRET () at nasmjf.asm:244 149 (gdb) c 150 Continuing. 151 FIVE 152 153 Breakpoint 2, code_INTERPRET () at nasmjf.asm:244 154 (gdb) p/x $esp 155 $3 = 0xbffff98c 156 (gdb) x/x $esp 157 0xbffff98c: 0x00000005 158 159 Using my compiled word FIVE put a 5 on the stack! 160 It works! 161 162 I think I've earned a bit of fun, so the next thing 163 I'll implement is EMIT, which will let me actually 164 display characters on the screen!