about summary refs log tree commit diff
path: root/hex.hex
blob: 6e627e9a04ae5d78813955027041432d37f4b8f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
~   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
  ~ label elf-program-header at offset 0x0000000000000040 is here.
  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.
  ~ label cold-start at offset 0x0000000000000078 is here.
  ~   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              ~ 0x80001d8 :rbx mov-reg64-imm32

  ~ label input-loop-start at offset 0x000000000000007f is here.
  e8 88 00 00 00                    ~ 0x88 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                       ~ 0x0 :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                       ~ 0xa :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                    ~ 0x79 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                       ~ 0x4 :rbp rol-reg64-imm8

  ~ Now we read another byte.
  e8 5a 00 00 00                    ~ 0x5a call-rel-imm32

  ~ Handle the length. A second hex digit is required here.
  48 83 f8 00                       ~ 0x0 :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                    ~ 0x5d 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                          ~ :rbp :rbx mov-indirect-reg64-reg64
  48 89 de                          ~ :rbx :rsi mov-reg64-reg64
                                    ~ buffer pointer
  48 c7 c2 01 00 00 00              ~ 0x1 :rdx mov-reg64-imm32
                                    ~ buffer length
  48 c7 c0 01 00 00 00              ~ 0x1 :rax mov-reg64-imm32
                                    ~ syscall number for sys-write
  48 c7 c7 01 00 00 00              ~ 0x1 :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

  ~ label skip-comment at offset 0x00000000000000e4 is here.
  ~ Read a byte for the comment.
  e8 23 00 00 00                    ~ 0x23 call-rel-imm32

  ~ Handle the length. We're allowed to end in a comment.
  48 83 f8 00                       ~ 0x0 :rax cmp-reg64-imm8
  74 0d                             ~ 0xd :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                       ~ 0xa :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".
  ~ label exit at offset 0x00000000000000fc is here.
  48 c7 c0 3c 00 00 00              ~ 0x3c :rax mov-reg64-imm32
                                    ~ syscall number for sys-exit
  48 c7 c7 00 00 00 00              ~ 0x0 :rdi mov-reg64-imm32
                                    ~ exit code
  0f 05                             ~ syscall

~ This is the routine named "read-byte".
  ~ label read-byte at offset 0x000000000000010c is here.
  ~ 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              ~ 0x1 :rdx mov-reg64-imm32
                                    ~ buffer length
  0f 05                             ~ syscall
  c3                                ~ ret

~ This is the routine named "decode-nibble".
  ~ label decode-nibble at offset 0x000000000000011f is here.
  48 83 e8 30                       ~ 0x30 :rax sub-reg64-imm8
                                    ~ ASCII zero
  7c 29                             ~ 0x29 :cc-less jmp-cc-rel-imm8
  48 83 f8 0a                       ~ 0xa :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                       ~ 0xa :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                             ~ 0xd :cc-less jmp-cc-rel-imm8
  48 83 c0 0a                       ~ 0xa :rax add-reg64-imm8
  48 83 f8 10                       ~ 0x10 :rax cmp-reg64-imm8
  72 02                             ~ 0x2 :cc-below jmp-cc-rel-imm8
  eb 01                             ~ 0x1 jmp-rel-imm8
  ~ label got-nibble at offset 0x000000000000014d is here.
  c3                                ~ ret


~ These are the error handler routines.
  ~ label invalid-byte at offset 0x000000000000014e is here.
  48 be ae 01 00 08 00 00 00 00     ~ 0x80001ae :rsi mov-reg64-imm64
  48 ba 0e 00 00 00 00 00 00 00     ~ 0xe :rdx mov-reg64-imm64
  eb 2a                             ~ 0x2a jmp-rel-imm8
  ~ label unexpected-eof at offset 0x0000000000000164 is here.
  48 be c8 01 00 08 00 00 00 00     ~ 0x80001c8 :rsi mov-reg64-imm64
  48 ba 10 00 00 00 00 00 00 00     ~ 0x10 :rdx mov-reg64-imm64
  eb 14                             ~ 0x14 jmp-rel-imm8
  ~ label read-error at offset 0x000000000000017a is here.
  48 be bc 01 00 08 00 00 00 00     ~ 0x80001bc :rsi mov-reg64-imm64
  48 ba 0c 00 00 00 00 00 00 00     ~ 0xc :rdx mov-reg64-imm64
  ~ label exit-with-error at offset 0x000000000000018e is here.
  48 c7 c0 01 00 00 00              ~ 0x1 :rax mov-reg64-imm32
                                    ~ syscall number for sys-write
  48 c7 c7 02 00 00 00              ~ 0x2 :rdi mov-reg64-imm32
                                    ~ file descriptor 2 is stderr
  0f 05                             ~ syscall
  48 c7 c0 3c 00 00 00              ~ 0x3c :rax mov-reg64-imm32
                                    ~ syscall number for sys-exit
  48 c7 c7 01 00 00 00              ~ 0x1 :rdi mov-reg64-imm32
                                    ~ exit code
  0f 05                             ~ syscall

~ These are the message strings.
  ~ label invalid-byte-message at offset 0x00000000000001ae is here.
  ~ "Invalid byte."   (string literal with null)
  49 6e 76 61 6c 69 64 20 62 79 74 65 2e 00
  ~ label read-error-message at offset 0x00000000000001bc is here.
  ~ "Read error."   (string literal with null)
  52 65 61 64 20 65 72 72 6f 72 2e 00
  ~ label unexpected-eof-message at offset 0x00000000000001c8 is here.
  ~ "Unexpected EOF."   (string literal with null)
  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.
  ~ label buffer at offset 0x00000000000001d8 is here.
  00 00 00 00 00 00 00 00
~ label total-size at offset 0x00000000000001e0 is here.

~ This is the end of the hex dump.