summary refs log tree commit diff
path: root/quine.asm
diff options
context:
space:
mode:
Diffstat (limited to 'quine.asm')
-rw-r--r--quine.asm114
1 files changed, 82 insertions, 32 deletions
diff --git a/quine.asm b/quine.asm
index 50f245f..22ebb1e 100644
--- a/quine.asm
+++ b/quine.asm
@@ -1362,6 +1362,32 @@ macro NEXT
 end macro
 
 ;;;
+;;; Macro BEFORENEXT
+;;; ----------------
+;;;
+;;;   Sometimes we want to transfer control from a word implemented in
+;;; machine-code to another word, without coming back after, as if we were
+;;; simply jumping to it. This is an innovation of ours; Jonesforth doesn't do
+;;; it.
+;;;
+;;;   This implementation will work regardless of how the receiving word is
+;;; implemented. It impersonates NEXT, setting up rax to point to the codeword
+;;; then jumping to the interpreter. Since it doesn't change the control
+;;; stack or rsi, when the receiving word eventually invokes NEXT, it will
+;;; pick up in the same place as if this sending word had done it.
+;;;
+;;;   Thus, notionally we are doing just this one transfer of control before
+;;; eventually getting around to inlining NEXT. Hence the name.
+;;;
+macro BEFORENEXT target
+  ; Do a permanent transfer of control by setting rax and invoking the
+  ; codeword. Of course, we could jump to DOCOL ourselves but this will work
+  ; regardless of what the receiving codeword is.
+  mov.qreg.qimm rax, target
+  jmp.abs.indirect.qreg rax
+end macro
+
+;;;
 ;;; Macros PUSHCONTROL
 ;;;        POPCONTROL
 ;;; ------------------
@@ -2152,23 +2178,47 @@ defword WRITE_SELF_RAW_H, 0
 
 ; In: base address, value
 ; Out: new base address
-defword PACK, 0
+defword PACK64, 0
   dq DOCOL                       ; codeword
   dq SWAP, DUP, ROLLD3, STORE, LIT, 8, ADD
   dq EXIT
-defword PACK8, 0
+defword PACK32, 0
   dq DOCOL                       ; codeword
-  dq SWAP, DUP, ROLLD3, STORE8, LIT, 1, ADD
+  dq SWAP, DUP, ROLLD3, STORE32, LIT, 4, ADD
   dq EXIT
 defword PACK16, 0
   dq DOCOL                       ; codeword
   dq SWAP, DUP, ROLLD3, STORE16, LIT, 2, ADD
   dq EXIT
-defword PACK32, 0
+defword PACK8, 0
   dq DOCOL                       ; codeword
-  dq SWAP, DUP, ROLLD3, STORE32, LIT, 4, ADD
+  dq SWAP, DUP, ROLLD3, STORE8, LIT, 1, ADD
   dq EXIT
 
+; In the interests of reducing our executable's size, since a lot of it goes
+; to PACK* invocations, we define words that combine LIT with PACK*. This
+; shaves roughly 700 bytes as of when it was added.
+defword LITPACK64, 0
+  dq $ + 0x8                     ; codeword
+  lodsq
+  push.qreg rax
+  BEFORENEXT PACK64
+defword LITPACK32, 0
+  dq $ + 0x8                     ; codeword
+  lodsq
+  push.qreg rax
+  BEFORENEXT PACK32
+defword LITPACK16, 0
+  dq $ + 0x8                     ; codeword
+  lodsq
+  push.qreg rax
+  BEFORENEXT PACK16
+defword LITPACK8, 0
+  dq $ + 0x8                     ; codeword
+  lodsq
+  push.qreg rax
+  BEFORENEXT PACK8
+
 
 ;;;
 ;;; ELF header
@@ -2179,32 +2229,32 @@ defword PACK32, 0
 defword ELF_FILE_HEADER, 0
   dq DOCOL                       ; codeword
 
-  dq LIT, 0x7f bappend "ELF", PACK32        ; magic number
-  dq LIT, 2, PACK8                          ; 64-bit
-  dq LIT, 1, PACK8                          ; little-endian
-  dq LIT, 1, PACK8                          ; ELF header format v1
-  dq LIT, 0, PACK8                          ; System-V ABI
-  dq LIT, 0, PACK                           ; (padding)
+  dq LITPACK32, 0x7f bappend "ELF"          ; magic number
+  dq LITPACK8, 2                            ; 64-bit
+  dq LITPACK8, 1                            ; little-endian
+  dq LITPACK8, 1                            ; ELF header format v1
+  dq LITPACK8, 0                            ; System-V ABI
+  dq LITPACK64, 0                           ; (padding)
 
-  dq LIT, 2, PACK16                         ; executable
-  dq LIT, 0x3e, PACK16                      ; Intel x86-64
-  dq LIT, 1, PACK32                         ; ELF format version
+  dq LITPACK16, 2                           ; executable
+  dq LITPACK16, 0x3e                        ; Intel x86-64
+  dq LITPACK32, 1                           ; ELF format version
 
   ; Compute the entry pointer.
-  dq LIT, _start, PACK                      ; entry point
+  dq LITPACK64, _start                      ; entry point
     ; The offset of _start. This includes the origin, intentionally.
 
-  dq LIT, 64, PACK                          ; program header offset
+  dq LITPACK64, 64                          ; program header offset
     ; We place the program header immediately after the ELF header. This
     ; offset is from the start of the file.
-  dq LIT, 0, PACK                           ; section header offset
-  dq LIT, 0, PACK32                         ; processor flags
-  dq LIT, 64, PACK16                        ; ELF header size
-  dq LIT, 56, PACK16                        ; program header entry size
-  dq LIT, 1, PACK16                         ; number of program header entries
-  dq LIT, 0, PACK16                         ; section header entry size
-  dq LIT, 0, PACK16                         ; number of section header entries
-  dq LIT, 0, PACK16                         ; section name string table index
+  dq LITPACK64, 0                           ; section header offset
+  dq LITPACK32, 0                           ; processor flags
+  dq LITPACK16, 64                          ; ELF header size
+  dq LITPACK16, 56                          ; program header entry size
+  dq LITPACK16, 1                           ; number of program header entries
+  dq LITPACK16, 0                           ; section header entry size
+  dq LITPACK16, 0                           ; number of section header entries
+  dq LITPACK16, 0                           ; section name string table index
 
   dq EXIT
 
@@ -2219,18 +2269,18 @@ defword ELF_FILE_HEADER, 0
 defword ELF_PROGRAM_HEADER, 0
   dq DOCOL                       ; codeword
 
-  dq LIT, 1, PACK32                        ; "loadable" segment type
-  dq LIT, 0x05, PACK32                     ; read+execute permission
-  dq LIT, 0, PACK                          ; offset in file
-  dq LIT, $$, PACK                         ; virtual address
+  dq LITPACK32, 1                          ; "loadable" segment type
+  dq LITPACK32, 0x05                       ; read+execute permission
+  dq LITPACK64, 0                          ; offset in file
+  dq LITPACK64, $$                         ; virtual address
     ; required, but can be anything, subject to alignment
-  dq LIT, 0, PACK16                        ; physical address (ignored)
+  dq LITPACK16, 0                          ; physical address (ignored)
 
   ; Fill in 0 as the file size for now, to avoid unitialized memory.
-  dq LIT, 0, PACK                          ; size in file
-  dq LIT, 0, PACK                          ; size in memory
+  dq LITPACK64, 0                          ; size in file
+  dq LITPACK64, 0                          ; size in memory
 
-  dq LIT, 0, PACK                          ; segment alignment
+  dq LITPACK64, 0                          ; segment alignment
     ; for relocation, but this doesn't apply to us
 
   dq EXIT