summary refs log tree commit diff
path: root/quine.asm
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2025-10-19 05:35:09 -0700
committerIrene Knapp <ireneista@irenes.space>2025-10-19 05:35:09 -0700
commit8c9157ba5a54f3ab08c2082864da9395f99dad94 (patch)
tree74af78a584e438156e3d2e117d254006b6d0cf8d /quine.asm
parent6b143324786cc25e00dc4cafcfe9ad9ef1ccae06 (diff)
rename a bunch of instructions HEAD main
this is just cleanup. once they're all named in a uniform way, it will make sense to write higher-level wrappers around them...

Force-Push: yes
Change-Id: Id110111d7cd0bf936de8f101cf6886513e1cca84
Diffstat (limited to 'quine.asm')
-rw-r--r--quine.asm114
1 files changed, 65 insertions, 49 deletions
diff --git a/quine.asm b/quine.asm
index 7e15a51..3b6df78 100644
--- a/quine.asm
+++ b/quine.asm
@@ -14,7 +14,7 @@
 ;;;
 ;;; 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: $?
+;;; rm quine2; fasmg quine.asm quine && ./quine > quine2; echo "exit code:" $?; echo; hexdump -C quine; echo; hexdump -C quine2; echo; cmp -l quine quine2 ; echo cmp: $?
 ;;;
 ;;; The reason this removes the old one first is that otherwise, there's a
 ;;; risk the error message will be scrolled off the top of the screen and
@@ -73,7 +73,7 @@ end macro
 macro qwordreg result, register
   match =rax?, register
     result = 0
-  else match =rcx?, regiser
+  else match =rcx?, register
     result = 1
   else match =rdx?, register
     result = 2
@@ -265,9 +265,7 @@ end macro
 ; This uses opcode 0xC6, which has w = 0. Since we run in 64-bit mode, that
 ; makes the operand size 8 bits, regardless of the current operand-size
 ; attribute. [Intel] volume 2D, appendix B, section B-1.4.3, table B-6.
-;
-; TODO this should be mov.(something).disp8
-macro mov.rel.b target, offset, source
+macro mov.qreg.disp8.bimm target, offset, source
   match =rsp, target
     db 0xC6
     modrm 1, 0, 4
@@ -286,7 +284,7 @@ end macro
 ; us an operand size of 32 bits by default. [Intel] volume 1, section 3.6.1,
 ; table 3-4. We want a 16-bit operand, so we use the operand-size prefix,
 ; 0x66, and we leave REX.W unset.
-macro mov.rel.w target, offset, source
+macro mov.qreg.disp8.wimm target, offset, source
   match =rsp, target
     db 0x66
     db 0xC7
@@ -305,7 +303,7 @@ end macro
 ; This uses opcode 0x67, which has w = 1. We run in 64-bit mode, so that gives
 ; us an operand size of 32 by default. [Intel] volume 2D, section B.1.43,
 ; table B-6. This is what we want, so we leave it.
-macro mov.rel.d target, offset, source
+macro mov.qreg.disp8.dimm target, offset, source
   match =rsp, target
     db 0xC7
     modrm 1, 0, 4
@@ -321,7 +319,7 @@ end macro
 ; register, with an 8-bit displacement and no indexing.
 ;
 ; This uses opcode 0x89.
-macro mov.rel.q target, offset, source
+macro mov.qreg.disp8.qreg target, offset, source
   match =rsp, target
     qwordreg sreg, source
     rex.w
@@ -343,7 +341,7 @@ end macro
 ; gives us an operand size of 32 by default. [Intel] volume 2D,
 ; section B.1.43, table B-6. We want a 64-bit operand, so we use the REX.W
 ; prefix, 0x48.
-macro mov.rel.q.d target, offset, source
+macro mov.qreg.disp8.dimm target, offset, source
   match =rsp, target
     rex.w
     db 0xC7
@@ -682,9 +680,32 @@ DOCOL:
   mov.qreg.qreg rsi, rax
   NEXT
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Implementation strategy ;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Routine _start
+;;; --------------
+;;;
+;;;   This is the entry point of the whole program, the very first code we
+;;; actually execute. We go with the name linkers generally use for it, though
+;;; it's not very Forth-y. The ELF header points to it.
+;;;
+;;;   The kernel gives us most registers zeroed, and rsp pointing to the
+;;; command-line stuff (argc, argv, envp), which is at an ASLR'd address with
+;;; some stack space allocated for us, despite the fact we didn't request any.
+;;; It also gives us all the flags clear except IF, but we don't rely on that.
+;;; Lastly, of course, it loads our code segment and sets the instruction
+;;; pointer where we asked; we don't need to check what those addresses are,
+;;; because they're not randomized.
+;;;
+;;;   This routine is really only responsible for one-time initialization.
+;;;
+_start:
+  cld                                      ; clear the DF flag
+  ; If we wanted to save the initial stack pointer, we'd do that here.
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; (old) 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
@@ -704,45 +725,40 @@ DOCOL:
 ;;;
 ;;; * rsp points to the bottom of the buffer.
 ;;;
-_start:
-  ;;;
-  ;;; Initialize registers
-  ;;;
-  cld                                      ; clear the DF flag
   mov.dreg.dimm rdx, 0                     ; store running file size here
-  sub.qreg.bimm rsp, 0xFF                  ; reserve stack space
+  ;sub.qreg.bimm rsp, 0xFF                  ; reserve stack space
 
   ;;;
   ;;; 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
-  mov.rel.b rsp, 0x06, 1                   ; ELF header format version 1
-  mov.rel.b rsp, 0x07, 0                   ; System-V ABI
-  mov.rel.q.d rsp, 0x08, 0                 ; (padding)
+  mov.qreg.disp8.dimm rsp, 0x00, 0x7F bappend "ELF"  ; magic number
+  mov.qreg.disp8.bimm rsp, 0x04, 2         ; 64-bit
+  mov.qreg.disp8.bimm rsp, 0x05, 1         ; little-endian
+  mov.qreg.disp8.bimm rsp, 0x06, 1         ; ELF header format version 1
+  mov.qreg.disp8.bimm rsp, 0x07, 0         ; System-V ABI
+  mov.qreg.disp8.dimm rsp, 0x08, 0         ; (padding)
 
-  mov.rel.w rsp, 0x10, 2                   ; executable
-  mov.rel.w rsp, 0x12, 0x3E                ; Intel x86-64
-  mov.rel.d rsp, 0x14, 1                   ; ELF format version
+  mov.qreg.disp8.wimm rsp, 0x10, 2         ; executable
+  mov.qreg.disp8.wimm rsp, 0x12, 0x3E      ; Intel x86-64
+  mov.qreg.disp8.dimm rsp, 0x14, 1         ; ELF format version
 
   ; Compute the entry pointer.
   mov.qreg.qimm rax, $$                    ; the memory origin
   add.qreg.bimm rax, 0x78                  ; the size of the headers
   add.qreg.dimm rax, 155                   ; the offset of _start
-  mov.rel.q rsp, 0x18, rax                 ; entry point
+  mov.qreg.disp8.qreg rsp, 0x18, rax       ; entry point
 
-  mov.rel.q.d rsp, 0x20, 64                ; program header offset
+  mov.qreg.disp8.dimm rsp, 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.rel.q.d rsp, 0x28, 0                 ; section header offset
-  mov.rel.d rsp, 0x30, 0                   ; processor flags
-  mov.rel.w rsp, 0x34, 64                  ; ELF header size
-  mov.rel.w rsp, 0x36, 56                  ; program header entry size
-  mov.rel.w rsp, 0x38, 1                   ; number of program header entries
-  mov.rel.w rsp, 0x3a, 0                   ; section header entry size
-  mov.rel.w rsp, 0x3c, 0                   ; number of section header entries
-  mov.rel.w rsp, 0x3e, 0                   ; section name string table index
+  mov.qreg.disp8.dimm rsp, 0x28, 0         ; section header offset
+  mov.qreg.disp8.dimm rsp, 0x30, 0         ; processor flags
+  mov.qreg.disp8.wimm rsp, 0x34, 64        ; ELF header size
+  mov.qreg.disp8.wimm rsp, 0x36, 56        ; program header entry size
+  mov.qreg.disp8.wimm rsp, 0x38, 1         ; number of program header entries
+  mov.qreg.disp8.wimm rsp, 0x3a, 0         ; section header entry size
+  mov.qreg.disp8.wimm rsp, 0x3c, 0         ; number of section header entries
+  mov.qreg.disp8.wimm rsp, 0x3e, 0         ; section name string table index
 
   ; Add the size of the ELF header to the running total
   mov.dreg.dimm rax, 0x40
@@ -751,19 +767,19 @@ _start:
   ;;;
   ;;; 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
-  mov.rel.q.d rsp, 0x50, $$                ; virtual address
+  mov.qreg.disp8.dimm rsp, 0x40, 1         ; "loadable" segment type
+  mov.qreg.disp8.dimm rsp, 0x44, 0x05      ; read+execute permission
+  mov.qreg.disp8.dimm rsp, 0x48, 0         ; offset in file
+  mov.qreg.disp8.dimm rsp, 0x50, $$        ; virtual address
     ; required, but can be anything, subject to alignment
-  mov.rel.q.d rsp, 0x58, 0                 ; physical address (ignored)
+  mov.qreg.disp8.dimm rsp, 0x58, 0         ; physical address (ignored)
 
   ; Fill in 0 as the file size for now, to avoid unitialized memory.
-  mov.rel.q.d rsp, 0x60, 0                 ; size in file
-  mov.rel.q.d rsp, 0x68, 0                 ; size in memory
+  mov.qreg.disp8.dimm rsp, 0x60, 0         ; size in file
+  mov.qreg.disp8.dimm rsp, 0x68, 0         ; size in memory
 
-  mov.rel.q.d rsp, 0x70, 0                 ; segment alignment
-    ;   for relocation - will we be ASLR'd?
+  mov.qreg.disp8.dimm rsp, 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
@@ -773,14 +789,14 @@ _start:
   ;;; way to generate it.
   ;;;
   ;;; TODO of course, really we want to for-real track this
-  mov.qreg.qimm rax, 0x200
+  mov.qreg.qimm rax, 0x201
   add.qreg.qreg rdx, rax
 
   ;;;
   ;;; 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
+  mov.qreg.disp8.qreg rsp, 0x60, rdx       ; size in file
+  mov.qreg.disp8.qreg rsp, 0x68, rdx       ; size in memory
 
   ;;;
   ;;; The buffer is ready; output the file.