diff options
author | Irene Knapp <ireneista@irenes.space> | 2025-10-11 18:11:34 -0700 |
---|---|---|
committer | Irene Knapp <ireneista@irenes.space> | 2025-10-11 18:11:34 -0700 |
commit | 4ccde781d12f3aa416aaa2f0f57de29d6e2f062b (patch) | |
tree | a12d1927a4ef05b8e3a2e05dc9c9829ecff531dd | |
parent | 825ae329d7106de1c457f91e4861d0164376a41a (diff) |
comment the code in preparation for restructuring it
Force-Push: yes Change-Id: I561d5fbb35db97b9d236a159c6c888b0651248c3
-rw-r--r-- | quine.asm | 97 |
1 files changed, 73 insertions, 24 deletions
diff --git a/quine.asm b/quine.asm index ab4f13a..b7904da 100644 --- a/quine.asm +++ b/quine.asm @@ -1,12 +1,25 @@ -; fasmg hello.asm hello && chmod 755 hello && ./hello; echo $? +; Currently, this is not yet fully self-hosting; it is based on +; flatassembler[1]. A minimal command to build and run it is: +; +; fasmg quine.asm quine && chmod 755 quine && ./quine; echo $? ; ; ***WARNING*** this version leaves the error message scrolled off the top of ; the screen and you see stale output ; fasmg quine.asm quine && ./quine > quine2; echo "exit code:" $?; echo; hexdump -C quine; echo; hexdump -C quine2; cmp quine quine2; echo; echo "compare:" $? ; ZydisDisasm -64 quine ; -; rm quine2; fasmg quine.asm quine && ./quine > quine2; echo "exit code:" $?; echo; hexdump -C quine; echo; hexdump -C quine2; echo; cmp quine quine2 ; echo $? - +; A workflow you may wish to use for debugging is: +; +; rm quine2; fasmg quine.asm quine && ./quine > quine2; echo "exit code:" $?; echo; hexdump -C quine; echo; hexdump -C quine2; echo; cmp quine quine2 ; echo cmp: $? +; +; You may also wish to do: +; +; objdump --disassemble quine +; ZydisDisasm -64 quine +; +; This relies on GNU binutils, and on zydis, respectively. +; +; [1] https://flatassembler.net/ macro rex.0 @@ -251,6 +264,7 @@ end macro org 0x08000000 + elf_header: ; * denotes mandatory fields according to breadbox db 0x7F, "ELF" ; *magic number @@ -292,11 +306,37 @@ program_header_entry_size = $ - program_header load_origin = 0x08000000 + +;;; Implementation strategy: +;;; +;;; We assemble the entire file contents in a stack-allocated buffer. +;;; We avoid using the stack for any other purpose. When the file is fully +;;; assembled, we output it. +;;; +;;; The assembly proceeds in several chunks - ELF header, program header, +;;; etc. Each chunk extends the buffer as per its own needs, by adjusting +;;; the stack pointer. All chunks also update a running total file size, +;;; which refers to how many bytes have actually been populated, not to the +;;; size of the buffer. +;;; +;;; Register usage: +;;; +;;; * rdx holds the total used file size so far. During hand-off between +;;; chunks, this size must be equal to the buffer size; within a chunk it +;;; may be less. +;;; +;;; * rsp points to the bottom of the buffer. +;;; _start: + ;;; + ;;; Initialize registers + ;;; mov.dreg.dimm rdx, 0 ; store running file size here sub.b rsp, 0xFF ; reserve stack space - ; ELF header + ;;; + ;;; ELF header + ;;; mov.rel.d rsp, 0x00, 0x7F bappend "ELF" ; magic number mov.rel.b rsp, 0x04, 2 ; 64-bit mov.rel.b rsp, 0x05, 1 ; little-endian @@ -325,7 +365,13 @@ _start: mov.rel.w rsp, 0x3c, 0 ; number of section header entries mov.rel.w rsp, 0x3e, 0 ; section name string table index - ; Program header + ; Add the size of the ELF header to the running total + mov.dreg.dimm rax, 0x40 + add.q rdx, rax + + ;;; + ;;; Program header + ;;; mov.rel.d rsp, 0x40, 1 ; "loadable" segment type mov.rel.d rsp, 0x44, 0x05 ; read+execute permission mov.rel.q.d rsp, 0x48, 0 ; offset in file @@ -340,21 +386,29 @@ _start: mov.rel.q.d rsp, 0x70, 0 ; segment alignment ; for relocation - will we be ASLR'd? - ; Add the size of the ELF header to the running total - mov.dreg.dimm rax, 0x78 + ; Add the size of the program header to the running total + mov.dreg.dimm rax, 0x38 add.q rdx, rax - ; Go back and fill in the file size now that we know it. - ; so notionally, let's pretend rdx is a variable that keeps track of file - ; size. we would do something to populate it, then we would add it to rax... - mov.qreg.qimm rax, 0x185 + ; Add the guessed, wrong size of the program + + ;;; Hardcode the size of the actual code chunk, since we don't yet have a + ;;; way to generate it. + ;;; + ;;; TODO of course, really we want to for-real track this + mov.qreg.qimm rax, 0x15a add.q rdx, rax - ; TODO of course, really we want to for-real track these + + ;;; + ;;; Go back and fill in the file size now that we know it. + ;;; mov.rel.q rsp, 0x60, rdx ; size in file mov.rel.q rsp, 0x68, rdx ; size in memory ; TODO it works for rax source but not yet for rdx - ;;; after the file size is populated, that's the entire ELF header. yay! + ;;; + ;;; The buffer is ready; output the file. + ;;; ; write() from stack-allocated buffer mov.b rax,1 @@ -363,28 +417,23 @@ _start: mov.qreg.qimm rdx, 0x78 syscall - ; write() hardcoded header + ; write() the machine code by using self-reference + ; + ; TODO do this in a "real" quine way mov.b rax, 1 mov.qreg.qimm rdi, 1 mov.qreg.qimm rsi, elf_header + 0x78 mov.qreg.qimm rdx, file_size - 0x78 syscall - ; write() greeting - mov.b rax, 1 - mov.qreg.qimm rdi, 2 - mov.qreg.qimm rsi, greeting - mov.qreg.qimm rdx, greeting_size - syscall + ;;; + ;;; Clean up. + ;;; ; exit() mov.b rax, 60 mov.b rdi, 0 syscall -greeting: - db "Hello, Irenes!", 0x0A -greeting_size = $ - greeting - file_size = $ - $$ |