2 # instruction effective address register displacement immediate
3 # . op subop mod rm32 base index scale r32
4 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
6 # If datum of 'word' is not a valid name, it must be a hex int. Parse and print
7 # it in 'width' bytes of hex, least significant first.
8 # Otherwise just print the entire word including metadata.
9 # Always print a trailing space.
10 emit: # out: (addr buffered-file), word: (addr slice), width: int
13 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
19 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
20 # var datum/edi: slice
23 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
24 # datum = next-token-from-slice(word->start, word->end, '/')
27 68/push 0x2f/imm32/slash
28 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
29 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
31 e8/call next-token-from-slice/disp32
33 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
34 # if (valid-name?(datum)) write-slice-buffered(out, word) and return
35 # . eax = valid-name?(name)
39 e8/call valid-name?/disp32
41 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
43 3d/compare-eax-and 0/imm32/false
44 74/jump-if-= $emit:hex-int/disp8
46 # . write-slice-buffered(out, word)
49 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
51 e8/call write-slice-buffered/disp32
53 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
54 # . write-buffered(out, " ")
57 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
59 e8/call write-buffered/disp32
61 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
63 eb/jump $emit:end/disp8
64 # otherwise emit-hex(out, parse-hex-int-from-slice(datum), width)
65 # (Weird shit can happen here if the datum of 'word' isn't either a valid
66 # name or a hex number. `emit` is mostly used by translate_subx, which
67 # is currently designed to only receive legal SubX programs. We just
68 # want to make sure that valid names aren't treated as (valid) hex
71 # . var value/eax: int = parse-hex-int-from-slice(datum)
75 e8/call parse-hex-int-from-slice/disp32
77 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
78 # . emit-hex(out, value, width)
80 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
82 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
84 e8/call emit-hex/disp32
86 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
89 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
95 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
102 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
104 # . clear-stream(_test-output-stream)
106 68/push _test-output-stream/imm32
108 e8/call clear-stream/disp32
110 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
111 # . clear-stream($_test-output-buffered-file->buffer)
113 68/push $_test-output-buffered-file->buffer/imm32
115 e8/call clear-stream/disp32
117 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
119 b8/copy-to-eax "30"/imm32
120 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
121 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
122 05/add-to-eax 4/imm32
123 # var slice/ecx: slice = {eax, ecx}
126 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
127 # emit(_test-output-buffered-file, slice, 1)
131 68/push _test-output-buffered-file/imm32
135 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
136 # flush(_test-output-buffered-file)
138 68/push _test-output-buffered-file/imm32
142 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
143 # check-stream-equal(_test-output-stream, "30 ", msg)
145 68/push "F - test-emit-number/1"/imm32
147 68/push _test-output-stream/imm32
149 e8/call check-stream-equal/disp32
151 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
153 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
157 test-emit-negative-number:
158 # test support for sign-extending negative numbers
161 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
163 # . clear-stream(_test-output-stream)
165 68/push _test-output-stream/imm32
167 e8/call clear-stream/disp32
169 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
170 # . clear-stream($_test-output-buffered-file->buffer)
172 68/push $_test-output-buffered-file->buffer/imm32
174 e8/call clear-stream/disp32
176 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
178 b8/copy-to-eax "-2"/imm32
179 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
180 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
181 05/add-to-eax 4/imm32
182 # var slice/ecx: slice = {eax, ecx}
185 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
186 # emit(_test-output-buffered-file, slice, 2)
190 68/push _test-output-buffered-file/imm32
194 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
195 # flush(_test-output-buffered-file)
197 68/push _test-output-buffered-file/imm32
201 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
202 # check-stream-equal(_test-output-stream, "fe ff ", msg)
204 68/push "F - test-emit-number/1"/imm32
205 68/push "fe ff "/imm32
206 68/push _test-output-stream/imm32
208 e8/call check-stream-equal/disp32
210 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
212 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
216 test-emit-number-with-metadata:
219 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
221 # . clear-stream(_test-output-stream)
223 68/push _test-output-stream/imm32
225 e8/call clear-stream/disp32
227 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
228 # . clear-stream($_test-output-buffered-file->buffer)
230 68/push $_test-output-buffered-file->buffer/imm32
232 e8/call clear-stream/disp32
234 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
235 # (eax..ecx) = "-2/foo"
236 b8/copy-to-eax "-2/foo"/imm32
237 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
238 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
239 05/add-to-eax 4/imm32
240 # var slice/ecx: slice = {eax, ecx}
243 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
244 # emit(_test-output-buffered-file, slice, 2)
248 68/push _test-output-buffered-file/imm32
252 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
253 # flush(_test-output-buffered-file)
255 68/push _test-output-buffered-file/imm32
259 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
260 # the '/foo' will have no impact on the output
261 # check-stream-equal(_test-output-stream, "fe ff ", msg)
263 68/push "F - test-emit-number-with-metadata"/imm32
264 68/push "fe ff "/imm32
265 68/push _test-output-stream/imm32
267 e8/call check-stream-equal/disp32
269 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
271 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
275 test-emit-non-number:
278 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
280 # . clear-stream(_test-output-stream)
282 68/push _test-output-stream/imm32
284 e8/call clear-stream/disp32
286 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
287 # . clear-stream($_test-output-buffered-file->buffer)
289 68/push $_test-output-buffered-file->buffer/imm32
291 e8/call clear-stream/disp32
293 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
295 b8/copy-to-eax "xyz"/imm32
296 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
297 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
298 05/add-to-eax 4/imm32
299 # var slice/ecx: slice = {eax, ecx}
302 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
303 # emit(_test-output-buffered-file, slice, 2)
307 68/push _test-output-buffered-file/imm32
311 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
312 # flush(_test-output-buffered-file)
314 68/push _test-output-buffered-file/imm32
318 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
319 # check-stream-equal(_test-output-stream, "xyz", msg)
321 68/push "F - test-emit-non-number"/imm32
323 68/push _test-output-stream/imm32
325 e8/call check-stream-equal/disp32
327 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
329 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
333 test-emit-non-number-with-metadata:
336 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
338 # . clear-stream(_test-output-stream)
340 68/push _test-output-stream/imm32
342 e8/call clear-stream/disp32
344 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
345 # . clear-stream($_test-output-buffered-file->buffer)
347 68/push $_test-output-buffered-file->buffer/imm32
349 e8/call clear-stream/disp32
351 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
352 # (eax..ecx) = "xyz/"
353 b8/copy-to-eax "xyz/"/imm32
354 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
355 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
356 05/add-to-eax 4/imm32
357 # var slice/ecx: slice = {eax, ecx}
360 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
361 # emit(_test-output-buffered-file, slice, 2)
365 68/push _test-output-buffered-file/imm32
369 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
370 # flush(_test-output-buffered-file)
372 68/push _test-output-buffered-file/imm32
376 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
377 # check-stream-equal(_test-output-stream, "xyz/", msg)
379 68/push "F - test-emit-non-number-with-metadata"/imm32
380 68/push "xyz/ "/imm32
381 68/push _test-output-stream/imm32
383 e8/call check-stream-equal/disp32
385 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
387 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
391 test-emit-non-number-with-all-hex-digits-and-metadata:
394 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
396 # . clear-stream(_test-output-stream)
398 68/push _test-output-stream/imm32
400 e8/call clear-stream/disp32
402 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
403 # . clear-stream($_test-output-buffered-file->buffer)
405 68/push $_test-output-buffered-file->buffer/imm32
407 e8/call clear-stream/disp32
409 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
410 # (eax..ecx) = "abcd/xyz"
411 b8/copy-to-eax "abcd/xyz"/imm32
412 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
413 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
414 05/add-to-eax 4/imm32
415 # var slice/ecx: slice = {eax, ecx}
418 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
419 # emit(_test-output-buffered-file, slice, 2)
423 68/push _test-output-buffered-file/imm32
427 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
428 # flush(_test-output-buffered-file)
430 68/push _test-output-buffered-file/imm32
434 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
436 #? # . write(2/stderr, "^")
439 #? 68/push 2/imm32/stderr
441 #? e8/call write/disp32
442 #? # . . discard args
443 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
444 #? # . write-stream(2/stderr, _test-output-stream)
446 #? 68/push _test-output-stream/imm32
447 #? 68/push 2/imm32/stderr
449 #? e8/call write-stream/disp32
450 #? # . . discard args
451 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
452 #? # . write(2/stderr, "$\n")
454 #? 68/push "$\n"/imm32
455 #? 68/push 2/imm32/stderr
457 #? e8/call write/disp32
458 #? # . . discard args
459 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
461 # check-stream-equal(_test-output-stream, "abcd/xyz")
463 68/push "F - test-emit-non-number-with-all-hex-digits"/imm32
464 68/push "abcd/xyz "/imm32
465 68/push _test-output-stream/imm32
467 e8/call check-stream-equal/disp32
469 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
471 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp