snapshot (not working)
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Mon, 17 May 2021 23:29:33 +0000 (09:29 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Mon, 17 May 2021 23:29:33 +0000 (09:29 +1000)
Makefile
machine.fasm
main.fasm
math.fasm [new file with mode: 0644]
memory.fasm [new file with mode: 0644]
stack.fasm [new file with mode: 0644]
stdio.fasm [new file with mode: 0644]
symbols.lsp [new file with mode: 0755]
syscalls.fasm [new file with mode: 0644]
wordlists.fasm [new file with mode: 0644]

index 1e629b944805f77bbfc05ffac20ea21f2b3e7819..2a4d3bbbe7fe92c7b9089e3e50a27f35fe528474 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,24 @@
 BINARY = rrqforth
 
 BINARY = rrqforth
 
-default: rrqforth
+default: X
 
 VFMT := "RRQ Forth version %h at %aI"
 VERSION := $(shell git log -1 --pretty=format:'$(VFMT)' main.fasm)
 
 
 VFMT := "RRQ Forth version %h at %aI"
 VERSION := $(shell git log -1 --pretty=format:'$(VFMT)' main.fasm)
 
-main.fasm: machine.fasm stdio.fasm
+main.fasm: machine.fasm readline.fasm syscalls.fasm
 
 version: main.fasm
        @echo "db '$(VERSION)'\ndb 10" > $@
 
 
 version: main.fasm
        @echo "db '$(VERSION)'\ndb 10" > $@
 
-rrqforth: main.fasm | version
+rrqforth: main.fasm | 
        fasm $^ $@
        chmod a+x $@
 
        fasm $^ $@
        chmod a+x $@
 
+rrqforth.fas: main.fasm rrqforth
+       fasm $< -s $@
+
+X: rrqforth.fas
+       ./symbols.lsp $< > $@
+
 clean:
 clean:
-       rm -f version rrqforth
+       rm -f version rrqforth rrqforth.fas
index 92f51a1f3433d103ee650eab2c2ef48273f13f32..ddfb9711fe18abd89b514d3ccffd2989a18140c8 100644 (file)
 ;;;
 ;;; function calling
 
 ;;;
 ;;; function calling
 
-;;; FORTH model
-;;; rsp = data stack pointer
-;;; rbp = frame pointer
-;;; rdi = frame stack
-;;; rsi = instruction pointer
 
 
-;;; ========================================
-;;; The next macro "moves" execution to the next FORTH instruction,
-;;; using rsi as instruction pointer.
-
-       macro next {
-       lodsq                   ; mov rax, qword [rsi]
-                               ; add rsi,8
-       jmp qword [rax]         ; goto code of that FORTH word
-       }
-
-;;; ========================================
-;;; The pushr macro pushes x onto the return stack
-;;; The popr macro pops x from the return stack
-       macro pushr x {
-       sub rbp, 8
-       mov qword [rbp], x
-       }
-
-       macro popr x {
-       mov x, [rbp]
-       add rbp, 8
-       }
-
-;;; ========================================
-;;; 
-
-       previous_word = 0
-
-       ;; Macro WORD starts a FORTH word definition in this code
-       macro WORD label, name, doer, flags {
-label#_tfa:
-       ;; TFA
-       dq previous_word
-       ;; PFA
-label#_word:
-       previous_word = label#_word
-       db flags + 0
-       db label - $ - 1
-       db name
-       ;; CFA = pointer to "interpreter"
-label:
-       dq doer
-       }
-
-       ;; Macro WORD_assembler begins an assembler implementation
-       macro WORD_assembler label, name, flags {
-       WORD label, name, label#_code, flags
-label#_code:
-       }
index 25e48b4f69a9aa1daf2561f2a24230d3f848a771..f06c158bd5a9879f64f804185a7292861a307d38 100644 (file)
--- a/main.fasm
+++ b/main.fasm
-; This is a forth interpreter
+; This is a forth interpreter for x86_64 (elf64)
        format elf64 executable
        format elf64 executable
-       entry main_code
+       entry main
+
+;;; ========================================
+;;; The pushr macro pushes x onto the return stack
+;;; The popr macro pops x from the return stack
+macro pushr x {
+       sub rbp, 8
+       mov [rbp], x
+}
+
+macro popr x {
+       mov x, [rbp]
+       add rbp, 8
+}
+
+;;; ========================================
+;;; The next macro "moves" execution to the next FORTH instruction,
+;;; using rsi as instruction pointer. It points to the doer field of a
+;;; word, which points to the assembly code that implements the
+;;; execution effect of the word. That doer code is entered with rsi
+;;; referring to the subsequent address in the colling word, and rax
+;;; referring to the doer field of the called word.
+
+macro next {
+       lodsq                   ; mov rax, [rsi] + add rsi,8
+       jmp qword [rax]         ; goto code of that FORTH word (64 bit jump)
+}
+
+;;; ========================================
+;;; The FORTH macro transitions to inline FORTH execution.
+macro FORTH {
+       local forthcode
+       mov rsi,forthcode
+       next
+       ;; align 8
+forthcode:
+}
+
+;;; ========================================
+;;; The ENDFORTH macro transitions back to inline assembler after FORTH
+;;; ========================================
+macro ENDFORTH {
+       dq inline_code
+}
+
+;;; ========================================
+;;; The DOFORTH lays out a single FORTH call
+;;; ========================================
+macro DOFORTH label {
+       FORTH
+       dq label
+       ENDFORTH
+}
+
+;;; Macro WORD starts a FORTH word definition in this code
+;;; 
+       previous_word = 0       ; Used for chaining the words
+
+       IMMEDIATE = 1           ; optional flag
+
+macro WORD label, name, doer, flags {
+       ;; align 8
+label#_TFA:
+       ;; TFA
+       dq previous_word
+       previous_word = label#_TFA
+       ;; PFA
+label#_PFA:
+       db flags + 0
+       db label - $ - 2
+       db name
+       db 0
+       ;; align 8
+
+label#_OFF:
+       dq 0                    ; The DOES offset. Defaults to 0.
+       ;; also CFA = pointer to "doer"
+label:
+       if doer eq
+           dq doforth
+       else
+           if doer in <fasm>
+               dq label#_DFA
+           else
+               dq doer
+           end if
+       end if
+       ;; DFA
+label#_DFA:
+}
+
+;;; ============================================================
+;;; FORTH machine model
+;;; rsp = data stack pointer
+;;; rbp = return stack pointer
+;;; rsi = instruction pointer
+
+;;; ============================================================
 
 
-;;; ############################################################
-;;; The FORTH words
        segment readable writable executable
 
        segment readable writable executable
 
-include 'machine.fasm'
-       
-       ;; PROGRAM_VERSION is the program version string
-       WORD program_version, 'PROGRAM_VERSION', marker
-       db length
-program_version_string:        
-       include 'version'
-       length = $ - program_version_string
+       WORD return_stack,'RS',dovariable
+       ;; The return stack
+       rb 1048576              ; 1 Mb return stack
+RS_TOP:                                ; The initial rbp
        
        
-       ;; MAIN is the program entry point
-       ;; ( -- )
-       WORD_assembler main, "MAIN"
-       mov rsi,program_version_string ; address of string
-       mov edx,length          ; length of string (cheating)
-       mov edi,1               ; stdout
-       mov eax,1               ; sys_write
-       syscall
-       jmp terminate0_code
+       WORD data_stack,'DS',dovariable
+       ;; The data stack
+       rb 1048576              ; 1 Mb data stack
+DS_TOP:                                ; The initial rsp
 
 
-       ;; TERMINATE0 terminates the program with code 0
+       WORD inline_code,'[ASM]',fasm
        ;; ( -- )
        ;; ( -- )
-       WORD_assembler terminate0, 'TERMINATE0'
-       xor edi,edi
-       mov eax,60
-       syscall
+       ;; This transitions execution into inline assembler in the
+       ;; calling word defintion. Note that it stops advancing rsi;
+       ;; code should use FORTH macro to reenter forth execution, or
+       ;; exit to the calling definition via "jmp exit".
+       jmp qword rsi
 
 
-       ;; EXIT ends a forth code defintion, returning to caller
-       ;; ( -- )
-       WORD_assembler exit, 'EXIT'
+;;; Execution semantics for FORTH defition word
+;;; At entry, rsi points into the calling definition, at the cell
+;;; following the cell indicating this word, rax points to the CFA of
+;;; this word.
+doforth:
+       pushr rsi
+       lea rsi, [rax+8]        ; rsi = the DFA of the rax word
+       next
+
+       WORD p_exit, 'EXIT',fasm
+       ;; ( -- ) ( R: addr -- )
+       ;; Returns execution to the calling definition as per the
+       ;; return stack.
+exit:
        popr rsi
        next
        popr rsi
        next
-       
-       ;; MARKER is a word that pushes the address after itself, then exits
-       ;; ( -- p )
-       WORD_assembler marker, 'MARKER'
-       push qword rsi
-       jmp exit_code
-
-       ;; MARKER@ is a word that pushes a the value after itself, then exits
-       ;; ( -- v )
-       WORD_assembler marker_get, 'MARKER@'
-       push qword [rsi]
-       jmp exit_code
-
-       ;; DOFORTH begins a FORTH defintion
-       WORD_assembler doforth, 'DOFORTH'
-       pushr rsi
-       lea rsi, [rax + 8]
+
+       ;; Execution semantics for a variable ( -- addr )
+       ;; rax points to doer field
+dovariable:
+       push rax+16
+       next
+
+       ;; Execution semantics for a constant ( -- v )
+       ;; rax points to doer field
+dovalue:
+       push qword [rax+16]
        next
 
        next
 
-       ;; LIT is a word that pushes a the value after itself, then continues
-       ;; ( -- v )
-       WORD_assembler lit, 'LIT'
-       push qword [rsi]
-       add rsi, 8
+       ;; Execution semantics for a string constant ( -- addr n )
+       ;; rax points to doer field
+dostring:
+       add rax,16
+       mov bl,[rax]
+       mov byte [rsp],bl
+       push rax+1
        next
 
        next
 
-       ;; HERE is a variable pointing to the free heap
-       WORD here, 'HERE', marker
-       dq heap_start           ; initialise to first "free" data
+include 'wordlists.fasm'
+include 'syscalls.fasm'
+include 'memory.fasm'
+include 'stack.fasm'
+include 'math.fasm'
+include 'stdio.fasm'
 
 
-       ;; WORDS is the list of words
-       WORD words, 'WORDS', marker
-       dq forth_tfa            ; initialise to last forth word
+       WORD p_program_version,'PROGRAM_VERSION',dostring
+       db length
+program_version_string:        
+       db 'RRQ Forth version 0.1 - 2021-05-13',10
+       length = $ - program_version_string
 
 
-       ;; FORTH is the last word of the VOCABULARY 
-       WORD forth, 'FORTH', marker_get
-       dq forth_tfa
+       WORD p_stdin,'STDIN',dovalue
+       ;; Initialised to hold a STREAM for fd 0
+       dq 0
        
        
-heap_start:
+       WORD p_quit,'QUIT',fasm
+       ;; QUIT is the program entry point ********************
+main:
+       mov rsp,DS_TOP
+       mov rbp,RS_TOP
+       ;; Initialize STREAM STDIN
+       push 0
+       push 10000
+       DOFORTH p_stream
+       pop qword [p_stdin_DFA]
+
+       ;; read a word
+       push qword 1            ; ( fd ) =stdout
+       push qword [p_stdin_DFA]
+       FORTH
+       dq p_read_word          ; ( fd s n )
+       dq sys_write
+       ENDFORTH
+
+       push qword 1                    ; stdout
+       push qword program_version_string ; address of string
+       push qword length               ; length of string (cheating)
+       DOFORTH sys_write               ; printout
+       pop rax                         ; ignore errors
+       
+       push 0
+       DOFORTH sys_exit
 
 
+       ;; TERMINATE0 terminates the program with code 0
+       ;; ( v -- )
+       WORD terminate, 'TERMINATE',fasm
+       pop rdx
+terminate_special:
+       mov eax,60
+       syscall
+
+last_word:
+       ;; FORTH is the last word of VOCABULARY FORTH
+       WORD forth,'FORTH',dovalue
+       dq forth_TFA
+       dq 0
+
+       
+heap_start:
diff --git a/math.fasm b/math.fasm
new file mode 100644 (file)
index 0000000..d25d14c
--- /dev/null
+++ b/math.fasm
@@ -0,0 +1,59 @@
+;;; Words doing arithmetics
+       
+       WORD p_plus, '+',fasm
+       ;; ( n1 n2 -- n3 )
+       ;; n3 is the sum of n1 and n2
+       pop rax
+       add [rsp],rax
+       next
+
+       WORD p_minus, '-',fasm
+       ;; ( n1 n2 -- n3 )
+       ;; n3 is the result of subtracting n2 from n1
+       pop rax
+       sub [rsp], rax
+       next
+
+       WORD p_mult, '*',fasm
+       ;; ( n1 n2 -- n3 )
+       ;; Multiply n1 by n2 giving the product n3.
+       ;; [rsp{8}] * [rsp+8{8}]
+       ;; dd00 = [rsp+4{4}]*[rsp+12{4}] ignored
+       ;; needs checking !!
+       ;; 
+       ;; 0cc0 = [rsp{4}]*[rsp+12{4}]
+       mov eax, dword [rsp]
+       imul dword [rsp+12]
+       mov ebx,eax
+       ;; 0bb0 = [rsp+4{4}]*[rsp+8{4}]
+       mov eax, dword [rsp+4]
+       imul dword [rsp+8]
+       add ebx, eax
+       ;; 00aa = [rsp{4}]*[rsp+8{4}]
+       mov eax, dword [rsp]
+       imul dword [rsp+8]
+       add ebx, edx
+       shl rbx,32
+       mov eax,eax             ; ensure zero-extending eax
+       add rax, rbx
+       push rax
+       next
+
+       WORD p_abs, 'ABS',fasm
+       ;; ( n -- u )
+       ;; u is the absolute value of n.
+       cmp qword [rsp],0
+       jge p_abs_end
+       neg qword [rsp]
+p_abs_end:
+       next
+
+       WORD p_negate, 'NEGATE',fasm
+       ;; ( n1 -- n2 )
+       ;; Negate n1, giving its arithmetic inverse n2. 
+       xor rax,rax
+       sub rax,qword [rsp]
+       mov qword [rsp],rax
+       next
+
+       
diff --git a/memory.fasm b/memory.fasm
new file mode 100644 (file)
index 0000000..8a7ec6e
--- /dev/null
@@ -0,0 +1,109 @@
+;;; This file defines "memory access words"
+
+       WORD p_get, '@',fasm
+       ;; ( addr -- v )
+       ;; Load value v from address addr
+       pop rax
+       push qword [rax]
+       next
+
+       WORD p_put, '!',fasm
+       ;; ( v addr -- )
+       ;; Store value v at address addr.
+       pop rax
+       pop rbx
+       mov qword [rax], rbx
+       next
+
+       WORD p_Cget, 'C@',fasm
+       ;; ( addr -- v )
+       ;; Load the (unsigned) byte v from address addr.
+       pop rax
+       mov bl,[rax]
+       push 0
+       mov [rsp],bl
+       next
+       
+       WORD p_Cput, 'C!',fasm
+       ;; ( v addr -- )
+       ;; Store byte value v at address addr.
+       pop rax
+       pop rbx
+       mov byte [rax], bl
+       next
+
+       WORD p_2get, '2@',fasm
+       ;; ( addr -- v1 v2 )
+       ;; Load the cell pair {x2,x1} from address addr.
+       pop rax
+       push qword [rax+8]
+       push qword [rax]
+       next
+
+       WORD p_2put, '!',fasm
+       ;; ( v1 v2 addr -- )
+       ;; Store value pair {v2,v1} at address addr.
+       pop rax
+       pop rbx
+       mov qword [rax], rbx
+       pop rbx
+       mov qword [rax+8], rbx
+       next
+
+       WORD p_erase, 'ERASE',fasm
+       ;; ( addr u -- )
+       ;; Clear u bytes at address addr and up.
+       pop rax
+       pop rbx
+       xor rcx,rcx
+p_erase_loop:
+       cmp rax,8
+       jl p_erase_last
+       mov qword [rbx],0       ; mov qword[rbx],rcx
+       add rbx,8
+       sub rax,8
+       jmp p_erase_loop
+p_erase_more:
+       mov [rbx],byte 0        ; mov byte [rbx], cl
+       inc rbx
+       dec rax
+p_erase_last:
+       jg p_erase_more
+       next
+
+       WORD p_1plus, '1+',fasm
+       ;; ( n1 -- n2 )
+       ;; Add one (1) to n1 resulting in n2.
+       inc qword [rsp]
+       next
+
+       WORD p_plus_put, '+!',fasm
+       ;; ( n addr -- )
+       ;; Add n to the value at addr.
+       pop rax
+       pop rbx
+       add [rax],rbx
+       next
+
+       WORD p_1minus, '1-',fasm
+       ;; ( n1 -- n2 )
+       ;; Subtract one (1) from n1 resulting in n2. 
+       dec qword [rsp]
+       next
+
+       WORD p_2mult, '2*',fasm
+       ;; ( x1 -- x2 )
+       ;; x2 is the result of shifting x1 one bit toward the
+       ;; most-significant bit, filling the vacated least-significant
+       ;; bit with zero.
+       shl qword [rsp],1
+       next
+
+       WORD p_2div, '2/',fasm
+       ;; ( x1 -- x2 )
+       ;; x2 is the result of shifting x1 one bit toward the
+       ;; least-significant bit, leaving the most-significant bit
+       ;; unchanged. (signed right shift)
+       sar qword [rsp],1
+       next
+       
diff --git a/stack.fasm b/stack.fasm
new file mode 100644 (file)
index 0000000..9726cc2
--- /dev/null
@@ -0,0 +1,121 @@
+;;; Words for stack manipulations
+       
+       WORD p_dup, 'DUP',fasm
+       ;; ( v -- v v )
+       ;; Duplicate top ov stack value.
+       ;; push qword [rsp] ??
+       mov rax,qword [rsp]
+       push rax
+       next
+
+       WORD p_2dup, '2DUP',fasm
+       ;; ( x1 x2 -- x1 x2 x1 x2 )
+       ;; Duplicate cell pair x1 x2.
+       push qword [rsp+8]
+       push qword [rsp+8]
+       next
+
+       WORD p_drop, 'DROP',fasm
+       ;; ( x -- )
+       ;; Remove x from the stack.
+       add rsp,8
+       next
+
+       WORD p_2drop, '2DROP',fasm
+       ;; ( x1 x2 -- )
+       ;; Drop cell pair x1 x2 from the stack.
+       add rsp,16
+       next
+
+       WORD p_over, 'OVER',fasm
+       ;; ( x1 x2 -- x1 x2 x1 )
+       ;; Place a copy of x1 on top of the stack. 
+       push qword [rsp+8]
+       next
+
+       WORD p_2over, '2OVER',fasm
+       ;; ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
+       ;; Copy cell pair x1 x2 to the top of the stack.
+       push qword [rsp+24]
+       push qword [rsp+24]
+       next
+
+       WORD p_swap, 'SWAP',fasm
+       ;; ( x1 x2 -- x2 x1 )
+       ;; Exchange the top two stack items.
+       mov rax,qword [rsp]
+       mov rbx,qword [rsp+8]
+       mov qword [rsp+8],rax
+       mov qword [rsp],rbx
+       next
+
+       WORD p_2swap, '2SWAP',fasm
+       ;; ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
+       ;; Exchange the top two cell pairs.
+       mov rax,qword [rsp]
+       mov rbx,qword [rsp+16]
+       mov qword [rsp], rbx
+       mov qword [rsp+16],rax
+       mov rax,qword [rsp+8]
+       mov rbx,qword [rsp+24]
+       mov qword [rsp+8], rbx
+       mov qword [rsp+24],rax
+       next
+
+       WORD p_rot, 'ROT',fasm
+       ;; ( x1 x2 x3 -- x2 x3 x1 )
+       ;; Rotate the top three stack entries.
+       mov rax,qword [rsp+16]
+       mov rbx,qword [rsp+8]
+       mov qword [rsp+16],rbx
+       mov rbx,qword [rsp]
+       mov qword [rsp+8],rbx
+       mov qword [rsp],rax
+       next
+
+       ;; ( xu xu-1 ... x0 u -- xu-1 ... x0 xu )
+       ;; Remove u. Rotate u+1 items on the top of the stack. An
+       ;; ambiguous condition exists if there are less than u+2 items
+       ;; on the stack before ROLL is executed.
+       WORD p_roll, 'ROLL',fasm
+       pop rcx
+       shl rcx,3
+       add rcx,rsp
+       mov rax,[rcx+8]
+p_roll_loop:
+       cmp rcx,rsp
+       je p_roll_eq
+       mov rbx,[rcx]
+       mov [rcx+8],rbx
+       sub rcx,8
+       jmp p_roll_loop
+p_roll_eq:
+       mov [rsp],rax
+       next
+
+       WORD p_nip, 'NIP',fasm
+       ;; ( x1 x2 -- x2 )
+       ;; Discard the second stack item. 
+       pop rax
+       mov qword [rsp],rax
+       next
+
+       WORD p_pick, 'PICK',fasm
+       ;; ( xu...x1 x0 u -- xu...x1 x0 xu )
+       ;; Remove u. Copy the xu to the top of the stack. An ambiguous
+       ;; condition exists if there are less than u+2 items on the
+       ;; stack before PICK is executed.
+       pop rax
+       shl rax,3               ; 8 bytes per index
+       push qword [rsp+rax]
+       next
+
+       WORD w6.2.2300, 'TUCK',fasm
+       ;; ( x1 x2 -- x2 x1 x2 )
+       ;; insert the top stack value into below second stack value.
+       pop rax
+       pop rbx
+       push rax
+       push rbx
+       push rax
+       next
diff --git a/stdio.fasm b/stdio.fasm
new file mode 100644 (file)
index 0000000..ae3e08e
--- /dev/null
@@ -0,0 +1,140 @@
+;;; ========================================
+;;; Dynamic memory management. Allocated with MALLOC and released with
+;;; MUNMAP (see below)
+
+       ;; ( size -- addr )
+       ;; Allocates memory (using brk)
+       WORD p_malloc,'MALLOC',fasm
+       pushr rsi               ; pretend it's a FORTH word since it
+                               ; ends via sys_mmap_asm
+       pop rax
+       push qword 0            ; address of mapping (suggestion)
+       push rax                ; length of mapping
+       push qword 3            ; protection mode PROT_READ | PROT_WRITE
+       push qword 8226         ; flags PRIVATE | ANONYMOUS | LOCKED
+       push qword -1           ; fd -1
+       push qword 0            ; offset
+       jmp sys_mmap_asm        ; exit via sys_mmap
+
+;;; ========================================
+;;; Mapping files
+
+       ;; ( fd -- address )
+       ;; Request memory mapping of a file
+       WORD p_mmap,'MMAP',fasm
+       pushr rsi               ; pretend it's a FORTH word since it
+                               ; ends via sys_mmap_asm
+       pop rax
+       push qword 0            ; address of mapping (suggestion)
+       push qword 10240        ; length of mapping
+       push qword 1            ; protection mode PROT_READ
+       push qword 2            ; flags MAP_PRIVATE
+       push rax                ; fd
+       push qword 0            ; offset
+       jmp sys_mmap_asm        ; exit via sys_mmap
+
+;;; ========================================
+;;; Input stream handling. An input stream has a stream buffer that is
+;;; gradually filled on needs basis. The stream buffer includes a
+;;; header portion with:
+;;; * size of buffer (excluding the 32 byte head)
+;;; * source file descriptor
+;;; * current fill
+;;; * current read position
+
+       WORD p_stream,'STREAM',
+       ;; ( fd size -- addr )
+       ;; Allocates a stream buffer of the given size and initializes
+       ;; it to be filled from the given input file descriptor.
+       dq p_dup                ; ( fd size size )
+       dq p_malloc             ; ( fd size addr )
+       dq p_2dup               ; ( fd size addr size addr )
+       dq p_swap               ; ( fd size addr addr size )
+       dq p_erase              ; ( fd size addr )
+       ENDFORTH
+       pop rax                 ; ( fd size )
+       pop rbx                 ; ( fd )
+       sub rbx,32
+       mov [rax],rbx
+       pop rbx
+       mov [rax+8],rbx
+       push rax
+       jmp exit
+
+       WORD p_read_stream_char,'READ-STREAM-CHAR',fasm
+       ;; ( stream -- ch )
+       pushr rsi
+       mov rax,qword [rsp]
+       mov rbx,[rax+16]        ; fill
+p_read_stream_char.READ:
+       mov rcx,[rax+24]        ; current
+       cmp rbx,rcx
+       jg p_read_stream_char.CHAR
+       push qword [rax+8]      ; fd
+       lea rbx,[rax+32]
+       push rbx                ; buffer
+       push qword [rax]        ; size
+       mov qword[rax+16],0
+       mov qword[rax+24],0
+       DOFORTH sys_read
+       pop rbx
+       mov rax,qword [rsp]
+       cmp rbx,0
+       jle p_read_stream_char.EOF
+       mov qword[rax+16],rbx
+       jmp p_read_stream_char.READ
+p_read_stream_char.EOF:
+       mov qword [rsp],-1
+       popr rsi
+       next
+p_read_stream_char.CHAR:
+       inc qword [rax+24]
+       add rcx,32
+       mov qword [rsp],0
+       mov bl,[rax+rcx]
+       mov byte [rsp],bl
+       popr rsi
+       next
+
+       WORD p_line_buffer,'LINE-BUFFER',dovariable
+       ;; A buffer for holding a text line
+       rb 1024
+
+       WORD p_read_word,'READ-WORD',fasm
+       ;; ( stream -- addr length )
+       ;; Read a text line from the stream into the line buffer
+       pushr rsi
+       pop rax
+       push qword p_line_buffer_DFA
+       push qword 0
+       push rax
+p_read_word_skipblanks:        
+       FORTH
+       dq p_dup
+       dq p_read_stream_char
+       ENDFORTH
+       pop rbx
+       cmp bl,0
+       jl p_read_word_nomore
+       cmp bl,' '
+       jle p_read_word_skipblanks
+p_read_word_readword:
+       FORTH
+       dq p_dup
+       dq p_read_stream_char
+       ENDFORTH
+       pop rbx
+       cmp bl,0
+       jl p_read_word_nomore
+       cmp bl,' '
+       jle p_read_word_nomore
+       ;; ( buffer length stream )
+       mov rax,qword [rsp+16]
+       mov rcx,qword [rsp+8]
+       mov [rax+rcx],bl
+       inc qword [rsp+8]
+       jmp p_read_word_readword
+p_read_word_nomore:
+       pop rax
+       popr rsi
+       next
diff --git a/symbols.lsp b/symbols.lsp
new file mode 100755 (executable)
index 0000000..98f4c41
--- /dev/null
@@ -0,0 +1,118 @@
+#!/usr/bin/newlisp
+#
+# Print an assembly listing for ELF targets associating binary address
+# with source lines.
+
+(signal 2 exit) ; exit on Ctrl-C
+
+; Format a byte or list of bytes into a hex string
+(define (hex L)
+  (if (list? L) (string "0x" (join (map (curry format "%02x") L)))
+    ; else
+    (hex (list L))))
+
+; Helper function to "copy out" a NUL terminated string from the
+; beginning of a memblock. (only an issue with utf8-enabled newlisp)
+(define (asciiz X) (get-string (address X)))
+
+; Helper function to set and print a variable
+(define (print-assign X Y) (set X (println X " = " Y)))
+
+; Helper "macro" to set variables and print their assignments
+(define-macro (setf-print)
+  (map (fn (P) (print-assign (P 0) (eval (P 1)))) (explode (args) 2)))
+
+; Load the .fas file here; named last on the command line
+(setf FAS (read-file (main-args -1)))
+
+(setf-print
+ SIGNATURE (hex (reverse (unpack (dup "b" 4) FAS)))
+ VERSION (unpack "bb" (4 FAS))
+ HEADER-LENGTH ((unpack "u" (6 FAS)) 0)
+ INFILEP ((unpack "lu" (8 FAS)) 0)
+ OUTFILEP ((unpack "lu" (12 FAS)) 0)
+ STRINGS-TABLE-OFFSET ((unpack "lu" (16 FAS)) 0)
+ STRINGS-TABLE-LENGTH ((unpack "lu" (20 FAS)) 0)
+ SYMBOLS-TABLE-OFFSET ((unpack "lu" (24 FAS)) 0)
+ SYMBOLS-TABLE-LENGTH ((unpack "lu" (28 FAS)) 0)
+ PREPROCESSED-OFFSET ((unpack "lu" (32 FAS)) 0)
+ PREPROCESSED-LENGTH ((unpack "lu" (36 FAS)) 0)
+ ASSEMBLY-DUMP-OFFSET ((unpack "lu" (40 FAS)) 0)
+ ASSEMBLY-DUMP-LENGTH ((unpack "lu" (44 FAS)) 0)
+ SECTION-TABLE-OFFSET ((unpack "lu" (48 FAS)) 0)
+ SECTION-TABLE-LENGTH ((unpack "lu" (52 FAS)) 0)
+ SYMBOL-REFERENCES-DUMP-OFFSET ((unpack "lu" (56 FAS)) 0)
+ SYMBOL-REFERENCES-DUMP-LENGTH ((unpack "lu" (60 FAS)) 0)
+ )
+
+(setf
+ STRINGS (STRINGS-TABLE-OFFSET STRINGS-TABLE-LENGTH FAS)
+ _ (println STRINGS)
+ PREP (PREPROCESSED-OFFSET PREPROCESSED-LENGTH FAS)
+ )
+
+(setf-print
+ MAIN-FILE (asciiz (INFILEP STRINGS))
+ )
+
+; Hash tables for filename->content and macroid->firstline
+(define FILES:FILES nil)   ; for captured file content
+(define MACROS:MACROS nil) ; for captured first-appearance-line of macros
+
+; Get/cache content of file
+(define (get-file NAME)
+  (or (FILES NAME) (FILES NAME (read-file NAME))))
+
+; Check if N is the first-appearence-line in macro ID
+; (capture N for the very first appearance of ID)
+(define (macro-start ID N)
+  (if (MACROS ID) (= (MACROS ID) N) (MACROS ID N)))
+
+; The file name for prep entry index i (with 0 = main file)
+(define (source-file i)
+  (if (= i) MAIN-FILE (asciiz (i PREP))))
+
+; Extract and format the file line with line number LN that is at at
+; position i of file FILE.
+(define (get-line i FILE LN)
+  (letn ((DATA (get-file FILE))
+         (END (find "\n" DATA nil i))
+         (R (i (- END i) DATA)) )
+    (format "%s:%-5d %s" FILE LN R)))
+
+; Format a "macro" prep entry by prepending an informative line for
+; the first-appearance-line.
+(define (resolve-macro AT PL)
+  (if (macro-start (PL 2) (PL 1))
+      (string (PREP-SOURCE-LINE "--------" (PL 2)) "\n"
+              (PREP-SOURCE-LINE AT (PL 3)))
+    ; else
+    (PREP-SOURCE-LINE AT (PL 3))))
+
+; Format output for "address" AT and prep line PL (unpacked)
+(define (prep-source AT PL)
+  (if (!= (& 0x80000000 (PL 1))) (resolve-macro AT PL)
+    ; else
+    (string AT " " (get-line (PL 2) (source-file (PL 0)) (PL 1)))))
+
+; Format output for "address" AT and prep line at P (index)
+(define (PREP-SOURCE-LINE AT P)
+  (prep-source AT (unpack "lu lu lu lu" (P PREP))))
+
+; Format output for assembly line L (memblock)
+(define (ASSEMBLY-LINE L)
+  (let ((AL (unpack "lu lu lu lu lu b b b b" (or L ""))))
+    (PREP-SOURCE-LINE (hex (AL 2)) (AL 1))
+    ))
+
+; divide memblock D into memblocks of size N
+(define (frag N D)
+  (unpack (dup (string "s" N " ") (/ (length D) N)) D))
+
+#### Main action(s) start here
+
+(map println
+     (map ASSEMBLY-LINE
+          (frag 28 (ASSEMBLY-DUMP-OFFSET ASSEMBLY-DUMP-LENGTH FAS))))
+
+(exit 0)
diff --git a/syscalls.fasm b/syscalls.fasm
new file mode 100644 (file)
index 0000000..ede8849
--- /dev/null
@@ -0,0 +1,372 @@
+;;; https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
+;;;
+;;;          id  rtn  0     1    2    3    4  5
+;;; x86_64: rax, rax, rdi, rsi, rdx, r10, r8, r9
+
+;;; %rax       System call     %rdi    %rsi    %rdx    %r10    %r8     %r9
+
+;;; ==============================
+;;; Helper macro for layout of syscall argument registers
+
+macro SYSCALLARG register,count,nargs {
+if count < nargs
+       mov register, [rsp + ((nargs-count-1)*8)]
+end if
+}
+
+;;; Code layout for system call with up to 6 arguments
+macro SYSCALL id,name,fname,nargs {
+       WORD name,fname,fasm
+       pushr rsi
+name#_asm:
+       mov rax,qword id
+       SYSCALLARG r9,5,nargs
+       SYSCALLARG r8,4,nargs
+       SYSCALLARG r10,3,nargs
+       SYSCALLARG rdx,2,nargs
+       SYSCALLARG rsi,1,nargs
+       SYSCALLARG rdi,0,nargs
+if nargs > 0
+       add rsp,nargs*8
+end if
+       syscall
+       push rax
+       jmp exit
+}
+
+       SYSCALL 0,sys_read,'SYS_READ',3
+       SYSCALL 1,sys_write,'SYS_WRITE',3
+       SYSCALL 2,sys_open,'SYS_OPEN',3
+       SYSCALL 3,sys_close,'SYS_CLOSE',1
+       SYSCALL 4,sys_stat,'SYS_STAT',2
+       SYSCALL 5,sys_fstat,'SYS_FSTAT',2                               
+       SYSCALL 6,sys_lstat,'SYS_LSTAT',2
+       SYSCALL 7,sys_poll,'SYS_POLL',3
+       SYSCALL 8,sys_lseek,'SYS_LSEEK',3
+       SYSCALL 9,sys_mmap,'SYS_MMAP',6
+       SYSCALL 10,sys_mprotect,'SYS_MPROTECT',3
+       SYSCALL 11,sys_munmap,'SYS_MUNMAP',2
+       SYSCALL 12,sys_brk,'SYS_BRK',1
+       SYSCALL 13,sys_rt_sigaction,'SYS_RT_SIGACTION',4
+       SYSCALL 14,sys_rt_sigprocmask,'SYS_RT_SIGPROCMASK',4
+       SYSCALL 15,sys_rt_sigreturn,'SYS_RT_SIGRETURN',1
+       SYSCALL 16,sys_ioctl,'SYS_IOCTL',3
+       SYSCALL 17,sys_pread64,'SYS_PREAD64',4
+       SYSCALL 18,sys_pwrite64,'SYS_PWRITE64',4
+       SYSCALL 19,sys_readv,'SYS_READV',3
+       SYSCALL 20,sys_writev,'SYS_WRITEV',3
+       SYSCALL 21,sys_access,'SYS_ACCESS',2
+       SYSCALL 22,sys_pipe,'SYS_PIPE',1
+       SYSCALL 23,sys_select,'SYS_SELECT',5
+       SYSCALL 24,sys_sched_yield,'SYS_SCHED_YIELD',0
+       SYSCALL 25,sys_mremap,'SYS_MREMAP',5
+       SYSCALL 26,sys_msync,'SYS_MSYNC',3
+       SYSCALL 27,sys_mincore,'SYS_MINCORE',3
+       SYSCALL 28,sys_madvise,'SYS_MADVISE',3
+       SYSCALL 29,sys_shmget,'SYS_SHMGET',3
+       SYSCALL 30,sys_shmat,'SYS_SHMAT',3
+       SYSCALL 31,sys_shmctl,'SYS_SHMCTL',3
+       SYSCALL 32,sys_dup,'SYS_DUP',1
+       SYSCALL 33,sys_dup2,'SYS_DUP2',2
+       SYSCALL 34,sys_pause,'SYS_PAUSE',0
+       SYSCALL 35,sys_nanosleep,'SYS_NANOSLEEP',2
+       SYSCALL 36,sys_getitimer,'SYS_GETITIMER',2
+       SYSCALL 37,sys_alarm,'SYS_ALARM',1
+       SYSCALL 38,sys_setitimer,'SYS_SETITIMER',3
+       SYSCALL 39,sys_getpid,'SYS_GETPID',0
+       SYSCALL 40,sys_sendfile,'SYS_SENDFILE',4
+       SYSCALL 41,sys_socket,'SYS_SOCKET',3
+       SYSCALL 42,sys_connect,'SYS_CONNECT',3
+       SYSCALL 43,sys_accept,'SYS_ACCEPT',3
+       SYSCALL 44,sys_sendto,'SYS_SENDTO',6
+       SYSCALL 45,sys_recvfrom,'SYS_RECVFROM',6
+       SYSCALL 46,sys_sendmsg,'SYS_SENDMSG',3                  
+       SYSCALL 47,sys_recvmsg,'SYS_RECVMSG',3                  
+       SYSCALL 48,sys_shutdown,'SYS_SHUTDOWN',2
+       SYSCALL 49,sys_bind,'SYS_BIND',3
+       SYSCALL 50,sys_listen,'SYS_LISTEN',2
+       SYSCALL 51,sys_getsockname,'SYS_GETSOCKNAME',3
+       SYSCALL 52,sys_getpeername,'SYS_GETPEERNAME',3
+       SYSCALL 53,sys_socketpair,'SYS_SOCKETPAIR',4
+       SYSCALL 54,sys_setsockopt,'SYS_SETSOCKOPT',5
+       SYSCALL 55,sys_getsockopt,'SYS_GETSOCKOPT',5
+       SYSCALL 56,sys_clone,'SYS_CLONE',5
+       SYSCALL 57,sys_fork,'SYS_FORK',0
+       SYSCALL 58,sys_vfork,'SYS_VFORK',0
+       SYSCALL 59,sys_execve,'SYS_EXECVE',3
+       SYSCALL 60,sys_exit,'SYS_EXIT',1
+       SYSCALL 61,sys_wait4,'SYS_WAIT4',4
+       SYSCALL 62,sys_kill,'SYS_KILL',2
+       SYSCALL 63,sys_uname,'SYS_UNAME',1
+       SYSCALL 64,sys_semget,'SYS_SEMGET',3
+       SYSCALL 65,sys_semop,'SYS_SEMOP',3
+       SYSCALL 66,sys_semctl,'SYS_SEMCTL',4
+       SYSCALL 67,sys_shmdt,'SYS_SHMDT',1
+       SYSCALL 68,sys_msgget,'SYS_MSGGET',2
+       SYSCALL 69,sys_msgsnd,'SYS_MSGSND',4
+       SYSCALL 70,sys_msgrcv,'SYS_MSGRCV',5
+       SYSCALL 71,sys_msgctl,'SYS_MSGCTL',3
+       SYSCALL 72,sys_fcntl,'SYS_FCNTL',3
+       SYSCALL 73,sys_flock,'SYS_FLOCK',2
+       SYSCALL 74,sys_fsync,'SYS_FSYNC',1
+       SYSCALL 75,sys_fdatasync,'SYS_FDATASYNC',1
+       SYSCALL 76,sys_truncate,'SYS_TRUNCATE',2
+       SYSCALL 77,sys_ftruncate,'SYS_FTRUNCATE',2
+       SYSCALL 78,sys_getdents,'SYS_GETDENTS',3
+       SYSCALL 79,sys_getcwd,'SYS_GETCWD',2
+       SYSCALL 80,sys_chdir,'SYS_CHDIR',1
+       SYSCALL 81,sys_fchdir,'SYS_FCHDIR',1
+       SYSCALL 82,sys_rename,'SYS_RENAME',2
+       SYSCALL 83,sys_mkdir,'SYS_MKDIR',2
+       SYSCALL 84,sys_rmdir,'SYS_RMDIR',1
+       SYSCALL 85,sys_creat,'SYS_CREAT',2
+       SYSCALL 86,sys_link,'SYS_LINK',2
+       SYSCALL 87,sys_unlink,'SYS_UNLINK',1
+       SYSCALL 88,sys_symlink,'SYS_SYMLINK',2
+       SYSCALL 89,sys_readlink,'SYS_READLINK',3
+       SYSCALL 90,sys_chmod,'SYS_CHMOD',2
+       SYSCALL 91,sys_fchmod,'SYS_FCHMOD',2
+       SYSCALL 92,sys_chown,'SYS_CHOWN',3
+       SYSCALL 93,sys_fchown,'SYS_FCHOWN',3
+       SYSCALL 94,sys_lchown,'SYS_LCHOWN',3
+       SYSCALL 95,sys_umask,'SYS_UMASK',1
+       SYSCALL 96,sys_gettimeofday,'SYS_GETTIMEOFDAY',2
+       SYSCALL 97,sys_getrlimit,'SYS_GETRLIMIT',2
+       SYSCALL 98,sys_getrusage,'SYS_GETRUSAGE',2
+       SYSCALL 99,sys_sysinfo,'SYS_SYSINFO',1
+       SYSCALL 100,sys_times,'SYS_TIMES',1
+       SYSCALL 101,sys_ptrace,'SYS_PTRACE',4
+       SYSCALL 102,sys_getuid,'SYS_GETUID',0
+       SYSCALL 103,sys_syslog,'SYS_SYSLOG',3
+       SYSCALL 104,sys_getgid,'SYS_GETGID',0
+       SYSCALL 105,sys_setuid,'SYS_SETUID',1
+       SYSCALL 106,sys_setgid,'SYS_SETGID',1
+       SYSCALL 107,sys_geteuid,'SYS_GETEUID',0
+       SYSCALL 108,sys_getegid,'SYS_GETEGID',0
+       SYSCALL 109,sys_setpgid,'SYS_SETPGID',2
+       SYSCALL 110,sys_getppid,'SYS_GETPPID',0
+       SYSCALL 111,sys_getpgrp,'SYS_GETPGRP',0
+       SYSCALL 112,sys_setsid,'SYS_SETSID',0
+       SYSCALL 113,sys_setreuid,'SYS_SETREUID',2
+       SYSCALL 114,sys_setregid,'SYS_SETREGID',2
+       SYSCALL 115,sys_getgroups,'SYS_GETGROUPS',2
+       SYSCALL 116,sys_setgroups,'SYS_SETGROUPS',2
+       SYSCALL 117,sys_setresuid,'SYS_SETRESUID',3
+       SYSCALL 118,sys_getresuid,'SYS_GETRESUID',3
+       SYSCALL 119,sys_setresgid,'SYS_SETRESGID',3
+       SYSCALL 120,sys_getresgid,'SYS_GETRESGID',3
+       SYSCALL 121,sys_getpgid,'SYS_GETPGID',1
+       SYSCALL 122,sys_setfsuid,'SYS_SETFSUID',1
+       SYSCALL 123,sys_setfsgid,'SYS_SETFSGID',1
+       SYSCALL 124,sys_getsid,'SYS_GETSID',1
+       SYSCALL 125,sys_capget,'SYS_CAPGET',2
+       SYSCALL 126,sys_capset,'SYS_CAPSET',2
+       SYSCALL 127,sys_rt_sigpending,'SYS_RT_SIGPENDING',2
+       SYSCALL 128,sys_rt_sigtimedwait,'SYS_RT_SIGTIMEDWAIT',4
+       SYSCALL 129,sys_rt_sigqueueinfo,'SYS_RT_SIGQUEUEINFO',3
+       SYSCALL 130,sys_rt_sigsuspend,'SYS_RT_SIGSUSPEND',2
+       SYSCALL 131,sys_sigaltstack,'SYS_SIGALTSTACK',2
+       SYSCALL 132,sys_utime,'SYS_UTIME',2
+       SYSCALL 133,sys_mknod,'SYS_MKNOD',3
+       ;SYSCALL 134,sys_uselib,'SYS_USELIB',   NOT IMPLEMENTED
+       SYSCALL 135,sys_personality,'SYS_PERSONALITY',1
+       SYSCALL 136,sys_ustat,'SYS_USTAT',2
+       SYSCALL 137,sys_statfs,'SYS_STATFS',2
+       SYSCALL 138,sys_fstatfs,'SYS_FSTATFS',2
+       SYSCALL 139,sys_sysfs,'SYS_SYSFS',3
+       SYSCALL 140,sys_getpriority,'SYS_GETPRIORITY',2
+       SYSCALL 141,sys_setpriority,'SYS_SETPRIORITY',3
+       SYSCALL 142,sys_sched_setparam,'SYS_SCHED_SETPARAM',2
+       SYSCALL 143,sys_sched_getparam,'SYS_SCHED_GETPARAM',2
+       SYSCALL 144,sys_sched_setscheduler,'SYS_SCHED_SETSCHEDULER',3
+       SYSCALL 145,sys_sched_getscheduler,'SYS_SCHED_GETSCHEDULER',1
+       SYSCALL 146,sys_sched_get_priority_max,'SYS_SCHED_GET_PRIORITY_MAX',1
+       SYSCALL 147,sys_sched_get_priority_min,'SYS_SCHED_GET_PRIORITY_MIN',1
+       SYSCALL 148,sys_sched_rr_get_interval,'SYS_SCHED_RR_GET_INTERVAL',2
+       SYSCALL 149,sys_mlock,'SYS_MLOCK',2
+       SYSCALL 150,sys_munlock,'SYS_MUNLOCK',2
+       SYSCALL 151,sys_mlockall,'SYS_MLOCKALL',1
+       SYSCALL 152,sys_munlockall,'SYS_MUNLOCKALL',0
+       SYSCALL 153,sys_vhangup,'SYS_VHANGUP',0
+       SYSCALL 154,sys_modify_ldt,'SYS_MODIFY_LDT',3
+       SYSCALL 155,sys_pivot_root,'SYS_PIVOT_ROOT',2
+       SYSCALL 156,sys__sysctl,'SYS__SYSCTL',1
+       SYSCALL 157,sys_prctl,'SYS_PRCTL',6
+       SYSCALL 158,sys_arch_prctl,'SYS_ARCH_PRCTL',3
+       SYSCALL 159,sys_adjtimex,'SYS_ADJTIMEX',1
+       SYSCALL 160,sys_setrlimit,'SYS_SETRLIMIT',2
+       SYSCALL 161,sys_chroot,'SYS_CHROOT',1
+       SYSCALL 162,sys_sync,'SYS_SYNC',0
+       SYSCALL 163,sys_acct,'SYS_ACCT',1
+       SYSCALL 164,sys_settimeofday,'SYS_SETTIMEOFDAY',2
+       SYSCALL 165,sys_mount,'SYS_MOUNT',5
+       SYSCALL 166,sys_umount2,'SYS_UMOUNT2',2
+       SYSCALL 167,sys_swapon,'SYS_SWAPON',2
+       SYSCALL 168,sys_swapoff,'SYS_SWAPOFF',1
+       SYSCALL 169,sys_reboot,'SYS_REBOOT',4
+       SYSCALL 170,sys_sethostname,'SYS_SETHOSTNAME',2
+       SYSCALL 171,sys_setdomainname,'SYS_SETDOMAINNAME',2
+       SYSCALL 172,sys_iopl,'SYS_IOPL',2
+       SYSCALL 173,sys_ioperm,'SYS_IOPERM',3
+       ;SYSCALL 174,sys_create_module,'SYS_CREATE_MODULE' REMOVED IN Linux 2.6
+       SYSCALL 175,sys_init_module,'SYS_INIT_MODULE',3
+       SYSCALL 176,sys_delete_module,'SYS_DELETE_MODULE',2
+       ;SYSCALL 177,sys_get_kernel_syms, REMOVED IN Linux 2.6
+       ;SYSCALL 178,sys_query_module,'SYS_QUERY_MODULE', REMOVED IN Linux 2.6
+       SYSCALL 179,sys_quotactl,'SYS_QUOTACTL',4
+       ;SYSCALL 180,sys_nfsservctl,'SYS_NFSSERVCTL',   NOT IMPLEMENTED
+       ;SYSCALL 181,sys_getpmsg,'SYS_GETPMSG', NOT IMPLEMENTED
+       ;SYSCALL 182,sys_putpmsg,'SYS_PUTPMSG', NOT IMPLEMENTED
+       ;SYSCALL 183,sys_afs_syscall,'SYS_AFS_SYSCALL', NOT IMPLEMENTED
+       ;SYSCALL 184,sys_tuxcall,'SYS_TUXCALL', NOT IMPLEMENTED
+       ;SYSCALL 185,sys_security,'SYS_SECURITY',       NOT IMPLEMENTED
+       SYSCALL 186,sys_gettid,'SYS_GETTID',0
+       SYSCALL 187,sys_readahead,'SYS_READAHEAD',3
+       SYSCALL 188,sys_setxattr,'SYS_SETXATTR',5
+       SYSCALL 189,sys_lsetxattr,'SYS_LSETXATTR',5
+       SYSCALL 190,sys_fsetxattr,'SYS_FSETXATTR',5
+       SYSCALL 191,sys_getxattr,'SYS_GETXATTR',4
+       SYSCALL 192,sys_lgetxattr,'SYS_LGETXATTR',4
+       SYSCALL 193,sys_fgetxattr,'SYS_FGETXATTR',4
+       SYSCALL 194,sys_listxattr,'SYS_LISTXATTR',3
+       SYSCALL 195,sys_llistxattr,'SYS_LLISTXATTR',4
+       SYSCALL 196,sys_flistxattr,'SYS_FLISTXATTR',3
+       SYSCALL 197,sys_removexattr,'SYS_REMOVEXATTR',2
+       SYSCALL 198,sys_lremovexattr,'SYS_LREMOVEXATTR',2
+       SYSCALL 199,sys_fremovexattr,'SYS_FREMOVEXATTR',2
+       SYSCALL 200,sys_tkill,'SYS_TKILL',2
+       SYSCALL 201,sys_time,'SYS_TIME',1
+       SYSCALL 202,sys_futex,'SYS_FUTEX',6
+       SYSCALL 203,sys_sched_setaffinity,'SYS_SCHED_SETAFFINITY',3
+       SYSCALL 204,sys_sched_getaffinity,'SYS_SCHED_GETAFFINITY',3
+       ;SYSCALL 205,sys_set_thread_area, NOT IMPLEMENTED. Use arch_prctl
+       SYSCALL 206,sys_io_setup,'SYS_IO_SETUP',2
+       SYSCALL 207,sys_io_destroy,'SYS_IO_DESTROY',2
+       SYSCALL 208,sys_io_getevents,'SYS_IO_GETEVENTS',4
+       SYSCALL 209,sys_io_submit,'SYS_IO_SUBMIT',3
+       SYSCALL 210,sys_io_cancel,'SYS_IO_CANCEL',3
+       ;SYSCALL 211,sys_get_thread_area, NOT IMPLEMENTED. Use arch_prctl
+       SYSCALL 212,sys_lookup_dcookie,'SYS_LOOKUP_DCOOKIE',3
+       SYSCALL 213,sys_epoll_create,'SYS_EPOLL_CREATE',1
+       ;SYSCALL 214,sys_epoll_ctl_old,'SYS_EPOLL_CTL_OLD', NOT IMPLEMENTED
+       ;SYSCALL 215,sys_epoll_wait_old,'SYS_EPOLL_WAIT_OLD', NOT IMPLEMENTED
+       SYSCALL 216,sys_remap_file_pages,'SYS_REMAP_FILE_PAGES',5
+       SYSCALL 217,sys_getdents64,'SYS_GETDENTS64',3
+       SYSCALL 218,sys_set_tid_address,'SYS_SET_TID_ADDRESS',1
+       SYSCALL 219,sys_restart_syscall,'SYS_RESTART_SYSCALL',0
+       SYSCALL 220,sys_semtimedop,'SYS_SEMTIMEDOP',4
+       SYSCALL 221,sys_fadvise64,'SYS_FADVISE64',4
+       SYSCALL 222,sys_timer_create,'SYS_TIMER_CREATE',3
+       SYSCALL 223,sys_timer_settime,'SYS_TIMER_SETTIME',4
+       SYSCALL 224,sys_timer_gettime,'SYS_TIMER_GETTIME',2
+       SYSCALL 225,sys_timer_getoverrun,'SYS_TIMER_GETOVERRUN',1
+       SYSCALL 226,sys_timer_delete,'SYS_TIMER_DELETE',1
+       SYSCALL 227,sys_clock_settime,'SYS_CLOCK_SETTIME',2
+       SYSCALL 228,sys_clock_gettime,'SYS_CLOCK_GETTIME',2
+       SYSCALL 229,sys_clock_getres,'SYS_CLOCK_GETRES',2
+       SYSCALL 230,sys_clock_nanosleep,'SYS_CLOCK_NANOSLEEP',4
+       SYSCALL 231,sys_exit_group,'SYS_EXIT_GROUP',1
+       SYSCALL 232,sys_epoll_wait,'SYS_EPOLL_WAIT',4
+       SYSCALL 233,sys_epoll_ctl,'SYS_EPOLL_CTL',4
+       SYSCALL 234,sys_tgkill,'SYS_TGKILL',3
+       SYSCALL 235,sys_utimes,'SYS_UTIMES',2
+       ;SYSCALL 236,sys_vserver,'SYS_VSERVER', NOT IMPLEMENTED
+       SYSCALL 237,sys_mbind,'SYS_MBIND',6
+       SYSCALL 238,sys_set_mempolicy,'SYS_SET_MEMPOLICY',3
+       SYSCALL 239,sys_get_mempolicy,'SYS_GET_MEMPOLICY',5
+       SYSCALL 240,sys_mq_open,'SYS_MQ_OPEN',4
+       SYSCALL 241,sys_mq_unlink,'SYS_MQ_UNLINK',1
+       SYSCALL 242,sys_mq_timedsend,'SYS_MQ_TIMEDSEND',5
+       SYSCALL 243,sys_mq_timedreceive,'SYS_MQ_TIMEDRECEIVE',5
+       SYSCALL 244,sys_mq_notify,'SYS_MQ_NOTIFY',2
+       SYSCALL 245,sys_mq_getsetattr,'SYS_MQ_GETSETATTR',3
+       SYSCALL 246,sys_kexec_load,'SYS_KEXEC_LOAD',4
+       SYSCALL 247,sys_waitid,'SYS_WAITID',5
+       SYSCALL 248,sys_add_key,'SYS_ADD_KEY',4
+       SYSCALL 249,sys_request_key,'SYS_REQUEST_KEY',4
+       SYSCALL 250,sys_keyctl,'SYS_KEYCTL',5
+       SYSCALL 251,sys_ioprio_set,'SYS_IOPRIO_SET',3
+       SYSCALL 252,sys_ioprio_get,'SYS_IOPRIO_GET',2
+       SYSCALL 253,sys_inotify_init,'SYS_INOTIFY_INIT',0
+       SYSCALL 254,sys_inotify_add_watch,'SYS_INOTIFY_ADD_WATCH',3
+       SYSCALL 255,sys_inotify_rm_watch,'SYS_INOTIFY_RM_WATCH',2
+       SYSCALL 256,sys_migrate_pages,'SYS_MIGRATE_PAGES',4
+       SYSCALL 257,sys_openat,'SYS_OPENAT',4
+       SYSCALL 258,sys_mkdirat,'SYS_MKDIRAT',3
+       SYSCALL 259,sys_mknodat,'SYS_MKNODAT',4
+       SYSCALL 260,sys_fchownat,'SYS_FCHOWNAT',5
+       SYSCALL 261,sys_futimesat,'SYS_FUTIMESAT',3
+       SYSCALL 262,sys_newfstatat,'SYS_NEWFSTATAT',4
+       SYSCALL 263,sys_unlinkat,'SYS_UNLINKAT',3
+       SYSCALL 264,sys_renameat,'SYS_RENAMEAT',4
+       SYSCALL 265,sys_linkat,'SYS_LINKAT',5
+       SYSCALL 266,sys_symlinkat,'SYS_SYMLINKAT',3
+       SYSCALL 267,sys_readlinkat,'SYS_READLINKAT',4
+       SYSCALL 268,sys_fchmodat,'SYS_FCHMODAT',3
+       SYSCALL 269,sys_faccessat,'SYS_FACCESSAT',3
+       SYSCALL 270,sys_pselect6,'SYS_PSELECT6',6
+       SYSCALL 271,sys_ppoll,'SYS_PPOLL',5
+       SYSCALL 272,sys_unshare,'SYS_UNSHARE',1
+       SYSCALL 273,sys_set_robust_list,'SYS_SET_ROBUST_LIST',2
+       SYSCALL 274,sys_get_robust_list,'SYS_GET_ROBUST_LIST',3
+       SYSCALL 275,sys_splice,'SYS_SPLICE',6
+       SYSCALL 276,sys_tee,'SYS_TEE',4
+       SYSCALL 277,sys_sync_file_range,'SYS_SYNC_FILE_RANGE',4
+       SYSCALL 278,sys_vmsplice,'SYS_VMSPLICE',4
+       SYSCALL 279,sys_move_pages,'SYS_MOVE_PAGES',6
+       SYSCALL 280,sys_utimensat,'SYS_UTIMENSAT',4
+       SYSCALL 281,sys_epoll_pwait,'SYS_EPOLL_PWAIT',6
+       SYSCALL 282,sys_signalfd,'SYS_SIGNALFD',3
+       SYSCALL 283,sys_timerfd_create,'SYS_TIMERFD_CREATE',2
+       SYSCALL 284,sys_eventfd,'SYS_EVENTFD',1
+       SYSCALL 285,sys_fallocate,'SYS_FALLOCATE',4
+       SYSCALL 286,sys_timerfd_settime,'SYS_TIMERFD_SETTIME',4
+       SYSCALL 287,sys_timerfd_gettime,'SYS_TIMERFD_GETTIME',2
+       SYSCALL 288,sys_accept4,'SYS_ACCEPT4',4
+       SYSCALL 289,sys_signalfd4,'SYS_SIGNALFD4',4
+       SYSCALL 290,sys_eventfd2,'SYS_EVENTFD2',2
+       SYSCALL 291,sys_epoll_create1,'SYS_EPOLL_CREATE1',1
+       SYSCALL 292,sys_dup3,'SYS_DUP3',3
+       SYSCALL 293,sys_pipe2,'SYS_PIPE2',2
+       SYSCALL 294,sys_inotify_init1,'SYS_INOTIFY_INIT1',1
+       SYSCALL 295,sys_preadv,'SYS_PREADV',5
+       SYSCALL 296,sys_pwritev,'SYS_PWRITEV',5
+       SYSCALL 297,sys_rt_tgsigqueueinfo,'SYS_RT_TGSIGQUEUEINFO',4
+       SYSCALL 298,sys_perf_event_open,'SYS_PERF_EVENT_OPEN',5
+       SYSCALL 299,sys_recvmmsg,'SYS_RECVMMSG',5
+       SYSCALL 300,sys_fanotify_init,'SYS_FANOTIFY_INIT',2
+       SYSCALL 301,sys_fanotify_mark,'SYS_FANOTIFY_MARK',5     
+       SYSCALL 302,sys_prlimit64,'SYS_PRLIMIT64',4
+       SYSCALL 303,sys_name_to_handle_at,'SYS_NAME_TO_HANDLE_AT',5
+       SYSCALL 304,sys_open_by_handle_at,'SYS_OPEN_BY_HANDLE_AT',5
+       SYSCALL 305,sys_clock_adjtime,'SYS_CLOCK_ADJTIME',2
+       SYSCALL 306,sys_syncfs,'SYS_SYNCFS',1
+       SYSCALL 307,sys_sendmmsg,'SYS_SENDMMSG',4
+       SYSCALL 308,sys_setns,'SYS_SETNS',2
+       SYSCALL 309,sys_getcpu,'SYS_GETCPU',3
+       SYSCALL 310,sys_process_vm_readv,'SYS_PROCESS_VM_READV',6
+       SYSCALL 311,sys_process_vm_writev,'SYS_PROCESS_VM_WRITEV',6
+       SYSCALL 312,sys_kcmp,'SYS_KCMP',5
+       SYSCALL 313,sys_finit_module,'SYS_FINIT_MODULE',3
+       SYSCALL 314,sys_sched_setattr,'SYS_SCHED_SETATTR',3
+       SYSCALL 315,sys_sched_getattr,'SYS_SCHED_GETATTR',4
+       SYSCALL 316,sys_renameat2,'SYS_RENAMEAT2',5
+       SYSCALL 317,sys_seccomp,'SYS_SECCOMP',3
+       SYSCALL 318,sys_getrandom,'SYS_GETRANDOM',3
+       SYSCALL 319,sys_memfd_create,'SYS_MEMFD_CREATE',2
+       SYSCALL 320,sys_kexec_file_load,'SYS_KEXEC_FILE_LOAD',5
+       SYSCALL 321,sys_bpf,'SYS_BPF',3
+       SYSCALL 322,stub_execveat,'STUB_EXECVEAT',5
+       SYSCALL 323,userfaultfd,'USERFAULTFD',1
+       SYSCALL 324,membarrier,'MEMBARRIER',2
+       SYSCALL 325,mlock2,'MLOCK2',3
+       SYSCALL 326,copy_file_range,'COPY_FILE_RANGE',6
+       SYSCALL 327,preadv2,'PREADV2',6
+       SYSCALL 328,pwritev2,'PWRITEV2',6
+       SYSCALL 329,pkey_mprotect,'PKEY_MPROTECT',0
+       SYSCALL 330,pkey_alloc,'PKEY_ALLOC',0
+       SYSCALL 331,pkey_free,'PKEY_FREE',0
+       SYSCALL 332,statx,'STATX',0
+       SYSCALL 333,io_pgetevents,'IO_PGETEVENTS',0
+       SYSCALL 334,rseq,'RSEQ',0
+       SYSCALL 335,pkey_mprotect1,'PKEY_MPROTECT1',0
diff --git a/wordlists.fasm b/wordlists.fasm
new file mode 100644 (file)
index 0000000..9790a28
--- /dev/null
@@ -0,0 +1,59 @@
+;;; This file contains words dealing with word lists (vocabularies)
+;;;
+       WORD p_wordlists,'WORDLIST',dovariable
+       ;; VARIABLE WORDLIST is the currently active wordlist.
+       dq last_word
+
+       WORD p_strncmp,'STRNCMP',fasm
+       ;; ( chars1 chars2 n -- flag )
+       ;; Compare bytes until one is NUL, return <0, =0 or >0 to
+       ;; indicate that chars1 is lesser, they are equal, or chars2
+       ;; is lesser in ascii ordering respectively.
+       pop rdx
+       pop rbx
+       pop rax
+       xor rcx,rcx
+       ;; rax = chars1, rbx = chars2, cl = byte acc, rdx = length
+       inc rdx
+p_strncmp_loop:
+       dec rdx
+       je p_strncmp_end
+       mov cl,[rax]
+       inc rax
+       sub cl,[rbx]
+       inc rbx
+       je p_strncmp_loop
+p_strncmp_end:
+       push rcx
+       next
+
+       WORD p_find,'FIND'
+       ;; ( chars length -- [ chars 0 | cfa 1 )
+       ;; Search the current wordlists for the given pname
+       mov rcx,[p_wordlists_DFA]
+p_find_loop:
+       cmp rcx,0
+       je p_find_done
+       mov rbx,[rsp]
+       mov rax,[rsp+8]
+       cmp bl,byte [rcx+10]
+       jne p_find_nextword
+       push rcx
+       ;; check word
+       push rax
+       push rcx+11
+       push rbx
+       DOFORTH p_strncmp
+       pop rax                 ; return value
+       pop rcx
+       cmp rax,0
+       je p_find_done
+p_find_nextword:
+       mov rcx,[rcx]
+       jmp p_find_loop
+p_find_found:
+       mov qword [rsp+8],rcx   ; replace chars with tfa
+       mov rcx,1
+p_find_done:
+       push rcx
+       next