From b4284df8e98265a2d6acb4e2c92894b72a5f5855 Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Sun, 26 Oct 2025 16:18:53 -0700 Subject: 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 --- quine.asm | 145 ++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 51 deletions(-) (limited to 'quine.asm') 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 -- cgit 1.4.1