From bda3f24bb893d79c8d772025c45eb79495d0ad58 Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Wed, 9 Sep 2026 02:16:04 -0700 Subject: check in the hex binary and commented hex-dump yes, wow, right? big milestone! doesn't work for evoke itself quite yet, but getting really close Force-Push: yes Change-Id: I1e836b85cf185db4aa835d2aa494a67585e60744 --- hex.hex | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 hex.hex (limited to 'hex.hex') diff --git a/hex.hex b/hex.hex new file mode 100644 index 0000000..1c30eae --- /dev/null +++ b/hex.hex @@ -0,0 +1,216 @@ +~ This file is a commented hexadecimal representation of a compiled +~ program, the output of Evocation's hex transform. The comments are +~ intended to allow a human reader to audit it. You can convert it to a +~ runnable executable by piping it through the program named 'hex' and +~ chmodding the output 755. The difference between a source and a binary +~ is comments! Enjoy. :) + +~ This particular program is 'hex' itself. You of course already need to +~ have a binary copy of it to use this file, but you may find it helpful +~ to have this hex dump anyway, to aid in auditing your binary. + + +~ ELF file header + ~ * denotes mandatory fields according to breadbox + 7f 45 4c 46 ~ *magic number + 02 ~ 64-bit + 01 ~ little-endian + 01 ~ ELF header format v1 + 00 ~ System-V ABI + 00 00 00 00 00 00 00 00 ~ (padding) + + 02 00 ~ *executable + 3e 00 ~ *Intel x86-64 + 01 00 00 00 ~ ELF format version + + 78 00 00 08 00 00 00 00 ~ *entry point + 40 00 00 00 00 00 00 00 ~ *program header offset + 00 00 00 00 00 00 00 00 ~ section header offset + 00 00 00 00 ~ processor flags + + 40 00 ~ ELF header size + 38 00 ~ *program header entry size + 01 00 ~ *number of program header entries + 00 00 ~ section header entry size + 00 00 ~ number of section header entries + 00 00 ~ section name string table index + +~ ELF program header + 01 00 00 00 ~ *"loadable" segment type + 07 00 00 00 ~ *read+write+execute permission + 00 00 00 00 00 00 00 00 ~ *offset in file + 00 00 00 08 00 00 00 00 ~ *virtual address + 00 00 00 00 00 00 00 00 ~ physical address (ignored) + + e0 01 00 00 00 00 00 00 ~ *size in file + e0 01 00 00 00 00 00 00 ~ *size in memory + + 00 00 00 00 00 00 00 00 ~ segment alignment + + +~ This is the start routine, the first thing that runs when the ELF loads. + ~ The basic registers preserved across syscalls are rbx, rsp, rbp. + ~ To avoid redundant moves, we store the buffer pointer in rbx just once, + ~ and keep it there. We've made sure our load origin fits in 32 bits, so + ~ we can use imm32 for that. We're going to want to do an indirect load + ~ from it, so we can't use rbp for this. + 48 c7 c3 d8 01 00 08 ~ 0x080001d8 :rbx mov-reg64-imm32 + + e8 88 00 00 00 ~ 0x00000088 call-rel-imm32 + + ~ If the length is 0, we got EOF. If it's less than zero, we got a read + ~ error. Either way, we exit. This is a signed comparison, as it needs to + ~ be. + 48 83 f8 00 ~ 0x00 :rax cmp-reg64-imm8 + 74 72 ~ 0x72 :cc-equal jmp-cc-rel-imm8 + 7c ee ~ 0xee :cc-less jmp-cc-rel-imm8 + + ~ Now that the length is handled, retrieve the input byte. + 48 8b 03 ~ :rbx :rax mov-reg64-indirect-reg64 + + ~ If it's space or linefeed, skip it (go back to the loop start). + 48 83 f8 20 ~ 0x20 :rax cmp-reg64-imm8 + ~ ASCII space + 74 ea ~ 0xffffffffffffffea :cc-equal jmp-cc-rel-imm8 + 48 83 f8 0a ~ 0x0a :rax cmp-reg64-imm8 + ~ ASCII linefeed + 74 e4 ~ 0xffffffffffffffe4 :cc-equal jmp-cc-rel-imm8 + ~ If it's a comment, skip the whole thing. + 48 83 f8 7e ~ 0x7e :rax cmp-reg64-imm8 + ~ ASCII tilde + 74 43 ~ 0x43 :cc-equal jmp-cc-rel-imm8 + + ~ Decode the value, or exit with an error. + e8 79 00 00 00 ~ 0x00000079 call-rel-imm32 + + ~ We use rbp as a place to stash the high nibble. + 48 89 c5 ~ :rax :rbp mov-reg64-reg64 + 48 c1 c5 04 ~ 0x04 :rbp rol-reg64-imm8 + + ~ Now we read another byte. + e8 5a 00 00 00 ~ 0x0000005a call-rel-imm32 + + ~ Handle the length. A second hex digit is required here. + 48 83 f8 00 ~ 0x00 :rax cmp-reg64-imm8 + 74 ac ~ 0xac :cc-equal jmp-cc-rel-imm8 + 7c c0 ~ 0xc0 :cc-less jmp-cc-rel-imm8 + + ~ Now that the length is handled, retrieve the input byte. + 48 8b 03 ~ :rbx :rax mov-reg64-indirect-reg64 + + ~ Decode the value, or exit with an error. + e8 5d 00 00 00 ~ 0x0000005d call-rel-imm32 + + ~ We OR in the low nibble. + 48 0b e8 ~ :rax :rbp or-reg64-reg64 + + ~ Output the byte. We reuse the buffer as a place to store it. + 48 89 2b ~ :rbx :rbp mov-indirect-reg64-reg64 + 48 89 de ~ :rbx :rsi mov-reg64-reg64 + ~ buffer pointer + 48 c7 c2 01 00 00 00 ~ 0x00000001 :rdx mov-reg64-imm32 + ~ buffer length + 48 c7 c0 01 00 00 00 ~ 0x00000001 :rax mov-reg64-imm32 + ~ syscall number for sys-write + 48 c7 c7 01 00 00 00 ~ 0x00000001 :rdi mov-reg64-imm32 + ~ file descriptor 1 is stdout + 0f 05 ~ syscall + + ~ Back to the start of the loop. + eb 9b ~ 0xffffffffffffff9b jmp-rel-imm8 + + ~ Read a byte for the comment. + e8 23 00 00 00 ~ 0x00000023 call-rel-imm32 + + ~ Handle the length. We're allowed to end in a comment. + 48 83 f8 00 ~ 0x00 :rax cmp-reg64-imm8 + 74 0d ~ 0x0d :cc-equal jmp-cc-rel-imm8 + 7c 89 ~ 0x89 :cc-less jmp-cc-rel-imm8 + + ~ Now that the length is handled, retrieve the input byte. + 48 8b 03 ~ :rbx :rax mov-reg64-indirect-reg64 + + ~ If it's linefeed, the comment is over. + 48 83 f8 0a ~ 0x0a :rax cmp-reg64-imm8 + ~ ASCII linefeed + 74 85 ~ 0xffffffffffffff85 :cc-equal jmp-cc-rel-imm8 + + ~ We're still in the comment, keep handling it. + eb e8 ~ 0xffffffffffffffe8 jmp-rel-imm8 + +~ This is the routine named "exit". + 48 c7 c0 3c 00 00 00 ~ 0x0000003c :rax mov-reg64-imm32 + ~ syscall number for sys-exit + 48 c7 c7 00 00 00 00 ~ 0x00000000 :rdi mov-reg64-imm32 + ~ exit code + 0f 05 ~ syscall + +~ This is the routine named "read-byte". + ~ We use self-xor as a concise way to set registers to zero. + 48 33 c0 ~ :rax :rax xor-reg64-reg64 + ~ syscall number for sys-read + 48 33 ff ~ :rdi :rdi xor-reg64-reg64 + ~ file descriptor 0 is stdin + 48 89 de ~ :rbx :rsi mov-reg64-reg64 + ~ buffer pointer + ~ We read one byte at a time, because it makes the loop structure simple. + 48 c7 c2 01 00 00 00 ~ 0x00000001 :rdx mov-reg64-imm32 + ~ buffer length + 0f 05 ~ syscall + c3 ~ ret + +~ This is the routine named "decode-nibble". + 48 83 e8 30 ~ 0x30 :rax sub-reg64-imm8 + ~ ASCII zero + 7c 29 ~ 0x29 :cc-less jmp-cc-rel-imm8 + 48 83 f8 0a ~ 0x0a :rax cmp-reg64-imm8 + 72 22 ~ 0x22 :cc-below jmp-cc-rel-imm8 + 48 83 e8 11 ~ 0x11 :rax sub-reg64-imm8 + ~ ASCII capital A + 7c 1d ~ 0x1d :cc-less jmp-cc-rel-imm8 + 48 83 c0 0a ~ 0x0a :rax add-reg64-imm8 + 48 83 f8 10 ~ 0x10 :rax cmp-reg64-imm8 + 72 12 ~ 0x12 :cc-below jmp-cc-rel-imm8 + 48 83 e8 2a ~ 0x2a :rax sub-reg64-imm8 + ~ ASCII lowercase a + 7c 0d ~ 0x0d :cc-less jmp-cc-rel-imm8 + 48 83 c0 0a ~ 0x0a :rax add-reg64-imm8 + 48 83 f8 10 ~ 0x10 :rax cmp-reg64-imm8 + 72 02 ~ 0x02 :cc-below jmp-cc-rel-imm8 + eb 01 ~ 0x01 jmp-rel-imm8 + c3 ~ ret + + +~ These are the error handler routines. + 48 be ae 01 00 08 00 00 00 00 ~ 0x00000000080001ae :rsi mov-reg64-imm64 + 48 ba 0e 00 00 00 00 00 00 00 ~ 0x000000000000000e :rdx mov-reg64-imm64 + eb 2a ~ 0x2a jmp-rel-imm8 + 48 be c8 01 00 08 00 00 00 00 ~ 0x00000000080001c8 :rsi mov-reg64-imm64 + 48 ba 10 00 00 00 00 00 00 00 ~ 0x0000000000000010 :rdx mov-reg64-imm64 + eb 14 ~ 0x14 jmp-rel-imm8 + 48 be bc 01 00 08 00 00 00 00 ~ 0x00000000080001bc :rsi mov-reg64-imm64 + 48 ba 0c 00 00 00 00 00 00 00 ~ 0x000000000000000c :rdx mov-reg64-imm64 + 48 c7 c0 01 00 00 00 ~ 0x00000001 :rax mov-reg64-imm32 + ~ syscall number for sys-write + 48 c7 c7 02 00 00 00 ~ 0x00000002 :rdi mov-reg64-imm32 + ~ file descriptor 2 is stderr + 0f 05 ~ syscall + 48 c7 c0 3c 00 00 00 ~ 0x0000003c :rax mov-reg64-imm32 + ~ syscall number for sys-exit + 48 c7 c7 01 00 00 00 ~ 0x00000001 :rdi mov-reg64-imm32 + ~ exit code + 0f 05 ~ syscall + +~ These are the message strings. + ~ String literal with null terminator: "Invalid byte." + 49 6e 76 61 6c 69 64 20 62 79 74 65 2e 00 + ~ String literal with null terminator: "Read error." + 52 65 61 64 20 65 72 72 6f 72 2e 00 + ~ String literal with null terminator: "Unexpected EOF." + 55 6e 65 78 70 65 63 74 65 64 20 45 4f 46 2e 00 + +~ This is a buffer that's zero in the ELF, but is written to at runtime +~ and used as a variable. + 00 00 00 00 00 00 00 00 + +~ This is the end of the hex dump. -- cgit 1.4.1