/* proof of concept code... pure subroutine-threaded forth */ .equ cellsize, 4 /* this type of forth doesn't use docol, next, nor unnest */ .macro datastack xchg %esi,%esp .endm .macro callstack xchg %esi,%esp .endm .macro poparg lodsl .endm .macro pusharg /* slow, avoid it */ subl $cellsize,%esi movl %eax,(%esi) .endm plus: /* + */ poparg addl %eax,(%esi) ret lit: /* get next number out of instruction stream */ datastack movl (%esi),%eax addl $cellsize,(%esi) pushl (%eax) callstack ret divide: /* / */ datastack popl %ebx popl %eax clrl %edx divl %ebx pushl %eax callstack ret /* ok, so here we go, the data stack has on it a 4 and an 8, (presumably put there during coldstart from argv) and ave is called from coldstart. since it's been called, the return stack (the actual machine stack of the x86) has on it the pointer to the end of the coldstart routine, which would probably be a 'RET' to the operating system (yes, that works with windows xp, and eax will go into errorlevel). subroutine-threading doesn't distinguish betweena highlevel and lowlevel words, and only needs a separate data stack, for which we use %esi. this register was chosen because it can be accessed two ways, as a stack by xchg with %esp, and also by using the lods instruction for an easy pop into the accumulator. */ nop: ret ave: call nop /* getting rid of this makes program 8% SLOWER! */ call plus call lit .long 2 call divide ret cold: movl $data,%esi /* for speed comparisons, enable this following line (and below) */ mov $REPS,%ecx /* repeat count */ 10: datastack pushl $4 pushl $8 callstack call ave poparg /* for speed comparisons, enable this following line (and above) */ loop 10b .ifeq OS-1 mov %eax,%ebx mov $1,%eax /* Unix exit call */ int $0x80 .else ret .endif .bss .skip 1024, 0 /* make sure at least this much data stack space */ data: .ifeq OS-2 imagebase = 0x400000 /* surely there's a better way? */ .section .idata /* w2k seems to require a valid import descriptor whether you want one or not... XP doesn't seem to care */ .long 0, 0, 0, 1f-imagebase, 2f-imagebase .long 0, 0, 0, 0, 0 /* null array ends table */ 1: .asciz "KERNEL32.DLL" 2: .long 3f-imagebase, 0 3: .word 0 .asciz "ExitProcess" .endif .global _mainCRTStartup, _start .equ _mainCRTStartup, cold /* for windows */ .equ _start, cold /* for linux */