summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2025-10-26 16:18:53 -0700
committerIrene Knapp <ireneista@irenes.space>2025-10-26 16:18:53 -0700
commitb4284df8e98265a2d6acb4e2c92894b72a5f5855 (patch)
tree6f2ed4a43fa233a86c2261c96bc7760a69c815b5
parent48bb1a77f3232e365f1becbb5313fb3240c8dc77 (diff)
move almost all the ELF stuff to code writen in Forth
wow, this sure does balloon the file size. must be something we can do about that...

Force-Push: yes
Change-Id: I477c4fdc9b42c3e5d50654d2864e3933da65a64d
-rw-r--r--quine.asm145
1 files changed, 94 insertions, 51 deletions
diff --git a/quine.asm b/quine.asm
index a25e1c5..50f245f 100644
--- a/quine.asm
+++ b/quine.asm
@@ -2118,9 +2118,14 @@ defword QUINE, 0
   ; ... and now we have allocated a block of memory, with its address on the
   ; stack. We also still have HEAP at the bottom of the stack, for future use.
 
-  ; This takes a buffer's address on the stack, populates it, then finishes by
-  ; pushing its length and address. Thus we don't need to care about how it
-  ; internally uses registers.
+  ; This takes a buffer's address on the stack and adds an ELF file header to
+  ; it, leaving nothing on the stack afterwards.
+  dq DUP, ELF_FILE_HEADER, ELF_PROGRAM_HEADER, DROP
+
+  ; This takes a buffer's address on the stack, skips an ELF file header based
+  ; on hardcoded size, appends an ELF program header, then finishes by pushing
+  ; the length of the part of the buffer that has now been used. Thus we don't
+  ; need to care about how it internally uses registers.
   dq DUP, OLD_CODE, SWAP
 
   ; write() from stack-allocated buffer
@@ -2145,6 +2150,92 @@ defword WRITE_SELF_RAW_H, 0
   NEXT
 
 
+; In: base address, value
+; Out: new base address
+defword PACK, 0
+  dq DOCOL                       ; codeword
+  dq SWAP, DUP, ROLLD3, STORE, LIT, 8, ADD
+  dq EXIT
+defword PACK8, 0
+  dq DOCOL                       ; codeword
+  dq SWAP, DUP, ROLLD3, STORE8, LIT, 1, ADD
+  dq EXIT
+defword PACK16, 0
+  dq DOCOL                       ; codeword
+  dq SWAP, DUP, ROLLD3, STORE16, LIT, 2, ADD
+  dq EXIT
+defword PACK32, 0
+  dq DOCOL                       ; codeword
+  dq SWAP, DUP, ROLLD3, STORE32, LIT, 4, ADD
+  dq EXIT
+
+
+;;;
+;;; ELF header
+;;;
+;;;   This is the top-level ELF header, for the entire file. An ELF always has
+;;; exactly one of this header, which is always at the start of the file.
+;;;
+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 LIT, 2, PACK16                         ; executable
+  dq LIT, 0x3e, PACK16                      ; Intel x86-64
+  dq LIT, 1, PACK32                         ; ELF format version
+
+  ; Compute the entry pointer.
+  dq LIT, _start, PACK                      ; entry point
+    ; The offset of _start. This includes the origin, intentionally.
+
+  dq LIT, 64, PACK                          ; 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 EXIT
+
+
+;;;
+;;; Program header
+;;;
+;;;   An ELF program header consists of any number of these entries; they are
+;;; always consecutive, but may be anywhere in the file. We always have
+;;; exactly one, and it's always right after the ELF file header.
+;;;
+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
+    ; required, but can be anything, subject to alignment
+  dq LIT, 0, PACK16                        ; 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 LIT, 0, PACK                          ; segment alignment
+    ; for relocation, but this doesn't apply to us
+
+  dq EXIT
+
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; (old) Implementation strategy ;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2179,58 +2270,10 @@ defword OLD_CODE, 0
   pop.qreg rcx                             ; our parameter - a block of memory
   mov.dreg.dimm rdx, 0                     ; store running file size here
 
-  ;;;
-  ;;; ELF header
-  ;;;
-  mov.qreg.disp8.dimm rcx, 0x00, 0x7F bappend "ELF"  ; magic number
-  mov.qreg.disp8.bimm rcx, 0x04, 2         ; 64-bit
-  mov.qreg.disp8.bimm rcx, 0x05, 1         ; little-endian
-  mov.qreg.disp8.bimm rcx, 0x06, 1         ; ELF header format version 1
-  mov.qreg.disp8.bimm rcx, 0x07, 0         ; System-V ABI
-  mov.qreg.disp8.dimm rcx, 0x08, 0         ; (padding)
-
-  mov.qreg.disp8.wimm rcx, 0x10, 2         ; executable
-  mov.qreg.disp8.wimm rcx, 0x12, 0x3E      ; Intel x86-64
-  mov.qreg.disp8.dimm rcx, 0x14, 1         ; ELF format version
-
-  ; Compute the entry pointer.
-  mov.qreg.qimm rax, _start                ; the offset of _start
-    ; This includes the origin, intentionally.
-  mov.qreg.disp8.qreg rcx, 0x18, rax       ; entry point
-
-  mov.qreg.disp8.dimm rcx, 0x20, 64        ; program header offset
-    ; We place the program header immediately after the ELF header. This
-    ; offset is from the start of the file.
-  mov.qreg.disp8.dimm rcx, 0x28, 0         ; section header offset
-  mov.qreg.disp8.dimm rcx, 0x30, 0         ; processor flags
-  mov.qreg.disp8.wimm rcx, 0x34, 64        ; ELF header size
-  mov.qreg.disp8.wimm rcx, 0x36, 56        ; program header entry size
-  mov.qreg.disp8.wimm rcx, 0x38, 1         ; number of program header entries
-  mov.qreg.disp8.wimm rcx, 0x3a, 0         ; section header entry size
-  mov.qreg.disp8.wimm rcx, 0x3c, 0         ; number of section header entries
-  mov.qreg.disp8.wimm rcx, 0x3e, 0         ; section name string table index
-
   ; Add the size of the ELF header to the running total
   mov.dreg.dimm rax, 0x40
   add.qreg.qreg rdx, rax
 
-  ;;;
-  ;;; Program header
-  ;;;
-  mov.qreg.disp8.dimm rcx, 0x40, 1         ; "loadable" segment type
-  mov.qreg.disp8.dimm rcx, 0x44, 0x05      ; read+execute permission
-  mov.qreg.disp8.dimm rcx, 0x48, 0         ; offset in file
-  mov.qreg.disp8.dimm rcx, 0x50, $$        ; virtual address
-    ; required, but can be anything, subject to alignment
-  mov.qreg.disp8.dimm rcx, 0x58, 0         ; physical address (ignored)
-
-  ; Fill in 0 as the file size for now, to avoid unitialized memory.
-  mov.qreg.disp8.dimm rcx, 0x60, 0         ; size in file
-  mov.qreg.disp8.dimm rcx, 0x68, 0         ; size in memory
-
-  mov.qreg.disp8.dimm rcx, 0x70, 0         ; segment alignment
-    ; for relocation, but this doesn't apply to us
-
   ; Add the size of the program header to the running total
   mov.dreg.dimm rax, 0x38
   add.qreg.qreg rdx, rax