summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2025-10-05 14:36:54 -0700
committerIrene Knapp <ireneista@irenes.space>2025-10-05 14:36:54 -0700
commit8f94834e451cf7ae7cccb5522562b3dea3754039 (patch)
tree2d0be73cde7abfb1767c8720226d9ccc072de57d
parent95ef9dbac33a46432b4ae4b5028d2538e9c4bfa9 (diff)
yay the earliest examples are in a solid state
Force-Push: yes
Change-Id: I7111b9a9ed3cb5c5cf162af336b2278cf5850b76
-rw-r--r--exit-code.S27
-rw-r--r--exit-code.asm2
-rw-r--r--quine.asm109
3 files changed, 137 insertions, 1 deletions
diff --git a/exit-code.S b/exit-code.S
new file mode 100644
index 0000000..4c723e8
--- /dev/null
+++ b/exit-code.S
@@ -0,0 +1,27 @@
+/*
+ * This file was a very early example, written by consulting [1]. It was
+ * useful primarily to see how the GNU assembler handles these opcodes, to
+ * better understand the encoding.
+ *
+ * [1] https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
+ *
+ *
+ * gcc -o quine -nostartfiles -nostdlib quine.S && ./quine ; echo $?
+ *
+ * or
+ *
+ * as -o quine.o quine.S && ld -s -o quine quine.o && ./quine; echo $?
+ *
+ * Can't use nasm, nasm is 32-bit only.
+ */
+.text
+
+.global _start
+
+_start:
+        //mov $60, %rax
+        //mov $42, %rdi
+        mov $60, %eax
+        mov $42, %edi
+        syscall
+
diff --git a/exit-code.asm b/exit-code.asm
index 05a8965..498bfc4 100644
--- a/exit-code.asm
+++ b/exit-code.asm
@@ -1,4 +1,4 @@
-; fasmg quine.asm quine
+; fasmg exit-code.asm exit-code
 
 macro mov.d target, source
   match =rax?, target
diff --git a/quine.asm b/quine.asm
new file mode 100644
index 0000000..9823d93
--- /dev/null
+++ b/quine.asm
@@ -0,0 +1,109 @@
+; fasmg quine.asm quine
+
+macro mov.d target, source
+  match =eax?, target
+    db 0xB8
+    dd source
+  else match =edi?, target
+    db 0xBF
+    dd source
+  else match =rax?, target
+    db 0x48, 0xC7, 0xC0
+;   48                           eAX REX.W prefix
+;                                    (DEC is the 32-bit meaning, ignore it)
+;                                    eAX -> register identifier,
+;                                           width depends on operand
+;                                    REX.W -> set 64-bit operand mode
+;           c7                    Grp 11^1A - MOV Ev, Iz
+;                                    immediate to register
+;                                    1A -> bits 5,4,3 of ModR/M are opcode
+;                                          extension
+;                                    E -> modR/M byte to follow for operand
+;                                    v -> word of appropriate size
+;                                    I -> immediate data
+;                                    z -> 32-bit operand
+;              c0                ModR/M byte
+;              0b11000000
+;                11               mod: always 11
+;                  000            op/reg: Mov Ev, Iz
+;                     00x         w absent
+;                       0         w (ignored)
+    dd source
+  else match =rdi, target
+    db 0x48, 0xC7, 0xC7
+;   7:   48 c7 c7 2a 00 00 00    mov    $0x2a,%rdi
+;   48                           eAX REX.W prefix
+;                                    (DEC is the 32-bit meaning, ignore it)
+;           c7                   Grp 11^1A - MOV Ev, Iz
+;                                    immediate to register
+;                                    1A -> bits 5,4,3 of ModR/M are opcode
+;                                          extension
+;                                    Ev -> ModR/M to follow for 32-bit operand
+;                                    Iz -> Immediate data, 32-bits
+;              c7                ModR/M byte
+;              0b11000111
+;                11               mod: always 11
+;                  000            op/reg: Mov Ev, Iz
+;                     11x         w present
+;                       1         w true; use EDI
+    dd source
+  end match
+end macro
+
+macro syscall
+  db 0x0F, 0x05
+;        0f                      two-byte escape
+;           05                   syscall ^ o64
+end macro
+
+
+
+
+org 0x08048000
+
+elf_header:
+; * denotes mandatory fields according to breadbox
+  db 0x7F, "ELF"                 ; *magic number
+  db 2                           ; 64-bit
+  db 1                           ; little-endian
+  db 1                           ; ELF header format version 1
+  db 0                           ; System-V ABI
+  db 8 dup 0                     ; (padding)
+
+  dw 2                           ; *executable
+  dw 0x3E                        ; *Intel x86-64
+  dd 1                           ; ELF format version
+
+  dq _start                      ; *entry point
+  dq program_header - $$         ; *program header offset
+  dq 0                           ; section header offset
+  dd 0                           ; processor flags
+  dw elf_header_size
+  dw program_header_entry_size   ; *
+  dw 1                           ; *number of program header entries
+  dw 0                           ; section header entry size
+  dw 0                           ; number of section header entries
+  dw 0                           ; section name string table index
+elf_header_size = $ - elf_header
+
+program_header:
+  dd 1                           ; *"loadable" segment type
+  dd 0x05                        ; *read+execute permission
+  dq 0                           ; *offset in file
+  dq $$                          ; *virtual address
+                                 ;   required, but can be anything, subject to
+                                 ;   alignment
+  dq 0                           ; physical address (ignored)
+  dq file_size                   ; *size in file
+  dq file_size                   ; *size in memory
+  dq 0                           ; segment alignment
+                                 ;   for relocation - will we be ASLR'd?
+program_header_entry_size = $ - program_header
+
+_start:
+  mov.d eax, 60
+  mov.d edi, 42
+  syscall
+
+file_size = $ - $$
+