1 # Syntax sugar for addressing modes that expand into /rm32 and other related
5 # $ bootstrap/bootstrap translate [012]*.subx subx-params.subx sigils.subx -o sigils
7 # We currently support the following notations:
10 # $ echo '%eax' | bootstrap/bootstrap run sigils
14 # $ echo '*eax' | bootstrap/bootstrap run sigils
18 # $ echo '*(eax+4)' | bootstrap/bootstrap run sigils
19 # 2/mod 0/rm32 4/disp32
22 # $ echo '*(eax+ecx)' | bootstrap/bootstrap run sigils
23 # 0/mod 4/rm32 0/base 1/index 0/scale
26 # $ echo '*(eax+ecx+4)' | bootstrap/bootstrap run sigils
27 # 2/mod 4/rm32 0/base 1/index 0/scale 4/disp32
30 # $ echo '*(eax+ecx<<2+4)' | bootstrap/bootstrap run sigils
31 # 2/mod 4/rm32 0/base 1/index 2/scale 4/disp32
34 # $ echo '*Foo' | bootstrap/bootstrap run sigils
35 # 0/mod 5/rm32/.disp32 Foo/disp32
39 # Addition isn't commutative here. Template must always be (base+index<<scale+disp),
40 # though some components are optional as described above.
41 # In particular, global variables like 'Foo' above don't support displacement
44 # No metadata allowed inside '*(...)'.
45 # Whitespace inside '*(...)' is ok. But not immediately after the '*' or '%'.
46 # We don't support conversions to floating-point registers. In particular, so
47 # far there's no %xmm1.
49 # The code generated is sub-optimal:
50 # - displacements are always disp32, even when disp8 will do
51 # - *(...esp...) always uses SIB arguments even when redundant
54 # instruction effective address register displacement immediate
55 # . op subop mod rm32 base index scale r32
56 # . 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
58 Entry: # run tests if necessary, convert stdin if not
60 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
63 # . Heap = new-segment(Heap-size)
66 ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size
68 e8/call new-segment/disp32
70 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
72 # - if argc > 1 and argv[1] == "test", then return run_tests()
73 # if (argc <= 1) goto interactive
74 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp
75 7e/jump-if-<= $subx-sigils-main:interactive/disp8
76 # if (!kernel-string-equal?(argv[1], "test")) goto interactive
77 # . eax = kernel-string-equal?(argv[1], "test")
80 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
82 e8/call kernel-string-equal?/disp32
84 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
85 # . if (eax == false) goto interactive
86 3d/compare-eax-and 0/imm32/false
87 74/jump-if-= $subx-sigils-main:interactive/disp8
89 e8/call run-tests/disp32
90 # syscall_exit(*Num-test-failures)
91 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx
92 eb/jump $subx-sigils-main:end/disp8
93 $subx-sigils-main:interactive:
94 # - otherwise convert stdin
95 # subx-sigils(Stdin, Stdout)
100 e8/call subx-sigils/disp32
102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
104 bb/copy-to-ebx 0/imm32
105 $subx-sigils-main:end:
106 e8/call syscall_exit/disp32
108 # error messages considered:
109 # *x + 34 -> error: base+disp addressing must be within '()'
110 subx-sigils: # in: (addr buffered-file), out: (addr buffered-file)
112 # var line: (stream byte 512)
115 # read-line-buffered(in, line)
116 # if (line->write == 0) break # end of file
118 # var word-slice = next-word-or-expression(line)
119 # if slice-empty?(word-slice) # end of line
121 # if slice-starts-with?(word-slice, "#") # comment
123 # if slice-starts-with?(word-slice, '%') # direct mode
124 # emit-direct-mode(out, word-slice)
125 # else if slice-starts-with?(word-slice, '*') # indirect mode
126 # if disp32-mode?(word-slice)
127 # emit-indirect-disp32(out, word-slice)
129 # base, index, scale, disp = parse-effective-address(word-slice)
130 # emit-indirect-mode(out, base, index, scale, disp)
131 # else if slice-starts-with?(word-slice, '+')
132 # abort("'+' only permitted within '*(...)'")
134 # write-slice-buffered(out, word-slice)
141 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
147 # var line/ecx: (stream byte 512)
148 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp
149 68/push 0x200/imm32/length
151 68/push 0/imm32/write
152 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
153 # var word-slice/edx: slice
155 68/push 0/imm32/start
156 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx
157 $subx-sigils:line-loop:
162 e8/call clear-stream/disp32
164 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
165 # read-line-buffered(in, line)
168 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
170 e8/call read-line-buffered/disp32
172 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
174 # if (line->write == 0) break
175 81 7/subop/compare 0/mod/indirect 1/rm32/ecx . . . . . 0/imm32 # compare *ecx
176 0f 84/jump-if-= $subx-sigils:break/disp32
177 $subx-sigils:word-loop:
178 # next-word-or-expression(line, word-slice)
183 e8/call next-word-or-expression/disp32
185 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
187 # if (slice-empty?(word-slice)) break
188 # . eax = slice-empty?(word-slice)
192 e8/call slice-empty?/disp32
194 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
195 # . if (eax != false) break
196 3d/compare-eax-and 0/imm32/false
197 0f 85/jump-if-!= $subx-sigils:next-line/disp32
198 $subx-sigils:check-for-comment:
199 # if (slice-starts-with?(word-slice, "#")) continue
200 # . start/ebx = word-slice->start
201 8b/copy 0/mod/indirect 2/rm32/edx . . . 3/r32/ebx . . # copy *edx to ebx
203 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
204 8a/copy-byte 0/mod/indirect 3/rm32/ebx . . . 0/r32/AL . . # copy byte at *ebx to AL
205 # . if (eax == '#') continue
206 3d/compare-eax-and 0x23/imm32/hash
207 74/jump-if-= $subx-sigils:word-loop/disp8
208 $subx-sigils:check-for-direct-mode:
209 # if (!slice-starts-with?(word-slice, "%")) goto next check
210 3d/compare-eax-and 0x25/imm32/percent
211 75/jump-if-!= $subx-sigils:check-for-indirect-mode/disp8
212 $subx-sigils:direct-mode:
213 #? # dump word-slice {{{
214 #? # . write(2/stderr, "w: ")
216 #? 68/push "w: "/imm32
217 #? 68/push 2/imm32/stderr
219 #? e8/call write/disp32
220 #? # . . discard args
221 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
222 #? # . clear-stream($Stderr->buffer)
224 #? 68/push $Stderr->buffer/imm32
226 #? e8/call clear-stream/disp32
227 #? # . . discard args
228 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
229 #? # . write-slice-buffered(Stderr, word-slice)
232 #? 68/push Stderr/imm32
234 #? e8/call write-slice-buffered/disp32
235 #? # . . discard args
236 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
239 #? 68/push Stderr/imm32
241 #? e8/call flush/disp32
242 #? # . . discard args
243 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
244 #? # . write(2/stderr, "$\n")
246 #? 68/push "$\n"/imm32
247 #? 68/push 2/imm32/stderr
249 #? e8/call write/disp32
250 #? # . . discard args
251 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
253 # emit-direct-mode(out, word-slice)
256 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
258 e8/call emit-direct-mode/disp32
260 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
262 e9/jump $subx-sigils:next-word/disp32
263 $subx-sigils:check-for-indirect-mode:
264 # if (!slice-starts-with?(word-slice, "*")) goto next check
265 3d/compare-eax-and 0x2a/imm32/asterisk
266 75/jump-if-!= $subx-sigils:check-for-invalid-addition/disp8
267 # if (!disp32-mode?(word-slice)) goto indirect mode
268 # . eax = disp32-mode?(word-slice)
272 e8/call disp32-mode?/disp32
274 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
275 # . if (eax == false) goto indirect mode
276 3d/compare-eax-and 0/imm32/false
277 74/jump-if-= $subx-sigils:indirect-mode/disp8
278 $subx-sigils:disp32-mode:
279 # emit-indirect-mode(out, word-slice)
282 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
284 e8/call emit-indirect-disp32/disp32
286 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
288 e9/jump $subx-sigils:next-word/disp32
289 $subx-sigils:indirect-mode:
295 # base/eax, index/ecx, scale/edx, disp/ebx = parse-effective-address(word-slice)
299 e8/call parse-effective-address/disp32
301 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
302 # emit-indirect-mode(out, base, index, scale, disp)
308 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
310 e8/call emit-indirect-mode/disp32
312 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
319 e9/jump $subx-sigils:next-word/disp32
320 $subx-sigils:check-for-invalid-addition:
321 # if (slice-starts-with?(word-slice, "+")) goto error1
322 3d/compare-eax-and 0x2b/imm32/plus
323 74/jump-if-= $subx-sigils:error1/disp8
324 $subx-sigils:check-for-invalid-left-shift:
325 # if (slice-starts-with?(word-slice, "<")) goto error1
326 3d/compare-eax-and 0x3c/imm32/less-than
327 74/jump-if-= $subx-sigils:error1/disp8
328 $subx-sigils:regular-word:
329 # write-slice-buffered(out, word-slice)
332 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
334 e8/call write-slice-buffered/disp32
336 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
338 $subx-sigils:next-word:
339 # write-buffered(out, " ")
342 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
344 e8/call write-buffered/disp32
346 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
348 e9/jump $subx-sigils:word-loop/disp32
349 $subx-sigils:next-line:
350 # write-buffered(out, "\n")
352 68/push Newline/imm32
353 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
355 e8/call write-buffered/disp32
357 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
359 e9/jump $subx-sigils:line-loop/disp32
363 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
367 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
370 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x214/imm32 # add to esp
371 # . restore registers
377 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
382 # print(stderr, "error: '" eax "' only permitted within '*(...)' in '" line "'")
383 # . write-buffered(Stderr, "error: '")
385 68/push "error: '"/imm32
388 e8/call write-buffered/disp32
390 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
391 # . write-byte-buffered(Stderr, eax)
396 e8/call write-byte-buffered/disp32
398 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
399 # . write-buffered(Stderr, "' only permitted within '*(...)' in '")
401 68/push "' only permitted within '*(...)' in '"/imm32
404 e8/call write-buffered/disp32
406 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
407 # . write-stream-data(Stderr, line)
412 e8/call write-stream-data/disp32
414 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
415 # . write-buffered(Stderr, "'")
420 e8/call write-buffered/disp32
422 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
429 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
431 bb/copy-to-ebx 1/imm32
432 e8/call syscall_exit/disp32
435 test-subx-sigils-passes-most-words-through:
438 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
440 # . clear-stream(_test-input-stream)
442 68/push _test-input-stream/imm32
444 e8/call clear-stream/disp32
446 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
447 # . clear-stream($_test-input-buffered-file->buffer)
449 68/push $_test-input-buffered-file->buffer/imm32
451 e8/call clear-stream/disp32
453 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
454 # . clear-stream(_test-output-stream)
456 68/push _test-output-stream/imm32
458 e8/call clear-stream/disp32
460 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
461 # . clear-stream($_test-output-buffered-file->buffer)
463 68/push $_test-output-buffered-file->buffer/imm32
465 e8/call clear-stream/disp32
467 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
469 # . write(_test-input-stream, "== abcd 0x1")
471 68/push "== abcd 0x1"/imm32
472 68/push _test-input-stream/imm32
476 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
477 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
479 68/push _test-output-buffered-file/imm32
480 68/push _test-input-buffered-file/imm32
482 e8/call subx-sigils/disp32
484 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
485 # check that the line just passed through
486 # . flush(_test-output-buffered-file)
488 68/push _test-output-buffered-file/imm32
492 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
493 #? # dump _test-output-stream {{{
494 #? # . write(2/stderr, "^")
497 #? 68/push 2/imm32/stderr
499 #? e8/call write/disp32
500 #? # . . discard args
501 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
502 #? # . write-stream(2/stderr, _test-output-stream)
504 #? 68/push _test-output-stream/imm32
505 #? 68/push 2/imm32/stderr
507 #? e8/call write-stream/disp32
508 #? # . . discard args
509 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
510 #? # . write(2/stderr, "$\n")
512 #? 68/push "$\n"/imm32
513 #? 68/push 2/imm32/stderr
515 #? e8/call write/disp32
516 #? # . . discard args
517 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
519 # . check-stream-equal(_test-output-stream, "== abcd 0x1 \n", msg)
521 68/push "F - test-subx-sigils-passes-most-words-through"/imm32
522 68/push "== abcd 0x1 \n"/imm32
523 68/push _test-output-stream/imm32
525 e8/call check-stream-equal/disp32
527 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
529 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
533 test-subx-sigils-direct-mode:
536 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
538 # . clear-stream(_test-input-stream)
540 68/push _test-input-stream/imm32
542 e8/call clear-stream/disp32
544 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
545 # . clear-stream($_test-input-buffered-file->buffer)
547 68/push $_test-input-buffered-file->buffer/imm32
549 e8/call clear-stream/disp32
551 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
552 # . clear-stream(_test-output-stream)
554 68/push _test-output-stream/imm32
556 e8/call clear-stream/disp32
558 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
559 # . clear-stream($_test-output-buffered-file->buffer)
561 68/push $_test-output-buffered-file->buffer/imm32
563 e8/call clear-stream/disp32
565 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
567 # . write(_test-input-stream, "ab %ecx")
569 68/push "ab %ecx"/imm32
570 68/push _test-input-stream/imm32
574 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
575 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
577 68/push _test-output-buffered-file/imm32
578 68/push _test-input-buffered-file/imm32
580 e8/call subx-sigils/disp32
582 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
583 # check that the line just passed through
584 # . flush(_test-output-buffered-file)
586 68/push _test-output-buffered-file/imm32
590 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
591 #? # dump _test-output-stream {{{
592 #? # . write(2/stderr, "^")
595 #? 68/push 2/imm32/stderr
597 #? e8/call write/disp32
598 #? # . . discard args
599 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
600 #? # . write-stream(2/stderr, _test-output-stream)
602 #? 68/push _test-output-stream/imm32
603 #? 68/push 2/imm32/stderr
605 #? e8/call write-stream/disp32
606 #? # . . discard args
607 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
608 #? # . write(2/stderr, "$\n")
610 #? 68/push "$\n"/imm32
611 #? 68/push 2/imm32/stderr
613 #? e8/call write/disp32
614 #? # . . discard args
615 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
617 # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg)
619 68/push "F - test-subx-sigils-direct-mode"/imm32
620 68/push "ab 3/mod/direct 0x00000001/rm32 \n"/imm32
621 68/push _test-output-stream/imm32
623 e8/call check-stream-equal/disp32
625 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
627 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
631 test-subx-sigils-direct-mode-with-metadata:
634 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
636 # . clear-stream(_test-input-stream)
638 68/push _test-input-stream/imm32
640 e8/call clear-stream/disp32
642 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
643 # . clear-stream($_test-input-buffered-file->buffer)
645 68/push $_test-input-buffered-file->buffer/imm32
647 e8/call clear-stream/disp32
649 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
650 # . clear-stream(_test-output-stream)
652 68/push _test-output-stream/imm32
654 e8/call clear-stream/disp32
656 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
657 # . clear-stream($_test-output-buffered-file->buffer)
659 68/push $_test-output-buffered-file->buffer/imm32
661 e8/call clear-stream/disp32
663 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
665 # . write(_test-input-stream, "ab %ecx/foo")
667 68/push "ab %ecx/foo"/imm32
668 68/push _test-input-stream/imm32
672 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
673 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
675 68/push _test-output-buffered-file/imm32
676 68/push _test-input-buffered-file/imm32
678 e8/call subx-sigils/disp32
680 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
681 # check that the line just passed through
682 # . flush(_test-output-buffered-file)
684 68/push _test-output-buffered-file/imm32
688 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
689 # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg)
691 68/push "F - test-subx-sigils-direct-mode-with-metadata"/imm32
692 68/push "ab 3/mod/direct 0x00000001/rm32 \n"/imm32
693 68/push _test-output-stream/imm32
695 e8/call check-stream-equal/disp32
697 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
699 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
703 test-subx-sigils-register-indirect-mode:
706 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
708 # . clear-stream(_test-input-stream)
710 68/push _test-input-stream/imm32
712 e8/call clear-stream/disp32
714 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
715 # . clear-stream($_test-input-buffered-file->buffer)
717 68/push $_test-input-buffered-file->buffer/imm32
719 e8/call clear-stream/disp32
721 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
722 # . clear-stream(_test-output-stream)
724 68/push _test-output-stream/imm32
726 e8/call clear-stream/disp32
728 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
729 # . clear-stream($_test-output-buffered-file->buffer)
731 68/push $_test-output-buffered-file->buffer/imm32
733 e8/call clear-stream/disp32
735 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
737 # . write(_test-input-stream, "ab *ecx")
739 68/push "ab *ecx"/imm32
740 68/push _test-input-stream/imm32
744 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
745 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
747 68/push _test-output-buffered-file/imm32
748 68/push _test-input-buffered-file/imm32
750 e8/call subx-sigils/disp32
752 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
753 # check that the line just passed through
754 # . flush(_test-output-buffered-file)
756 68/push _test-output-buffered-file/imm32
760 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
761 #? # dump _test-output-stream {{{
762 #? # . write(2/stderr, "^")
765 #? 68/push 2/imm32/stderr
767 #? e8/call write/disp32
768 #? # . . discard args
769 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
770 #? # . write-stream(2/stderr, _test-output-stream)
772 #? 68/push _test-output-stream/imm32
773 #? 68/push 2/imm32/stderr
775 #? e8/call write-stream/disp32
776 #? # . . discard args
777 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
778 #? # . write(2/stderr, "$\n")
780 #? 68/push "$\n"/imm32
781 #? 68/push 2/imm32/stderr
783 #? e8/call write/disp32
784 #? # . . discard args
785 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
787 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg)
789 68/push "F - test-subx-sigils-register-indirect-mode"/imm32
790 68/push "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
791 68/push _test-output-stream/imm32
793 e8/call check-stream-equal/disp32
795 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
797 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
801 test-subx-sigils-register-indirect-mode-with-metadata:
804 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
806 # . clear-stream(_test-input-stream)
808 68/push _test-input-stream/imm32
810 e8/call clear-stream/disp32
812 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
813 # . clear-stream($_test-input-buffered-file->buffer)
815 68/push $_test-input-buffered-file->buffer/imm32
817 e8/call clear-stream/disp32
819 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
820 # . clear-stream(_test-output-stream)
822 68/push _test-output-stream/imm32
824 e8/call clear-stream/disp32
826 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
827 # . clear-stream($_test-output-buffered-file->buffer)
829 68/push $_test-output-buffered-file->buffer/imm32
831 e8/call clear-stream/disp32
833 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
835 # . write(_test-input-stream, "ab *ecx/foo")
837 68/push "ab *ecx/foo"/imm32
838 68/push _test-input-stream/imm32
842 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
843 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
845 68/push _test-output-buffered-file/imm32
846 68/push _test-input-buffered-file/imm32
848 e8/call subx-sigils/disp32
850 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
851 # check that the line just passed through
852 # . flush(_test-output-buffered-file)
854 68/push _test-output-buffered-file/imm32
858 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
859 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg)
861 68/push "F - test-subx-sigils-register-indirect-mode-with-metadata"/imm32
862 68/push "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
863 68/push _test-output-stream/imm32
865 e8/call check-stream-equal/disp32
867 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
869 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
873 test-subx-sigils-register-indirect-mode-without-displacement:
876 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
878 # . clear-stream(_test-input-stream)
880 68/push _test-input-stream/imm32
882 e8/call clear-stream/disp32
884 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
885 # . clear-stream($_test-input-buffered-file->buffer)
887 68/push $_test-input-buffered-file->buffer/imm32
889 e8/call clear-stream/disp32
891 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
892 # . clear-stream(_test-output-stream)
894 68/push _test-output-stream/imm32
896 e8/call clear-stream/disp32
898 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
899 # . clear-stream($_test-output-buffered-file->buffer)
901 68/push $_test-output-buffered-file->buffer/imm32
903 e8/call clear-stream/disp32
905 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
907 # . write(_test-input-stream, "ab *(ecx)")
909 68/push "ab *(ecx)"/imm32
910 68/push _test-input-stream/imm32
914 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
915 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
917 68/push _test-output-buffered-file/imm32
918 68/push _test-input-buffered-file/imm32
920 e8/call subx-sigils/disp32
922 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
923 # check that the line just passed through
924 # . flush(_test-output-buffered-file)
926 68/push _test-output-buffered-file/imm32
930 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
931 #? # dump _test-output-stream {{{
932 #? # . write(2/stderr, "^")
935 #? 68/push 2/imm32/stderr
937 #? e8/call write/disp32
938 #? # . . discard args
939 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
940 #? # . write-stream(2/stderr, _test-output-stream)
942 #? 68/push _test-output-stream/imm32
943 #? 68/push 2/imm32/stderr
945 #? e8/call write-stream/disp32
946 #? # . . discard args
947 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
948 #? # . write(2/stderr, "$\n")
950 #? 68/push "$\n"/imm32
951 #? 68/push 2/imm32/stderr
953 #? e8/call write/disp32
954 #? # . . discard args
955 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
957 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 1/rm32 \n", msg)
959 68/push "F - test-subx-sigils-register-indirect-mode-without-displacement"/imm32
960 68/push "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
961 68/push _test-output-stream/imm32
963 e8/call check-stream-equal/disp32
965 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
967 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
971 test-subx-sigils-register-indirect-mode-with-displacement:
974 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
976 # . clear-stream(_test-input-stream)
978 68/push _test-input-stream/imm32
980 e8/call clear-stream/disp32
982 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
983 # . clear-stream($_test-input-buffered-file->buffer)
985 68/push $_test-input-buffered-file->buffer/imm32
987 e8/call clear-stream/disp32
989 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
990 # . clear-stream(_test-output-stream)
992 68/push _test-output-stream/imm32
994 e8/call clear-stream/disp32
996 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
997 # . clear-stream($_test-output-buffered-file->buffer)
999 68/push $_test-output-buffered-file->buffer/imm32
1001 e8/call clear-stream/disp32
1003 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1005 # . write(_test-input-stream, "ab *(ecx+4)")
1007 68/push "ab *(ecx+4)"/imm32
1008 68/push _test-input-stream/imm32
1010 e8/call write/disp32
1012 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1013 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
1015 68/push _test-output-buffered-file/imm32
1016 68/push _test-input-buffered-file/imm32
1018 e8/call subx-sigils/disp32
1020 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1021 # check that the line just passed through
1022 # . flush(_test-output-buffered-file)
1024 68/push _test-output-buffered-file/imm32
1026 e8/call flush/disp32
1028 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1029 #? # dump _test-output-stream {{{
1030 #? # . write(2/stderr, "^")
1032 #? 68/push "^"/imm32
1033 #? 68/push 2/imm32/stderr
1035 #? e8/call write/disp32
1036 #? # . . discard args
1037 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1038 #? # . write-stream(2/stderr, _test-output-stream)
1040 #? 68/push _test-output-stream/imm32
1041 #? 68/push 2/imm32/stderr
1043 #? e8/call write-stream/disp32
1044 #? # . . discard args
1045 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1046 #? # . write(2/stderr, "$\n")
1048 #? 68/push "$\n"/imm32
1049 #? 68/push 2/imm32/stderr
1051 #? e8/call write/disp32
1052 #? # . . discard args
1053 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1055 # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 1/rm32 4/disp32 \n", msg)
1057 68/push "F - test-subx-sigils-register-indirect-mode-with-displacement"/imm32
1058 68/push "ab 2/mod/*+disp32 0x00000001/rm32 0x00000004/disp32 \n"/imm32
1059 68/push _test-output-stream/imm32
1061 e8/call check-stream-equal/disp32
1063 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1065 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1070 test-subx-sigils-register-indirect-mode-with-sib-byte:
1073 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1075 # . clear-stream(_test-input-stream)
1077 68/push _test-input-stream/imm32
1079 e8/call clear-stream/disp32
1081 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1082 # . clear-stream($_test-input-buffered-file->buffer)
1084 68/push $_test-input-buffered-file->buffer/imm32
1086 e8/call clear-stream/disp32
1088 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1089 # . clear-stream(_test-output-stream)
1091 68/push _test-output-stream/imm32
1093 e8/call clear-stream/disp32
1095 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1096 # . clear-stream($_test-output-buffered-file->buffer)
1098 68/push $_test-output-buffered-file->buffer/imm32
1100 e8/call clear-stream/disp32
1102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1104 # . write(_test-input-stream, "ab *(ecx + edx<<3 + 4)")
1106 68/push "ab *(ecx + edx<<3 + 4)"/imm32
1107 68/push _test-input-stream/imm32
1109 e8/call write/disp32
1111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1112 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
1114 68/push _test-output-buffered-file/imm32
1115 68/push _test-input-buffered-file/imm32
1117 e8/call subx-sigils/disp32
1119 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1120 # check that the line just passed through
1121 # . flush(_test-output-buffered-file)
1123 68/push _test-output-buffered-file/imm32
1125 e8/call flush/disp32
1127 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1128 #? # dump _test-output-stream {{{
1129 #? # . write(2/stderr, "^")
1131 #? 68/push "^"/imm32
1132 #? 68/push 2/imm32/stderr
1134 #? e8/call write/disp32
1135 #? # . . discard args
1136 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1137 #? # . write-stream(2/stderr, _test-output-stream)
1139 #? 68/push _test-output-stream/imm32
1140 #? 68/push 2/imm32/stderr
1142 #? e8/call write-stream/disp32
1143 #? # . . discard args
1144 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1145 #? # . write(2/stderr, "$\n")
1147 #? 68/push "$\n"/imm32
1148 #? 68/push 2/imm32/stderr
1150 #? e8/call write/disp32
1151 #? # . . discard args
1152 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1154 # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale 4/disp32 \n", msg)
1156 68/push "F - test-subx-sigils-register-indirect-mode-with-sib-byte"/imm32
1157 68/push "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0x00000004/disp32 \n"/imm32
1158 68/push _test-output-stream/imm32
1160 e8/call check-stream-equal/disp32
1162 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1164 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1168 test-subx-sigils-register-indirect-mode-with-sib-byte-negative-displacement:
1171 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1173 # . clear-stream(_test-input-stream)
1175 68/push _test-input-stream/imm32
1177 e8/call clear-stream/disp32
1179 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1180 # . clear-stream($_test-input-buffered-file->buffer)
1182 68/push $_test-input-buffered-file->buffer/imm32
1184 e8/call clear-stream/disp32
1186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1187 # . clear-stream(_test-output-stream)
1189 68/push _test-output-stream/imm32
1191 e8/call clear-stream/disp32
1193 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1194 # . clear-stream($_test-output-buffered-file->buffer)
1196 68/push $_test-output-buffered-file->buffer/imm32
1198 e8/call clear-stream/disp32
1200 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1202 # . write(_test-input-stream, "ab *(ecx + edx<<3 - 4)")
1204 68/push "ab *(ecx + edx<<3 - 4)"/imm32
1205 68/push _test-input-stream/imm32
1207 e8/call write/disp32
1209 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1210 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
1212 68/push _test-output-buffered-file/imm32
1213 68/push _test-input-buffered-file/imm32
1215 e8/call subx-sigils/disp32
1217 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1218 # check that the line just passed through
1219 # . flush(_test-output-buffered-file)
1221 68/push _test-output-buffered-file/imm32
1223 e8/call flush/disp32
1225 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1226 #? # dump _test-output-stream {{{
1227 #? # . write(2/stderr, "^")
1229 #? 68/push "^"/imm32
1230 #? 68/push 2/imm32/stderr
1232 #? e8/call write/disp32
1233 #? # . . discard args
1234 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1235 #? # . write-stream(2/stderr, _test-output-stream)
1237 #? 68/push _test-output-stream/imm32
1238 #? 68/push 2/imm32/stderr
1240 #? e8/call write-stream/disp32
1241 #? # . . discard args
1242 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1243 #? # . write(2/stderr, "$\n")
1245 #? 68/push "$\n"/imm32
1246 #? 68/push 2/imm32/stderr
1248 #? e8/call write/disp32
1249 #? # . . discard args
1250 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1252 # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale -4/disp32 \n", msg)
1254 68/push "F - test-subx-sigils-register-indirect-mode-with-sib-byte-negative-displacement"/imm32
1255 68/push "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0xfffffffc/disp32 \n"/imm32
1256 68/push _test-output-stream/imm32
1258 e8/call check-stream-equal/disp32
1260 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1262 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1266 test-subx-sigils-indirect-mode-without-register:
1269 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1271 # . clear-stream(_test-input-stream)
1273 68/push _test-input-stream/imm32
1275 e8/call clear-stream/disp32
1277 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1278 # . clear-stream($_test-input-buffered-file->buffer)
1280 68/push $_test-input-buffered-file->buffer/imm32
1282 e8/call clear-stream/disp32
1284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1285 # . clear-stream(_test-output-stream)
1287 68/push _test-output-stream/imm32
1289 e8/call clear-stream/disp32
1291 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1292 # . clear-stream($_test-output-buffered-file->buffer)
1294 68/push $_test-output-buffered-file->buffer/imm32
1296 e8/call clear-stream/disp32
1298 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1300 # . write(_test-input-stream, "ab *Foo")
1302 68/push "ab *Foo"/imm32
1303 68/push _test-input-stream/imm32
1305 e8/call write/disp32
1307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1308 # subx-sigils(_test-input-buffered-file, _test-output-buffered-file)
1310 68/push _test-output-buffered-file/imm32
1311 68/push _test-input-buffered-file/imm32
1313 e8/call subx-sigils/disp32
1315 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1316 # check that the line just passed through
1317 # . flush(_test-output-buffered-file)
1319 68/push _test-output-buffered-file/imm32
1321 e8/call flush/disp32
1323 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1324 #? # dump _test-output-stream {{{
1325 #? # . write(2/stderr, "^")
1327 #? 68/push "^"/imm32
1328 #? 68/push 2/imm32/stderr
1330 #? e8/call write/disp32
1331 #? # . . discard args
1332 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1333 #? # . write-stream(2/stderr, _test-output-stream)
1335 #? 68/push _test-output-stream/imm32
1336 #? 68/push 2/imm32/stderr
1338 #? e8/call write-stream/disp32
1339 #? # . . discard args
1340 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1341 #? # . write(2/stderr, "$\n")
1343 #? 68/push "$\n"/imm32
1344 #? 68/push 2/imm32/stderr
1346 #? e8/call write/disp32
1347 #? # . . discard args
1348 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1350 # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 5/rm32/.disp32 Foo/disp32 \n", msg)
1352 68/push "F - test-subx-sigils-indirect-mode-without-register"/imm32
1353 68/push "ab 0/mod/indirect 5/rm32/.disp32 Foo/disp32 \n"/imm32
1354 68/push _test-output-stream/imm32
1356 e8/call check-stream-equal/disp32
1358 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1360 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1364 emit-direct-mode: # out: (addr buffered-file), word-slice: (addr slice)
1367 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1370 # var local-slice/eax: slice = {word-slice->start, word-slice->end}
1371 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax
1372 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1373 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax
1374 89/copy 3/mod/direct 0/rm32/eax . . . 4/r32/esp . . # copy esp to eax
1375 # ++local-slice->start to skip '%'
1377 ff 0/subop/increment 0/mod/indirect 0/rm32/eax . . . . . . # increment *eax
1378 #? # write-slice-buffered(Stderr, word-slice) {{{
1381 #? 68/push Stderr/imm32
1383 #? e8/call write-slice-buffered/disp32
1384 #? # . . discard args
1385 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1386 #? # . flush(Stderr)
1388 #? 68/push Stderr/imm32
1390 #? e8/call flush/disp32
1391 #? # . . discard args
1392 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1393 #? # . write(2/stderr, "$\n")
1395 #? 68/push "$\n"/imm32
1396 #? 68/push 2/imm32/stderr
1398 #? e8/call write/disp32
1399 #? # . . discard args
1400 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1402 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/")
1405 68/push 0x2f/imm32/slash
1406 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1407 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax
1409 e8/call next-token-from-slice/disp32
1411 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
1412 # reg-num/eax = get-slice(Registers, local-slice, row-size=12)
1414 68/push "Registers"/imm32
1415 68/push 0xc/imm32/row-size
1417 68/push Registers/imm32
1419 e8/call get-slice/disp32
1421 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
1422 # write-buffered(out, "3/mod/direct ")
1424 68/push "3/mod/direct "/imm32
1425 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
1427 e8/call write-buffered/disp32
1429 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1430 # write-int32-hex-buffered(out, *reg-num)
1432 ff 6/subop/push 0/mod/indirect 0/rm32/eax . . . . . . # push *eax
1433 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
1435 e8/call write-int32-hex-buffered/disp32
1437 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1438 # write-buffered(out, "/rm32")
1440 68/push "/rm32"/imm32
1441 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
1443 e8/call write-buffered/disp32
1445 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1446 $emit-direct-mode:end:
1448 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1449 # . restore registers
1452 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1456 test-emit-direct-mode:
1459 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1461 # . clear-stream(_test-output-stream)
1463 68/push _test-output-stream/imm32
1465 e8/call clear-stream/disp32
1467 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1468 # . clear-stream($_test-output-buffered-file->buffer)
1470 68/push $_test-output-buffered-file->buffer/imm32
1472 e8/call clear-stream/disp32
1474 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1475 # var slice/ecx = "%eax"
1476 b8/copy-to-eax "%eax"/imm32
1477 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1478 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
1479 05/add-to-eax 4/imm32
1480 # . ecx = {eax, ecx}
1483 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
1484 # emit-direct-mode(_test-output-buffered-file, str)
1487 68/push _test-output-buffered-file/imm32
1489 e8/call emit-direct-mode/disp32
1491 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1492 # . flush(_test-output-buffered-file)
1494 68/push _test-output-buffered-file/imm32
1496 e8/call flush/disp32
1498 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1499 #? # dump output {{{
1500 #? # . write(2/stderr, "^")
1502 #? 68/push "^"/imm32
1503 #? 68/push 2/imm32/stderr
1505 #? e8/call write/disp32
1506 #? # . . discard args
1507 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1508 #? # . write-stream(2/stderr, _test-output-stream)
1510 #? 68/push _test-output-stream/imm32
1511 #? 68/push 2/imm32/stderr
1513 #? e8/call write-stream/disp32
1514 #? # . . discard args
1515 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1516 #? # . write(2/stderr, "$\n")
1518 #? 68/push "$\n"/imm32
1519 #? 68/push 2/imm32/stderr
1521 #? e8/call write/disp32
1522 #? # . . discard args
1523 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1525 # check-stream-equal(_test-output-stream, "3/mod/direct 0/rm32", msg)
1527 68/push "F - test-emit-direct-mode/0"/imm32
1528 68/push "3/mod/direct 0x00000000/rm32"/imm32
1529 68/push _test-output-stream/imm32
1531 e8/call check-stream-equal/disp32
1533 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1535 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1539 test-emit-direct-mode-2:
1542 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1544 # . clear-stream(_test-output-stream)
1546 68/push _test-output-stream/imm32
1548 e8/call clear-stream/disp32
1550 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1551 # . clear-stream($_test-output-buffered-file->buffer)
1553 68/push $_test-output-buffered-file->buffer/imm32
1555 e8/call clear-stream/disp32
1557 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1558 # var slice/ecx = "%edi"
1559 b8/copy-to-eax "%edi"/imm32
1560 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1561 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
1562 05/add-to-eax 4/imm32
1563 # . ecx = {eax, ecx}
1566 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
1567 # emit-direct-mode(_test-output-buffered-file, str/ecx)
1570 68/push _test-output-buffered-file/imm32
1572 e8/call emit-direct-mode/disp32
1574 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1575 # . flush(_test-output-buffered-file)
1577 68/push _test-output-buffered-file/imm32
1579 e8/call flush/disp32
1581 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1582 #? # dump output {{{
1583 #? # . write(2/stderr, "^")
1585 #? 68/push "^"/imm32
1586 #? 68/push 2/imm32/stderr
1588 #? e8/call write/disp32
1589 #? # . . discard args
1590 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1591 #? # . write-stream(2/stderr, _test-output-stream)
1593 #? 68/push _test-output-stream/imm32
1594 #? 68/push 2/imm32/stderr
1596 #? e8/call write-stream/disp32
1597 #? # . . discard args
1598 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1599 #? # . write(2/stderr, "$\n")
1601 #? 68/push "$\n"/imm32
1602 #? 68/push 2/imm32/stderr
1604 #? e8/call write/disp32
1605 #? # . . discard args
1606 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1608 # check-stream-equal(_test-output-stream, "3/mod/direct 7/rm32", msg)
1610 68/push "F - test-emit-direct-mode/1"/imm32
1611 68/push "3/mod/direct 0x00000007/rm32"/imm32
1612 68/push _test-output-stream/imm32
1614 e8/call check-stream-equal/disp32
1616 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1618 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1622 # (re)compute the bounds of the next word or parenthetical expression in the line
1623 # return empty string on reaching end of file
1625 # error messages considered:
1626 # * ... -> error: no space after '*'
1627 # *(... -> error: *(...) expression must be all on a single line
1628 next-word-or-expression: # line: (addr stream byte), out: (addr slice)
1630 # skip-chars-matching(line, ' ')
1631 # if line->read >= line->write # end of line
1634 # out->start = &line->data[line->read]
1635 # if line->data[line->read] == '#' # comment
1636 # out.end = &line->data[line->write]
1638 # if line->data[line->read] == '"' # string literal
1640 # else if line->data[line->read] == '*' # expression
1641 # if line->data[line->read + 1] == ' '
1643 # if line->data[line->read + 1] == '('
1644 # skip-until-close-paren(line)
1645 # if (line->data[line->read] != ')'
1647 # ++line->data[line->read] to skip ')'
1648 # skip-chars-not-matching-whitespace(line)
1649 # out->end = &line->data[line->read]
1652 # ecx: often line->read
1653 # eax: often line->data[line->read]
1657 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1664 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
1666 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
1667 # skip-chars-matching(line, ' ')
1669 68/push 0x20/imm32/space
1670 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
1672 e8/call skip-chars-matching/disp32
1674 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1675 $next-word-or-expression:check0:
1676 # if (line->read >= line->write) clear out and return
1677 # . ecx = line->read
1678 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
1679 # . if (ecx < line->write) goto next check
1680 3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi
1681 7c/jump-if-< $next-word-or-expression:check-for-comment/disp8
1682 # . return out = {0, 0}
1683 c7 0/subop/copy 0/mod/direct 7/rm32/edi . . . . . 0/imm32 # copy to *edi
1684 c7 0/subop/copy 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 0/imm32 # copy to *(edi+4)
1685 e9/jump $next-word-or-expression:end/disp32
1686 $next-word-or-expression:check-for-comment:
1687 # out->start = &line->data[line->read]
1688 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax
1689 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi
1690 # if (line->data[line->read] != '#') goto next check
1691 # . eax = line->data[line->read]
1692 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
1693 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL
1694 # . if (eax != '#') goto next check
1695 3d/compare-eax-and 0x23/imm32/pound
1696 75/jump-if-!= $next-word-or-expression:check-for-string-literal/disp8
1697 $next-word-or-expression:comment:
1698 # out->end = &line->data[line->write]
1699 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
1700 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy esi+eax+12 to eax
1701 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
1702 # line->read = line->write # skip rest of line
1703 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
1704 89/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy eax to *(esi+4)
1706 eb/jump $next-word-or-expression:end/disp8
1707 $next-word-or-expression:check-for-string-literal:
1708 # if (line->data[line->read] != '"') goto next check
1709 3d/compare-eax-and 0x22/imm32/dquote
1710 75/jump-if-!= $next-word-or-expression:check-for-expression/disp8
1711 $next-word-or-expression:string-literal:
1716 e8/call skip-string/disp32
1718 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1720 eb/jump $next-word-or-expression:regular-word/disp8
1721 $next-word-or-expression:check-for-expression:
1722 # if (line->data[line->read] != '*') goto next check
1723 3d/compare-eax-and 0x2a/imm32/asterisk
1724 75/jump-if-!= $next-word-or-expression:regular-word/disp8
1725 # if (line->data[line->read + 1] == ' ') goto error1
1726 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xd/disp8 . # copy byte at *(esi+ecx+12+1) to AL
1727 3d/compare-eax-and 0x20/imm32/space
1728 74/jump-if-= $next-word-or-expression:error1/disp8
1729 # if (line->data[line->read + 1] != '(') goto regular word
1730 3d/compare-eax-and 0x28/imm32/open-paren
1731 75/jump-if-!= $next-word-or-expression:regular-word/disp8
1732 $next-word-or-expression:paren:
1733 # skip-until-close-paren(line)
1737 e8/call skip-until-close-paren/disp32
1739 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1740 # if (line->data[line->read] != ')') goto error2
1741 # . eax = line->data[line->read]
1742 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
1743 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL
1744 # . if (eax != ')') goto error2
1745 3d/compare-eax-and 0x29/imm32/close-paren
1746 75/jump-if-!= $next-word-or-expression:error2/disp8
1748 ff 0/subop/increment 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # increment *(esi+4)
1750 $next-word-or-expression:regular-word:
1751 # skip-chars-not-matching-whitespace(line) # including trailing newline
1753 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
1755 e8/call skip-chars-not-matching-whitespace/disp32
1757 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1758 # out->end = &line->data[line->read]
1759 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
1760 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax
1761 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
1762 $next-word-or-expression:end:
1763 # . restore registers
1769 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1773 $next-word-or-expression:error1:
1774 # print(stderr, "error: no space allowed after '*' in '" line "'")
1775 # . write-buffered(Stderr, "error: no space allowed after '*' in '")
1777 68/push "error: no space allowed after '*' in '"/imm32
1778 68/push Stderr/imm32
1780 e8/call write-buffered/disp32
1782 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1783 # . write-stream-data(Stderr, line)
1786 68/push Stderr/imm32
1788 e8/call write-stream-data/disp32
1790 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1791 # . write-buffered(Stderr, "'")
1794 68/push Stderr/imm32
1796 e8/call write-buffered/disp32
1798 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1801 68/push Stderr/imm32
1803 e8/call flush/disp32
1805 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1807 bb/copy-to-ebx 1/imm32
1808 e8/call syscall_exit/disp32
1811 $next-word-or-expression:error2:
1812 # print(stderr, "error: *(...) expression must be all on a single line in '" line "'")
1813 # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '")
1815 68/push "error: *(...) expression must be all on a single line in '"/imm32
1816 68/push Stderr/imm32
1818 e8/call write-buffered/disp32
1820 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1821 # . write-stream-data(Stderr, line)
1824 68/push Stderr/imm32
1826 e8/call write-stream-data/disp32
1828 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1829 # . write-buffered(Stderr, "'")
1832 68/push Stderr/imm32
1834 e8/call write-buffered/disp32
1836 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1839 68/push Stderr/imm32
1841 e8/call flush/disp32
1843 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1845 bb/copy-to-ebx 1/imm32
1846 e8/call syscall_exit/disp32
1849 test-next-word-or-expression:
1852 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1854 # . clear-stream(_test-input-stream)
1856 68/push _test-input-stream/imm32
1858 e8/call clear-stream/disp32
1860 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1861 # var slice/ecx: slice
1863 68/push 0/imm32/start
1864 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
1865 # write(_test-input-stream, " ab")
1868 68/push _test-input-stream/imm32
1870 e8/call write/disp32
1872 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1873 # next-word-or-expression(_test-input-stream, slice)
1876 68/push _test-input-stream/imm32
1878 e8/call next-word-or-expression/disp32
1880 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1881 # check-ints-equal(_test-input-stream->read, 4, msg)
1883 68/push "F - test-next-word-or-expression/updates-stream-read-correctly"/imm32
1885 b8/copy-to-eax _test-input-stream/imm32
1886 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1888 e8/call check-ints-equal/disp32
1890 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1891 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
1892 # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
1894 68/push "F - test-next-word-or-expression: start"/imm32
1896 # . . push slice->start - _test-input-stream
1897 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
1898 2d/subtract-from-eax _test-input-stream/imm32
1901 e8/call check-ints-equal/disp32
1903 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1904 # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
1905 # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
1907 68/push "F - test-next-word-or-expression: end"/imm32
1909 # . . push slice->end - _test-input-stream
1910 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
1911 2d/subtract-from-eax _test-input-stream/imm32
1914 e8/call check-ints-equal/disp32
1916 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1918 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1922 test-next-word-or-expression-returns-whole-comment:
1925 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1927 # . clear-stream(_test-input-stream)
1929 68/push _test-input-stream/imm32
1931 e8/call clear-stream/disp32
1933 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1934 # var slice/ecx: slice
1936 68/push 0/imm32/start
1937 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
1938 # write(_test-input-stream, " # a")
1940 68/push " # a"/imm32
1941 68/push _test-input-stream/imm32
1943 e8/call write/disp32
1945 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1946 # next-word-or-expression(_test-input-stream, slice)
1949 68/push _test-input-stream/imm32
1951 e8/call next-word-or-expression/disp32
1953 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1954 # check-ints-equal(_test-input-stream->read, 5, msg)
1956 68/push "F - test-next-word-or-expression-returns-whole-comment/updates-stream-read-correctly"/imm32
1958 b8/copy-to-eax _test-input-stream/imm32
1959 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1961 e8/call check-ints-equal/disp32
1963 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1964 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
1965 # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
1967 68/push "F - test-next-word-or-expression-returns-whole-comment: start"/imm32
1969 # . . push slice->start - _test-input-stream
1970 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
1971 2d/subtract-from-eax _test-input-stream/imm32
1974 e8/call check-ints-equal/disp32
1976 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1977 # check-ints-equal(slice->end - _test-input-stream->data, 5, msg)
1978 # . check-ints-equal(slice->end - _test-input-stream, 17, msg)
1980 68/push "F - test-next-word-or-expression-returns-whole-comment: end"/imm32
1982 # . . push slice->end - _test-input-stream
1983 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
1984 2d/subtract-from-eax _test-input-stream/imm32
1987 e8/call check-ints-equal/disp32
1989 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1991 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1995 test-next-word-or-expression-returns-empty-slice-on-eof:
1998 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2000 # . clear-stream(_test-input-stream)
2002 68/push _test-input-stream/imm32
2004 e8/call clear-stream/disp32
2006 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2007 # var slice/ecx: slice
2009 68/push 0/imm32/start
2010 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2011 # write nothing to _test-input-stream
2012 # next-word-or-expression(_test-input-stream, slice)
2015 68/push _test-input-stream/imm32
2017 e8/call next-word-or-expression/disp32
2019 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2020 # check-ints-equal(slice->end - slice->start, 0, msg)
2022 68/push "F - test-next-word-or-expression-returns-empty-expression-on-eof"/imm32
2024 # . . push slice->end - slice->start
2025 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
2026 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax
2029 e8/call check-ints-equal/disp32
2031 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2033 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2037 test-next-word-or-expression-returns-string-literal:
2040 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2042 # . clear-stream(_test-input-stream)
2044 68/push _test-input-stream/imm32
2046 e8/call clear-stream/disp32
2048 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2049 # var slice/ecx: slice
2051 68/push 0/imm32/start
2052 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2053 # write(_test-input-stream, " \"a b\"/imm32 ")
2055 68/push " \"a b\"/imm32 "/imm32
2056 68/push _test-input-stream/imm32
2058 e8/call write/disp32
2060 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2061 # next-word-or-expression(_test-input-stream, slice)
2064 68/push _test-input-stream/imm32
2066 e8/call next-word-or-expression/disp32
2068 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2069 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
2070 # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
2072 68/push "F - test-next-word-or-expression-returns-string-literal: start"/imm32
2074 # . . push slice->start - _test-input-stream
2075 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
2076 2d/subtract-from-eax _test-input-stream/imm32
2079 e8/call check-ints-equal/disp32
2081 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2082 # check-ints-equal(slice->end - _test-input-stream->data, 12, msg)
2083 # . check-ints-equal(slice->end - _test-input-stream, 24, msg)
2085 68/push "F - test-next-word-or-expression-returns-string-literal: end"/imm32
2087 # . . push slice->end - _test-input-stream
2088 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
2089 2d/subtract-from-eax _test-input-stream/imm32
2092 e8/call check-ints-equal/disp32
2094 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2096 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2100 test-next-word-or-expression-returns-string-with-escapes:
2103 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2105 # . clear-stream(_test-input-stream)
2107 68/push _test-input-stream/imm32
2109 e8/call clear-stream/disp32
2111 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2112 # var slice/ecx: slice
2114 68/push 0/imm32/start
2115 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2116 # write(_test-input-stream, " \"a\\\"b\"/x")
2118 68/push " \"a\\\"b\"/x"/imm32
2119 68/push _test-input-stream/imm32
2121 e8/call write/disp32
2123 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2124 # next-word-or-expression(_test-input-stream, slice)
2127 68/push _test-input-stream/imm32
2129 e8/call next-word-or-expression/disp32
2131 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2132 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
2133 # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
2135 68/push "F - test-next-word-or-expression-returns-string-with-escapes: start"/imm32
2137 # . . push slice->start - _test-input-stream
2138 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
2139 2d/subtract-from-eax _test-input-stream/imm32
2142 e8/call check-ints-equal/disp32
2144 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2145 # check-ints-equal(slice->end - _test-input-stream->data, 9, msg)
2146 # . check-ints-equal(slice->end - _test-input-stream, 21, msg)
2148 68/push "F - test-next-word-or-expression-returns-string-with-escapes: end"/imm32
2150 # . . push slice->end - _test-input-stream
2151 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
2152 2d/subtract-from-eax _test-input-stream/imm32
2155 e8/call check-ints-equal/disp32
2157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2159 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2163 test-next-word-or-expression-returns-whole-expression:
2166 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2168 # . clear-stream(_test-input-stream)
2170 68/push _test-input-stream/imm32
2172 e8/call clear-stream/disp32
2174 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2175 # var slice/ecx: slice
2177 68/push 0/imm32/start
2178 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2179 # write(_test-input-stream, " *(a b)/imm32 ")
2181 68/push " *(a b)/imm32 "/imm32
2182 68/push _test-input-stream/imm32
2184 e8/call write/disp32
2186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2187 # next-word-or-expression(_test-input-stream, slice)
2190 68/push _test-input-stream/imm32
2192 e8/call next-word-or-expression/disp32
2194 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2195 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
2196 # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
2198 68/push "F - test-next-word-or-expression-returns-whole-expression: start"/imm32
2200 # . . push slice->start - _test-input-stream
2201 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
2202 2d/subtract-from-eax _test-input-stream/imm32
2205 e8/call check-ints-equal/disp32
2207 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2208 # check-ints-equal(slice->end - _test-input-stream->data, 13, msg)
2209 # . check-ints-equal(slice->end - _test-input-stream, 25, msg)
2211 68/push "F - test-next-word-or-expression-returns-whole-expression: end"/imm32
2213 # . . push slice->end - _test-input-stream
2214 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
2215 2d/subtract-from-eax _test-input-stream/imm32
2218 e8/call check-ints-equal/disp32
2220 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2222 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2227 # *reg -> 0/mod reg/rm32
2228 # *(reg) -> 0/mod reg/rm32
2229 # *(reg+disp) -> 2/mod reg/rm32 disp/disp32
2230 # *(reg1+reg2<<s) -> 2/mod 4/rm32 reg1/base reg2/index s/scale 0/disp32
2231 # *(reg1+reg2<<s+disp) -> 2/mod 4/rm32 reg1/base reg2/index s/scale disp/disp32
2232 # Intermediate structure: base, index, scale, disp
2233 # Default values: base: 0, index: 4 (none), scale: 0, disp: 0
2234 parse-effective-address: # word-slice: (addr slice) -> base/eax, index/ecx, scale/edx, disp/ebx
2236 # var local-slice = {word-slice->start, word-slice->end}
2237 # ++local-slice->start to skip '*'
2238 # initialize defaults: base=0, index=4, scale=0, disp=0
2239 # if (*local-slice->start != '(') {
2240 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/")
2241 # base = get-slice(Registers, local-slice, row-size=12)
2244 # # compound expressions
2246 # read register into base
2248 # if (*local-slice->start == ')') goto end
2249 # if (*local-slice->start == '-') goto displacement
2250 # if (*local-slice->start != '+') goto error1
2251 # ++local-slice->start to skip '+'
2253 # if next 3 characters don't make a register, goto displacement
2254 # read register into index
2256 # if (*local-slice->start == ')') goto end
2257 # if (*local-slice->start == '<') {
2258 # ++local-slice->start to skip '<'
2259 # if (*local-slice->start != '<') goto error2
2260 # ++local-slice->start to skip '<'
2262 # read integer into scale
2264 # if (*local-slice->start == ')') goto end
2266 # if (*local-slice->start not in '+' '-') goto error3
2268 # read integer into disp
2270 # if (*local-slice->start != ')') goto error4
2273 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2277 # var local-slice/esi: slice = {word-slice->start, word-slice->end}
2278 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
2279 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2280 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2281 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
2282 # ++local-slice->start to skip '*'
2283 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
2284 # initialize defaults
2285 # base is in edi; we'll move it to eax just before we return
2286 bf/copy-to-edi 0/imm32
2287 b9/copy-to-ecx 4/imm32/no-index
2288 ba/copy-to-edx 0/imm32/.scale
2289 bb/copy-to-ebx 0/imm32/disp
2290 $parse-effective-address:check-for-simple-register:
2291 # if (*local-slice->start == '(') goto compound expression
2292 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
2293 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
2294 25/and-eax-with 0xff/imm32
2295 3d/compare-eax-and 0x28/imm32/open-paren
2296 74/jump-if-= $parse-effective-address:compound-expression/disp8
2297 $parse-effective-address:simple-register:
2298 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/")
2301 68/push 0x2f/imm32/slash
2302 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2303 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2305 e8/call next-token-from-slice/disp32
2307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
2308 # base = get-slice(Registers, local-slice, row-size=12)
2309 # . eax = get-slice(Registers, local-slice, row-size=12)
2311 68/push "Registers"/imm32
2312 68/push 0xc/imm32/row-size
2314 68/push Registers/imm32
2316 e8/call get-slice/disp32
2318 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
2320 8b/copy 0/mod/indirect 0/rm32/eax . . . 7/r32/edi . . # copy *eax to edi
2322 e9/jump $parse-effective-address:end/disp32
2323 $parse-effective-address:compound-expression:
2324 # ++local-slice->start to skip '('
2325 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
2327 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2329 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2330 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2332 e8/call skip-chars-matching-whitespace-in-slice/disp32
2334 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2335 # . local-slice->start = eax
2336 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2337 # read register into base
2338 # . eax = next-register(local-slice)
2342 e8/call next-register/disp32
2344 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2346 8b/copy 0/mod/indirect 0/rm32/eax . . . 7/r32/edi . . # copy *eax to edi
2348 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2350 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2351 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2353 e8/call skip-chars-matching-whitespace-in-slice/disp32
2355 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2356 # . local-slice->start = eax
2357 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2358 # if (*local-slice->start == ')') goto end
2359 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
2360 25/and-eax-with 0xff/imm32
2361 3d/compare-eax-and 0x29/imm32/close-paren
2362 0f 84/jump-if-= $parse-effective-address:end/disp32
2363 # if (*local-slice->start == '-') goto displacement
2364 3d/compare-eax-and 0x2d/imm32/minus
2365 0f 84/jump-if-= $parse-effective-address:displacement/disp32
2366 # if (*local-slice->start != '+') goto error1
2367 3d/compare-eax-and 0x2b/imm32/plus
2368 0f 85/jump-if-!= $parse-effective-address:error1/disp32
2369 $parse-effective-address:check-for-index:
2370 # ++local-slice->start to skip '+'
2371 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
2373 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2375 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2376 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2378 e8/call skip-chars-matching-whitespace-in-slice/disp32
2380 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2381 # . local-slice->start = eax
2382 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2383 $parse-effective-address:resolve-ambiguity:
2384 # if next 3 characters don't make a register, goto displacement
2387 # . var tmp/ecx = {local-slice->start, local-slice->start+3}
2388 # . . ecx = local-slice->start
2389 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx
2390 # . . eax = local-slice->start+3
2391 05/add-to-eax 3/imm32
2395 # . . copy esp to ecx
2396 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2397 # . eax = maybe-get-slice(Register, tmp, row-size=12)
2399 68/push 0xc/imm32/row-size
2401 68/push Registers/imm32
2403 e8/call maybe-get-slice/disp32
2405 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2407 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2410 # . if (eax == 0) goto displacement
2411 3d/compare-eax-and 0/imm32
2412 0f 84/jump-if-= $parse-effective-address:displacement/disp32
2413 $parse-effective-address:index:
2414 # read register into index
2415 # . eax = next-register(local-slice)
2419 e8/call next-register/disp32
2421 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2423 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
2425 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2427 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2428 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2430 e8/call skip-chars-matching-whitespace-in-slice/disp32
2432 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2433 # . local-slice->start = eax
2434 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2435 # if (*local-slice->start == ')') goto end
2436 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
2437 25/and-eax-with 0xff/imm32
2438 3d/compare-eax-and 0x29/imm32/close-paren
2439 0f 84/jump-if-= $parse-effective-address:end/disp32
2440 $parse-effective-address:check-for-scale:
2441 # if (*local-slice->start != '<') goto next check
2442 3d/compare-eax-and 0x3c/imm32/less-than
2443 75/jump-if-!= $parse-effective-address:check-for-displacement/disp8
2444 # ++local-slice->start to skip '<'
2445 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
2446 # if (*local-slice->start != '<') goto error2
2447 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
2448 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
2449 25/and-eax-with 0xff/imm32
2450 3d/compare-eax-and 0x3c/imm32/less-than
2451 0f 85/jump-if-!= $parse-effective-address:error2/disp32
2452 # ++local-slice->start to skip '<'
2453 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
2455 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2457 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2458 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2460 e8/call skip-chars-matching-whitespace-in-slice/disp32
2462 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2463 # . local-slice->start = eax
2464 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2465 $parse-effective-address:scale:
2466 # read positive integer into scale
2467 # . eax = next-positive-hex-int(local-slice)
2471 e8/call next-positive-hex-int/disp32
2473 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2475 89/copy 3/mod/direct 2/rm32/edx . . . 0/r32/eax . . # copy eax to edx
2477 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2479 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2480 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2482 e8/call skip-chars-matching-whitespace-in-slice/disp32
2484 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2485 # . local-slice->start = eax
2486 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2487 # if (*local-slice->start == ')') goto end
2488 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
2489 25/and-eax-with 0xff/imm32
2490 3d/compare-eax-and 0x29/imm32/close-paren
2491 74/jump-if-= $parse-effective-address:end/disp8
2492 $parse-effective-address:check-for-displacement:
2493 # if (*local-slice->start not in '+' '-') goto error3
2494 3d/compare-eax-and 0x2b/imm32/plus
2495 74/jump-if-= $parse-effective-address:displacement/disp8
2496 3d/compare-eax-and 0x2d/imm32/minus
2497 74/jump-if-= $parse-effective-address:displacement/disp8
2498 e9/jump $parse-effective-address:error3/disp32
2499 $parse-effective-address:displacement:
2500 # read integer into disp
2501 # . eax = next-hex-int(local-slice)
2505 e8/call next-hex-int/disp32
2507 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2509 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx
2511 # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2513 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
2514 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2516 e8/call skip-chars-matching-whitespace-in-slice/disp32
2518 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2519 # . local-slice->start = eax
2520 89/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy eax to *esi
2521 # if (*local-slice->start != ')') goto error4
2522 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
2523 25/and-eax-with 0xff/imm32
2524 3d/compare-eax-and 0x29/imm32/close-paren
2525 0f 85/jump-if-!= $parse-effective-address:error4/disp32
2526 $parse-effective-address:end:
2527 # return base in eax
2528 89/copy 3/mod/direct 0/rm32/eax . . . 7/r32/edi . . # copy edi to eax
2530 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2531 # . restore registers
2535 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2539 $parse-effective-address:error1:
2540 # print(stderr, "error: unexpected character: " eax "\n")
2541 # . write-buffered(Stderr, "error: unexpected character: ")
2543 68/push "error: unexpected character: "/imm32
2544 68/push Stderr/imm32
2546 e8/call write-buffered/disp32
2548 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2549 # . write-int32-hex-buffered(out, eax)
2552 68/push Stderr/imm32
2554 e8/call write-int32-hex-buffered/disp32
2556 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2557 # . write-buffered(Stderr, "\n")
2559 68/push Newline/imm32
2560 68/push Stderr/imm32
2562 e8/call write-buffered/disp32
2564 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2567 68/push Stderr/imm32
2569 e8/call flush/disp32
2571 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2573 bb/copy-to-ebx 1/imm32
2574 e8/call syscall_exit/disp32
2577 $parse-effective-address:error2:
2578 # print(stderr, "error: '<' can only be followed by '<' but got: " eax "\n")
2579 # . write-buffered(Stderr, "error: '<' can only be followed by '<' but got: ")
2581 68/push "error: '<' can only be followed by '<' but got: "/imm32
2582 68/push Stderr/imm32
2584 e8/call write-buffered/disp32
2586 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2587 # . write-int32-hex-buffered(out, eax)
2590 68/push Stderr/imm32
2592 e8/call write-int32-hex-buffered/disp32
2594 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2595 # . write-buffered(Stderr, "\n")
2597 68/push Newline/imm32
2598 68/push Stderr/imm32
2600 e8/call write-buffered/disp32
2602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2605 68/push Stderr/imm32
2607 e8/call flush/disp32
2609 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2611 bb/copy-to-ebx 1/imm32
2612 e8/call syscall_exit/disp32
2615 $parse-effective-address:error3:
2616 # print(stderr, "error: unexpected character before displacement: " eax "\n")
2617 # . write-buffered(Stderr, "error: unexpected character before displacement: ")
2619 68/push "error: unexpected character before displacement: "/imm32
2620 68/push Stderr/imm32
2622 e8/call write-buffered/disp32
2624 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2625 # . write-int32-hex-buffered(out, eax)
2628 68/push Stderr/imm32
2630 e8/call write-int32-hex-buffered/disp32
2632 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2633 # . write-buffered(Stderr, "\n")
2635 68/push Newline/imm32
2636 68/push Stderr/imm32
2638 e8/call write-buffered/disp32
2640 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2643 68/push Stderr/imm32
2645 e8/call flush/disp32
2647 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2649 bb/copy-to-ebx 1/imm32
2650 e8/call syscall_exit/disp32
2653 $parse-effective-address:error4:
2654 # print(stderr, "error: unexpected character after displacement: " eax "; expected ')' to wrap up\n")
2655 # . write-buffered(Stderr, "error: unexpected character after displacement: ")
2657 68/push "error: unexpected character after displacement: "/imm32
2658 68/push Stderr/imm32
2660 e8/call write-buffered/disp32
2662 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2663 # . write-int32-hex-buffered(out, eax)
2666 68/push Stderr/imm32
2668 e8/call write-int32-hex-buffered/disp32
2670 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2671 # . write-buffered(Stderr, "; expected ')' to wrap up\n")
2673 68/push "; expected ')' to wrap up\n"/imm32
2674 68/push Stderr/imm32
2676 e8/call write-buffered/disp32
2678 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2681 68/push Stderr/imm32
2683 e8/call flush/disp32
2685 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2687 bb/copy-to-ebx 1/imm32
2688 e8/call syscall_exit/disp32
2691 # assumes 'in' starts with a register name, and returns pointer to its code
2692 # side-effect: modifies 'in' to scan past the initial register name
2693 next-register: # in: (addr slice) -> reg/eax: int
2696 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2701 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
2702 # var reg-slice/ecx: slice = {in->start, in->start + 3}
2703 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
2704 05/add-to-eax 3/imm32
2706 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
2707 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2709 81 0/subop/add 0/mod/indirect 6/rm32/esi . . . . . 3/imm32 # add to *esi
2710 # eax = get-slice(Registers, reg-slice, row-size=12)
2712 68/push "next-register"/imm32
2713 68/push 0xc/imm32/row-size
2715 68/push Registers/imm32
2717 e8/call get-slice/disp32
2719 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
2722 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
2723 # . restore registers
2727 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2731 test-parse-effective-address-simple:
2734 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2735 # var slice/ecx = "*esi"
2736 b8/copy-to-eax "*esi"/imm32
2737 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
2738 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
2739 05/add-to-eax 4/imm32
2740 # . ecx = {eax, ecx}
2743 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2744 # eax, ecx, edx, ebx = parse-effective-address(slice)
2748 e8/call parse-effective-address/disp32
2750 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2751 # slice clobbered beyond this point
2752 # check-ints-equal(eax, 6, msg)
2754 68/push "F - test-parse-effective-address-simple/base"/imm32
2758 e8/call check-ints-equal/disp32
2760 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2761 # check-ints-equal(ecx, 4, msg)
2763 68/push "F - test-parse-effective-address-simple/index"/imm32
2764 68/push 4/imm32/none
2767 e8/call check-ints-equal/disp32
2769 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2770 # check-ints-equal(edx, 0, msg)
2772 68/push "F - test-parse-effective-address-simple/scale"/imm32
2773 68/push 0/imm32/none
2776 e8/call check-ints-equal/disp32
2778 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2779 # check-ints-equal(ebx, 0, msg)
2781 68/push "F - test-parse-effective-address-simple/displacement"/imm32
2782 68/push 0/imm32/none
2785 e8/call check-ints-equal/disp32
2787 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2789 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2793 test-parse-effective-address-base:
2796 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2797 # var slice/ecx = "*(esi )"
2798 b8/copy-to-eax "*(esi )"/imm32
2799 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
2800 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
2801 05/add-to-eax 4/imm32
2802 # . ecx = {eax, ecx}
2805 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2806 # eax, ecx, edx, ebx = parse-effective-address(slice)
2810 e8/call parse-effective-address/disp32
2812 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2813 # slice clobbered beyond this point
2814 # check-ints-equal(eax, 6, msg)
2816 68/push "F - test-parse-effective-address-base/base"/imm32
2820 e8/call check-ints-equal/disp32
2822 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2823 # check-ints-equal(ecx, 4, msg)
2825 68/push "F - test-parse-effective-address-base/index"/imm32
2826 68/push 4/imm32/none
2829 e8/call check-ints-equal/disp32
2831 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2832 # check-ints-equal(edx, 0, msg)
2834 68/push "F - test-parse-effective-address-base/scale"/imm32
2835 68/push 0/imm32/none
2838 e8/call check-ints-equal/disp32
2840 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2841 # check-ints-equal(ebx, 0, msg)
2843 68/push "F - test-parse-effective-address-base/displacement"/imm32
2844 68/push 0/imm32/none
2847 e8/call check-ints-equal/disp32
2849 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2851 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2855 test-parse-effective-address-base-displacement:
2858 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2859 # var slice/ecx = "*(esi+3)"
2860 b8/copy-to-eax "*(esi+3)"/imm32
2861 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
2862 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
2863 05/add-to-eax 4/imm32
2864 # . ecx = {eax, ecx}
2867 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2868 # eax, ecx, edx, ebx = parse-effective-address(slice)
2872 e8/call parse-effective-address/disp32
2874 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2875 # slice clobbered beyond this point
2876 # check-ints-equal(eax, 6, msg)
2878 68/push "F - test-parse-effective-address-base-displacement/base"/imm32
2882 e8/call check-ints-equal/disp32
2884 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2885 # check-ints-equal(ecx, 4, msg)
2887 68/push "F - test-parse-effective-address-base-displacement/index"/imm32
2888 68/push 4/imm32/none
2891 e8/call check-ints-equal/disp32
2893 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2894 # check-ints-equal(edx, 0, msg)
2896 68/push "F - test-parse-effective-address-base-displacement/scale"/imm32
2897 68/push 0/imm32/none
2900 e8/call check-ints-equal/disp32
2902 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2903 # check-ints-equal(ebx, 3, msg)
2905 68/push "F - test-parse-effective-address-base-displacement/displacement"/imm32
2909 e8/call check-ints-equal/disp32
2911 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2913 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2917 test-parse-effective-address-base-negative-displacement:
2920 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2921 # var slice/ecx = "*(esi-3)"
2922 b8/copy-to-eax "*(esi-3)"/imm32
2923 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
2924 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
2925 05/add-to-eax 4/imm32
2926 # . ecx = {eax, ecx}
2929 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2930 # eax, ecx, edx, ebx = parse-effective-address(slice)
2934 e8/call parse-effective-address/disp32
2936 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2937 # slice clobbered beyond this point
2938 # check-ints-equal(eax, 6, msg)
2940 68/push "F - test-parse-effective-address-base-negative-displacement/base"/imm32
2944 e8/call check-ints-equal/disp32
2946 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2947 # check-ints-equal(ecx, 4, msg)
2949 68/push "F - test-parse-effective-address-base-negative-displacement/index"/imm32
2950 68/push 4/imm32/none
2953 e8/call check-ints-equal/disp32
2955 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2956 # check-ints-equal(edx, 0, msg)
2958 68/push "F - test-parse-effective-address-base-negative-displacement/scale"/imm32
2959 68/push 0/imm32/none
2962 e8/call check-ints-equal/disp32
2964 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2965 # check-ints-equal(ebx, -3, msg)
2967 68/push "F - test-parse-effective-address-base-negative-displacement/displacement"/imm32
2971 e8/call check-ints-equal/disp32
2973 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
2975 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
2979 test-parse-effective-address-base-index:
2982 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
2983 # var slice/ecx = "*(esi+ecx)"
2984 b8/copy-to-eax "*(esi+ecx)"/imm32
2985 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
2986 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
2987 05/add-to-eax 4/imm32
2988 # . ecx = {eax, ecx}
2991 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
2992 # eax, ecx, edx, ebx = parse-effective-address(slice)
2996 e8/call parse-effective-address/disp32
2998 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
2999 # slice clobbered beyond this point
3000 # check-ints-equal(eax, 6, msg)
3002 68/push "F - test-parse-effective-address-base-index/base"/imm32
3006 e8/call check-ints-equal/disp32
3008 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3009 # check-ints-equal(ecx, 1, msg)
3011 68/push "F - test-parse-effective-address-base-index/index"/imm32
3012 68/push 1/imm32/none
3015 e8/call check-ints-equal/disp32
3017 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3018 # check-ints-equal(edx, 0, msg)
3020 68/push "F - test-parse-effective-address-base-index/scale"/imm32
3021 68/push 0/imm32/none
3024 e8/call check-ints-equal/disp32
3026 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3027 # check-ints-equal(ebx, 0, msg)
3029 68/push "F - test-parse-effective-address-base-index/displacement"/imm32
3033 e8/call check-ints-equal/disp32
3035 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3037 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3041 test-parse-effective-address-base-index-scale:
3044 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3045 # var slice/ecx = "*(esi+ecx<<2)"
3046 b8/copy-to-eax "*(esi+ecx<<2)"/imm32
3047 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
3048 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
3049 05/add-to-eax 4/imm32
3050 # . ecx = {eax, ecx}
3053 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
3054 # eax, ecx, edx, ebx = parse-effective-address(slice)
3058 e8/call parse-effective-address/disp32
3060 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3061 # slice clobbered beyond this point
3062 # check-ints-equal(eax, 6, msg)
3064 68/push "F - test-parse-effective-address-base-index-scale/base"/imm32
3068 e8/call check-ints-equal/disp32
3070 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3071 # check-ints-equal(ecx, 1, msg)
3073 68/push "F - test-parse-effective-address-base-index-scale/index"/imm32
3074 68/push 1/imm32/none
3077 e8/call check-ints-equal/disp32
3079 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3080 # check-ints-equal(edx, 2, msg)
3082 68/push "F - test-parse-effective-address-base-index-scale/scale"/imm32
3086 e8/call check-ints-equal/disp32
3088 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3089 # check-ints-equal(ebx, 0, msg)
3091 68/push "F - test-parse-effective-address-base-index-scale/displacement"/imm32
3095 e8/call check-ints-equal/disp32
3097 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3099 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3103 test-parse-effective-address-base-index-scale-displacement:
3106 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3107 # var slice/ecx = "*(esi + ecx<<2 - 0x34)"
3108 b8/copy-to-eax "*(esi + ecx<<2 - 0x34)"/imm32
3109 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
3110 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
3111 05/add-to-eax 4/imm32
3112 # . ecx = {eax, ecx}
3115 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
3116 # eax, ecx, edx, ebx = parse-effective-address(slice)
3120 e8/call parse-effective-address/disp32
3122 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3123 # slice clobbered beyond this point
3124 # check-ints-equal(eax, 6, msg)
3126 68/push "F - test-parse-effective-address-base-index-scale/base"/imm32
3130 e8/call check-ints-equal/disp32
3132 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3133 # check-ints-equal(ecx, 1, msg)
3135 68/push "F - test-parse-effective-address-base-index-scale/index"/imm32
3136 68/push 1/imm32/none
3139 e8/call check-ints-equal/disp32
3141 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3142 # check-ints-equal(edx, 2, msg)
3144 68/push "F - test-parse-effective-address-base-index-scale/scale"/imm32
3148 e8/call check-ints-equal/disp32
3150 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3151 # check-ints-equal(ebx, -0x34, msg)
3153 68/push "F - test-parse-effective-address-base-index-scale/displacement"/imm32
3157 e8/call check-ints-equal/disp32
3159 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3161 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3166 # if base is esp, then goto emit-sib
3167 # if base is ebp, then goto emit-sib
3168 # if index is none and disp is 0, then mod = 0 and rm32 = base
3169 # if index is none, then mod = 2 and rm32 = base and disp32 = disp
3171 # if index is not none, then mod = 2 and rm32 = 4 and base = base and index = index and disp32 = disp
3172 emit-indirect-mode: # out: (addr buffered-file), base: int, index: int, scale: int, disp: int
3175 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3176 $emit-indirect-mode:check-for-ebp:
3177 # if (base == 5) goto emit-sib
3178 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 5/imm32 # compare *(ebp+12)
3179 74/jump-if-= $emit-indirect-mode:emit-sib/disp8
3180 $emit-indirect-mode:check-for-esp:
3181 # if (base == 4) goto emit-sib
3182 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 4/imm32 # compare *(ebp+12)
3183 74/jump-if-= $emit-indirect-mode:emit-sib/disp8
3184 $emit-indirect-mode:check-for-sib:
3185 # if (index == 4/none) goto next check
3186 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 4/imm32 # compare *(ebp+16)
3187 0f 84/jump-if-= $emit-indirect-mode:check-for-disp/disp32
3188 $emit-indirect-mode:emit-sib:
3189 # emit(out, "2/mod/indirect 4/rm32/sib " base "/base " index "/index " scale "/scale " disp "/disp32")
3190 # . write-buffered(out, "2/mod/*+disp32 4/rm32/sib ")
3192 68/push "2/mod/*+disp32 4/rm32/sib "/imm32
3193 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3195 e8/call write-buffered/disp32
3197 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3198 # . write-int32-hex-buffered(out, base)
3200 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
3201 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3203 e8/call write-int32-hex-buffered/disp32
3205 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3206 # . write-buffered(out, "/base ")
3208 68/push "/base "/imm32
3209 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3211 e8/call write-buffered/disp32
3213 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3214 # . write-int32-hex-buffered(out, index)
3216 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
3217 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3219 e8/call write-int32-hex-buffered/disp32
3221 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3222 # . write-buffered(out, "/index ")
3224 68/push "/index "/imm32
3225 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3227 e8/call write-buffered/disp32
3229 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3230 # . write-int32-hex-buffered(out, scale)
3232 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20)
3233 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3235 e8/call write-int32-hex-buffered/disp32
3237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3238 # . write-buffered(out, "/scale ")
3240 68/push "/scale "/imm32
3241 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3243 e8/call write-buffered/disp32
3245 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3246 # . write-int32-hex-buffered(out, disp)
3248 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24)
3249 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3251 e8/call write-int32-hex-buffered/disp32
3253 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3254 # . write-buffered(out, "/disp32")
3256 68/push "/disp32"/imm32
3257 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3259 e8/call write-buffered/disp32
3261 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3262 e9/jump $emit-indirect-mode:end/disp32
3263 $emit-indirect-mode:check-for-disp:
3264 # if (disp == 0) goto next check
3265 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 0/imm32 # compare *(ebp+24)
3266 74/jump-if-= $emit-indirect-mode:emit-indirect/disp8
3267 $emit-indirect-mode:emit-disp:
3268 # emit(out, "2/mod/*+disp32 " base "/rm32 " disp "/disp32")
3269 # . write-buffered(out, "2/mod/*+disp32 ")
3271 68/push "2/mod/*+disp32 "/imm32
3272 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3274 e8/call write-buffered/disp32
3276 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3277 # . write-int32-hex-buffered(out, base)
3279 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
3280 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3282 e8/call write-int32-hex-buffered/disp32
3284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3285 # . write-buffered(out, "/rm32 ")
3287 68/push "/rm32 "/imm32
3288 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3290 e8/call write-buffered/disp32
3292 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3293 # . write-int32-hex-buffered(out, disp)
3295 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x18/disp8 . # push *(ebp+24)
3296 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3298 e8/call write-int32-hex-buffered/disp32
3300 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3301 # . write-buffered(out, "/disp32")
3303 68/push "/disp32"/imm32
3304 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3306 e8/call write-buffered/disp32
3308 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3309 eb/jump $emit-indirect-mode:end/disp8
3310 $emit-indirect-mode:emit-indirect:
3311 # emit(out, "0/mod/indirect " base "/rm32")
3312 # . write-buffered(out, "0/mod/indirect ")
3314 68/push "0/mod/indirect "/imm32
3315 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3317 e8/call write-buffered/disp32
3319 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3320 # . write-int32-hex-buffered(out, base)
3322 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
3323 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3325 e8/call write-int32-hex-buffered/disp32
3327 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3328 # . write-buffered(out, "/rm32")
3330 68/push "/rm32"/imm32
3331 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3333 e8/call write-buffered/disp32
3335 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3336 $emit-indirect-mode:end:
3338 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3342 test-emit-indirect-mode:
3345 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3347 # . clear-stream(_test-output-stream)
3349 68/push _test-output-stream/imm32
3351 e8/call clear-stream/disp32
3353 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3354 # . clear-stream($_test-output-buffered-file->buffer)
3356 68/push $_test-output-buffered-file->buffer/imm32
3358 e8/call clear-stream/disp32
3360 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3361 # emit-indirect-mode(_test-output-buffered-file, 0, 4/none, 0, 0)
3363 68/push 0/imm32/.disp
3364 68/push 0/imm32/.scale
3365 68/push 4/imm32/.index/none
3366 68/push 0/imm32/.base
3367 68/push _test-output-buffered-file/imm32
3369 e8/call emit-indirect-mode/disp32
3371 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3372 # . flush(_test-output-buffered-file)
3374 68/push _test-output-buffered-file/imm32
3376 e8/call flush/disp32
3378 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3379 #? # dump output {{{
3380 #? # . write(2/stderr, "^")
3382 #? 68/push "^"/imm32
3383 #? 68/push 2/imm32/stderr
3385 #? e8/call write/disp32
3386 #? # . . discard args
3387 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3388 #? # . write-stream(2/stderr, _test-output-stream)
3390 #? 68/push _test-output-stream/imm32
3391 #? 68/push 2/imm32/stderr
3393 #? e8/call write-stream/disp32
3394 #? # . . discard args
3395 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3396 #? # . write(2/stderr, "$\n")
3398 #? 68/push "$\n"/imm32
3399 #? 68/push 2/imm32/stderr
3401 #? e8/call write/disp32
3402 #? # . . discard args
3403 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3405 # check-stream-equal(_test-output-stream, "0/mod/indirect 0/rm32", msg)
3407 68/push "F - test-emit-indirect-mode"/imm32
3408 68/push "0/mod/indirect 0x00000000/rm32"/imm32
3409 68/push _test-output-stream/imm32
3411 e8/call check-stream-equal/disp32
3413 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3415 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3419 test-emit-indirect-mode-2:
3422 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3424 # . clear-stream(_test-output-stream)
3426 68/push _test-output-stream/imm32
3428 e8/call clear-stream/disp32
3430 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3431 # . clear-stream($_test-output-buffered-file->buffer)
3433 68/push $_test-output-buffered-file->buffer/imm32
3435 e8/call clear-stream/disp32
3437 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3438 # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 0)
3440 68/push 0/imm32/.disp
3441 68/push 0/imm32/.scale
3442 68/push 4/imm32/.index/none
3443 68/push 7/imm32/.base
3444 68/push _test-output-buffered-file/imm32
3446 e8/call emit-indirect-mode/disp32
3448 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3449 # . flush(_test-output-buffered-file)
3451 68/push _test-output-buffered-file/imm32
3453 e8/call flush/disp32
3455 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3456 #? # dump output {{{
3457 #? # . write(2/stderr, "^")
3459 #? 68/push "^"/imm32
3460 #? 68/push 2/imm32/stderr
3462 #? e8/call write/disp32
3463 #? # . . discard args
3464 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3465 #? # . write-stream(2/stderr, _test-output-stream)
3467 #? 68/push _test-output-stream/imm32
3468 #? 68/push 2/imm32/stderr
3470 #? e8/call write-stream/disp32
3471 #? # . . discard args
3472 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3473 #? # . write(2/stderr, "$\n")
3475 #? 68/push "$\n"/imm32
3476 #? 68/push 2/imm32/stderr
3478 #? e8/call write/disp32
3479 #? # . . discard args
3480 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3482 # check-stream-equal(_test-output-stream, "0/mod/indirect 7/rm32", msg)
3484 68/push "F - test-emit-indirect-mode-2"/imm32
3485 68/push "0/mod/indirect 0x00000007/rm32"/imm32
3486 68/push _test-output-stream/imm32
3488 e8/call check-stream-equal/disp32
3490 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3492 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3496 test-emit-indirect-mode-with-disp:
3499 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3501 # . clear-stream(_test-output-stream)
3503 68/push _test-output-stream/imm32
3505 e8/call clear-stream/disp32
3507 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3508 # . clear-stream($_test-output-buffered-file->buffer)
3510 68/push $_test-output-buffered-file->buffer/imm32
3512 e8/call clear-stream/disp32
3514 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3515 # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 4)
3517 68/push 4/imm32/.disp
3518 68/push 0/imm32/.scale
3519 68/push 4/imm32/.index/none
3520 68/push 6/imm32/.base
3521 68/push _test-output-buffered-file/imm32
3523 e8/call emit-indirect-mode/disp32
3525 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3526 # . flush(_test-output-buffered-file)
3528 68/push _test-output-buffered-file/imm32
3530 e8/call flush/disp32
3532 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3533 #? # dump output {{{
3534 #? # . write(2/stderr, "^")
3536 #? 68/push "^"/imm32
3537 #? 68/push 2/imm32/stderr
3539 #? e8/call write/disp32
3540 #? # . . discard args
3541 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3542 #? # . write-stream(2/stderr, _test-output-stream)
3544 #? 68/push _test-output-stream/imm32
3545 #? 68/push 2/imm32/stderr
3547 #? e8/call write-stream/disp32
3548 #? # . . discard args
3549 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3550 #? # . write(2/stderr, "$\n")
3552 #? 68/push "$\n"/imm32
3553 #? 68/push 2/imm32/stderr
3555 #? e8/call write/disp32
3556 #? # . . discard args
3557 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3559 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 4/disp32", msg)
3561 68/push "F - test-emit-indirect-mode-with-disp"/imm32
3562 68/push "2/mod/*+disp32 0x00000006/rm32 0x00000004/disp32"/imm32
3563 68/push _test-output-stream/imm32
3565 e8/call check-stream-equal/disp32
3567 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3569 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3573 test-emit-indirect-mode-with-disp-negative:
3576 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3578 # . clear-stream(_test-output-stream)
3580 68/push _test-output-stream/imm32
3582 e8/call clear-stream/disp32
3584 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3585 # . clear-stream($_test-output-buffered-file->buffer)
3587 68/push $_test-output-buffered-file->buffer/imm32
3589 e8/call clear-stream/disp32
3591 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3592 # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, -4)
3594 68/push -4/imm32/.disp
3595 68/push 0/imm32/.scale
3596 68/push 4/imm32/.index/none
3597 68/push 6/imm32/.base
3598 68/push _test-output-buffered-file/imm32
3600 e8/call emit-indirect-mode/disp32
3602 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3603 # . flush(_test-output-buffered-file)
3605 68/push _test-output-buffered-file/imm32
3607 e8/call flush/disp32
3609 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3610 #? # dump output {{{
3611 #? # . write(2/stderr, "^")
3613 #? 68/push "^"/imm32
3614 #? 68/push 2/imm32/stderr
3616 #? e8/call write/disp32
3617 #? # . . discard args
3618 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3619 #? # . write-stream(2/stderr, _test-output-stream)
3621 #? 68/push _test-output-stream/imm32
3622 #? 68/push 2/imm32/stderr
3624 #? e8/call write-stream/disp32
3625 #? # . . discard args
3626 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3627 #? # . write(2/stderr, "$\n")
3629 #? 68/push "$\n"/imm32
3630 #? 68/push 2/imm32/stderr
3632 #? e8/call write/disp32
3633 #? # . . discard args
3634 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3636 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 -4/disp32", msg)
3638 68/push "F - test-emit-indirect-mode-with-disp"/imm32
3639 68/push "2/mod/*+disp32 0x00000006/rm32 0xfffffffc/disp32"/imm32
3640 68/push _test-output-stream/imm32
3642 e8/call check-stream-equal/disp32
3644 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3646 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3650 test-emit-indirect-mode-with-sib:
3653 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3655 # . clear-stream(_test-output-stream)
3657 68/push _test-output-stream/imm32
3659 e8/call clear-stream/disp32
3661 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3662 # . clear-stream($_test-output-buffered-file->buffer)
3664 68/push $_test-output-buffered-file->buffer/imm32
3666 e8/call clear-stream/disp32
3668 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3669 # emit-indirect-mode(_test-output-buffered-file, 6/base, 1/index, 2/scale, 4/disp)
3671 68/push 4/imm32/.disp
3672 68/push 2/imm32/.scale
3673 68/push 1/imm32/.index
3674 68/push 6/imm32/.base
3675 68/push _test-output-buffered-file/imm32
3677 e8/call emit-indirect-mode/disp32
3679 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3680 # . flush(_test-output-buffered-file)
3682 68/push _test-output-buffered-file/imm32
3684 e8/call flush/disp32
3686 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3687 #? # dump output {{{
3688 #? # . write(2/stderr, "^")
3690 #? 68/push "^"/imm32
3691 #? 68/push 2/imm32/stderr
3693 #? e8/call write/disp32
3694 #? # . . discard args
3695 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3696 #? # . write-stream(2/stderr, _test-output-stream)
3698 #? 68/push _test-output-stream/imm32
3699 #? 68/push 2/imm32/stderr
3701 #? e8/call write-stream/disp32
3702 #? # . . discard args
3703 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3704 #? # . write(2/stderr, "$\n")
3706 #? 68/push "$\n"/imm32
3707 #? 68/push 2/imm32/stderr
3709 #? e8/call write/disp32
3710 #? # . . discard args
3711 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3713 # check-stream-equal(_test-output-stream, "2/mod/indirect 4/rm32/sib 6/base 1/index 2/scale 4/disp", msg)
3715 68/push "F - test-emit-indirect-mode-with-sib"/imm32
3716 68/push "2/mod/*+disp32 4/rm32/sib 0x00000006/base 0x00000001/index 0x00000002/scale 0x00000004/disp32"/imm32
3717 68/push _test-output-stream/imm32
3719 e8/call check-stream-equal/disp32
3721 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3723 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3727 test-emit-indirect-mode-ebp:
3730 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3732 # . clear-stream(_test-output-stream)
3734 68/push _test-output-stream/imm32
3736 e8/call clear-stream/disp32
3738 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3739 # . clear-stream($_test-output-buffered-file->buffer)
3741 68/push $_test-output-buffered-file->buffer/imm32
3743 e8/call clear-stream/disp32
3745 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3746 # emit-indirect-mode(_test-output-buffered-file, 5/base, 0/index, 0/scale, 0/disp)
3748 68/push 0/imm32/.disp
3749 68/push 0/imm32/.scale
3750 68/push 0/imm32/.index
3751 68/push 5/imm32/.base/ebp
3752 68/push _test-output-buffered-file/imm32
3754 e8/call emit-indirect-mode/disp32
3756 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3757 # . flush(_test-output-buffered-file)
3759 68/push _test-output-buffered-file/imm32
3761 e8/call flush/disp32
3763 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3764 #? # dump output {{{
3765 #? # . write(2/stderr, "^")
3767 #? 68/push "^"/imm32
3768 #? 68/push 2/imm32/stderr
3770 #? e8/call write/disp32
3771 #? # . . discard args
3772 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3773 #? # . write-stream(2/stderr, _test-output-stream)
3775 #? 68/push _test-output-stream/imm32
3776 #? 68/push 2/imm32/stderr
3778 #? e8/call write-stream/disp32
3779 #? # . . discard args
3780 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3781 #? # . write(2/stderr, "$\n")
3783 #? 68/push "$\n"/imm32
3784 #? 68/push 2/imm32/stderr
3786 #? e8/call write/disp32
3787 #? # . . discard args
3788 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3790 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 4/rm32/sib 5/base/ebp 0/index 0/scale 0/disp32", msg)
3792 68/push "F - test-emit-indirect-mode-ebp"/imm32
3793 68/push "2/mod/*+disp32 4/rm32/sib 0x00000005/base 0x00000000/index 0x00000000/scale 0x00000000/disp32"/imm32
3794 68/push _test-output-stream/imm32
3796 e8/call check-stream-equal/disp32
3798 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3800 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3804 test-emit-indirect-mode-esp:
3807 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3809 # . clear-stream(_test-output-stream)
3811 68/push _test-output-stream/imm32
3813 e8/call clear-stream/disp32
3815 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3816 # . clear-stream($_test-output-buffered-file->buffer)
3818 68/push $_test-output-buffered-file->buffer/imm32
3820 e8/call clear-stream/disp32
3822 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3823 # emit-indirect-mode(_test-output-buffered-file, 4/base, 0/index, 0/scale, 0/disp)
3825 68/push 0/imm32/.disp
3826 68/push 0/imm32/.scale
3827 68/push 0/imm32/.index
3828 68/push 4/imm32/.base/esp
3829 68/push _test-output-buffered-file/imm32
3831 e8/call emit-indirect-mode/disp32
3833 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x14/imm32 # add to esp
3834 # . flush(_test-output-buffered-file)
3836 68/push _test-output-buffered-file/imm32
3838 e8/call flush/disp32
3840 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
3841 #? # dump output {{{
3842 #? # . write(2/stderr, "^")
3844 #? 68/push "^"/imm32
3845 #? 68/push 2/imm32/stderr
3847 #? e8/call write/disp32
3848 #? # . . discard args
3849 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3850 #? # . write-stream(2/stderr, _test-output-stream)
3852 #? 68/push _test-output-stream/imm32
3853 #? 68/push 2/imm32/stderr
3855 #? e8/call write-stream/disp32
3856 #? # . . discard args
3857 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3858 #? # . write(2/stderr, "$\n")
3860 #? 68/push "$\n"/imm32
3861 #? 68/push 2/imm32/stderr
3863 #? e8/call write/disp32
3864 #? # . . discard args
3865 #? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3867 # check-stream-equal(_test-output-stream, "2/mod/*+disp32 4/rm32/sib 4/base/ebp 0/index 0/scale 0/disp32", msg)
3869 68/push "F - test-emit-indirect-mode-esp"/imm32
3870 68/push "2/mod/*+disp32 4/rm32/sib 0x00000004/base 0x00000000/index 0x00000000/scale 0x00000000/disp32"/imm32
3871 68/push _test-output-stream/imm32
3873 e8/call check-stream-equal/disp32
3875 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3877 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3881 disp32-mode?: # in: (addr slice) -> reg/eax: boolean
3884 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3888 # var local-slice/esi: slice = {in->start, in->end}
3889 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
3890 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
3891 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
3892 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
3893 # ++local-slice->start to skip '*'
3894 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
3895 # if (*local-slice->start == '(') return false
3896 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
3897 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
3898 25/and-eax-with 0xff/imm32
3899 3d/compare-eax-and 0x28/imm32/open-paren
3900 74/jump-if-= $disp32-mode?:false/disp8
3901 $disp32-mode?:check-for-register:
3902 # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/")
3905 68/push 0x2f/imm32/slash
3906 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
3907 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
3909 e8/call next-token-from-slice/disp32
3911 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
3912 # reg-num/eax = maybe-get-slice(Registers, local-slice, row-size=12)
3914 68/push 0xc/imm32/row-size
3916 68/push Registers/imm32
3918 e8/call maybe-get-slice/disp32
3920 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
3921 # if (eax != 0) return false
3922 3d/compare-eax-and 0/imm32
3923 75/jump-if-!= $disp32-mode?:false/disp8
3925 b8/copy-to-eax 1/imm32/true
3926 eb/jump $disp32-mode?:end/disp8
3927 $disp32-mode?:false:
3928 b8/copy-to-eax 0/imm32/false
3931 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3932 # . restore registers
3936 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3940 emit-indirect-disp32: # out: (addr buffered-file), word-slice: (addr slice)
3943 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
3946 # var local-slice/esi: slice = {in->start, in->end}
3947 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
3948 ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
3949 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
3950 89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
3951 # ++local-slice->start to skip '*'
3952 ff 0/subop/increment 0/mod/indirect 6/rm32/esi . . . . . . # increment *esi
3953 # write-buffered(out, "0/mod/indirect 5/rm32/.disp32 ")
3955 68/push "0/mod/indirect 5/rm32/.disp32 "/imm32
3956 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3958 e8/call write-buffered/disp32
3960 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3961 # write-slice-buffered(out, local-slice)
3964 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3966 e8/call write-slice-buffered/disp32
3968 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3969 # write-buffered(out, "/disp32")
3971 68/push "/disp32"/imm32
3972 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
3974 e8/call write-buffered/disp32
3976 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3977 $emit-indirect-disp32:end:
3979 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
3980 # . restore registers
3983 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
3987 # assumes 'in' starts with optional '+' or '-', optional whitespace, and an unsigned integer
3988 # returns the value of the integer
3989 # side-effect: modifies 'in' to skip past the integer
3990 next-hex-int: # in: (addr slice) -> result/eax
3993 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4001 31/xor 3/mod/direct 7/rm32/edi . . . 7/r32/edi . . # clear edi
4003 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
4005 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx
4006 # curr/ecx = in->start
4007 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
4008 # negate?/ebx = false
4009 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
4011 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
4012 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4013 $next-hex-int:positive:
4014 # if (*curr == '+') ++curr
4015 3d/compare-eax-and 0x2b/imm32/+
4016 75/jump-if-!= $next-hex-int:negative/disp8
4019 eb/jump $next-hex-int:skip-whitespace/disp8
4020 $next-hex-int:negative:
4021 # else if (*curr == '-') ++curr, negate = true
4022 3d/compare-eax-and 0x2d/imm32/-
4023 75/jump-if-!= $next-hex-int:skip-whitespace/disp8
4024 $next-hex-int:need-to-negate:
4028 bb/copy-to-ebx 1/imm32/true
4030 $next-hex-int:skip-whitespace:
4033 # eax = skip-chars-matching-whitespace-in-slice(word-slice->start, word-slice->end)
4038 e8/call skip-chars-matching-whitespace-in-slice/disp32
4040 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
4042 89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx
4045 $next-hex-int:initial-0:
4046 # skip past leading '0x'
4047 # . if (*curr != '0') jump to loop
4048 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4049 3d/compare-eax-and 0x30/imm32/0
4050 75/jump-if-!= $next-hex-int:loop/disp8
4053 $next-hex-int:initial-0x:
4054 # . if (curr >= in->end) return result
4055 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
4056 73/jump-if-addr>= $next-hex-int:end/disp8
4057 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
4058 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
4059 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4060 3d/compare-eax-and 0x78/imm32/x
4061 75/jump-if-!= $next-hex-int:loop/disp8
4065 # if (curr >= in->end) break
4066 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
4067 73/jump-if-addr>= $next-hex-int:break/disp8
4068 # if (!hex-digit?(*curr)) break
4070 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4071 # . eax = hex-digit?(*curr)
4075 e8/call hex-digit?/disp32
4077 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4078 # . if (eax == false) break
4079 3d/compare-eax-and 0/imm32/false
4080 74/jump-if-= $next-hex-int:break/disp8
4081 # eax = from-hex-char(*curr)
4082 # . . copy arg to eax
4083 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4085 e8/call from-hex-char/disp32
4086 # result = result * 16 + eax
4087 c1/shift 4/subop/left 3/mod/direct 7/rm32/edi . . . . . 4/imm8 # shift edi left by 4 bits
4088 01/add 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # add eax to edi
4092 eb/jump $next-hex-int:loop/disp8
4093 $next-hex-int:break:
4094 # if (negate?) result = -result
4095 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32/false # compare ebx
4096 74/jump-if-= $next-hex-int:end/disp8
4097 $next-hex-int:negate:
4098 f7 3/subop/negate 3/mod/direct 7/rm32/edi . . . . . . # negate edi
4100 # word-slice->start = curr
4101 89/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy ecx to *esi
4103 89/copy 3/mod/direct 0/rm32/eax . . . 7/r32/edi . . # copy edi to eax
4104 # . restore registers
4111 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4115 $next-hex-int:abort:
4116 # . _write(2/stderr, error)
4118 68/push "next-hex-int: invalid hex char: "/imm32
4119 68/push 2/imm32/stderr
4121 e8/call _write/disp32
4123 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
4124 # . clear-stream($Stderr->buffer)
4128 68/push $Stderr->buffer/imm32
4130 e8/call clear-stream/disp32
4132 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4135 # . write-int32-hex-buffered(Stderr, eax)
4138 68/push Stderr/imm32
4140 e8/call write-int32-hex-buffered/disp32
4142 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
4145 68/push Stderr/imm32
4147 e8/call flush/disp32
4149 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4150 # . _write(2/stderr, "\n")
4152 68/push Newline/imm32
4153 68/push 2/imm32/stderr
4155 e8/call _write/disp32
4157 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
4159 bb/copy-to-ebx 1/imm32
4160 e8/call syscall_exit/disp32
4163 test-next-hex-int-single-digit:
4166 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4167 # (eax..ecx) = "+a)"
4168 b8/copy-to-eax "+a)"/imm32
4169 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4170 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
4171 05/add-to-eax 4/imm32
4172 # var slice/ecx = {eax, ecx}
4175 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4176 # eax = next-hex-int(slice)
4180 e8/call next-hex-int/disp32
4182 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4183 # check-ints-equal(eax, 0xa, msg)
4185 68/push "F - test-next-hex-int-single-digit"/imm32
4189 e8/call check-ints-equal/disp32
4191 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4193 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4197 test-next-hex-int-multi-digit:
4200 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4201 # (eax..ecx) = "+ 34a)"
4202 b8/copy-to-eax "+ 34a)"/imm32
4203 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4204 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
4205 05/add-to-eax 4/imm32
4206 # var slice/ecx = {eax, ecx}
4209 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4210 # eax = next-hex-int(slice)
4214 e8/call next-hex-int/disp32
4216 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4217 # check-ints-equal(eax, 0x34a, msg)
4219 68/push "F - test-next-hex-int-multi-digit"/imm32
4223 e8/call check-ints-equal/disp32
4225 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4227 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4231 test-next-hex-int-0x-prefix:
4234 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4235 # (eax..ecx) = "+0x34)"
4236 b8/copy-to-eax "+0x34)"/imm32
4237 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4238 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
4239 05/add-to-eax 4/imm32
4240 # var slice/ecx = {eax, ecx}
4243 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4244 # eax = next-hex-int(slice)
4248 e8/call next-hex-int/disp32
4250 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4251 # check-ints-equal(eax, 0x34, msg)
4253 68/push "F - test-next-hex-int-0x-prefix"/imm32
4257 e8/call check-ints-equal/disp32
4259 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4261 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4265 test-next-hex-int-zero:
4268 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4269 # (eax..ecx) = "+0)"
4270 b8/copy-to-eax "+0)"/imm32
4271 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4272 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
4273 05/add-to-eax 4/imm32
4274 # var slice/ecx = {eax, ecx}
4277 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4278 # eax = next-hex-int(slice)
4282 e8/call next-hex-int/disp32
4284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4285 # check-ints-equal(eax, 0, msg)
4287 68/push "F - test-next-hex-int-zero"/imm32
4291 e8/call check-ints-equal/disp32
4293 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4295 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4299 test-next-hex-int-0-prefix:
4302 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4303 # (eax..ecx) = "+ 03)"
4304 b8/copy-to-eax "+ 03)"/imm32
4305 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4306 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
4307 05/add-to-eax 4/imm32
4308 # var slice/ecx = {eax, ecx}
4311 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4312 # eax = next-hex-int(slice)
4316 e8/call next-hex-int/disp32
4318 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4319 # check-ints-equal(eax, 3, msg)
4321 68/push "F - test-next-hex-int-0-prefix"/imm32
4325 e8/call check-ints-equal/disp32
4327 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4329 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4333 test-next-hex-int-negative:
4336 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4337 # (eax..ecx) = "-03)"
4338 b8/copy-to-eax "-03)"/imm32
4339 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4340 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
4341 05/add-to-eax 4/imm32
4342 # var slice/ecx = {eax, ecx}
4345 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4346 # eax = next-hex-int(slice)
4350 e8/call next-hex-int/disp32
4352 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4353 # check-ints-equal(eax, -3, msg)
4355 68/push "F - test-next-hex-int-negative"/imm32
4359 e8/call check-ints-equal/disp32
4361 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4363 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4367 test-next-hex-int-negative-with-space:
4370 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4371 # (eax..ecx) = "- 03)"
4372 b8/copy-to-eax "- 03)"/imm32
4373 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4374 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
4375 05/add-to-eax 4/imm32
4376 # var slice/ecx = {eax, ecx}
4379 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4380 # eax = next-hex-int(slice)
4384 e8/call next-hex-int/disp32
4386 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4387 # check-ints-equal(eax, -3, msg)
4389 68/push "F - test-next-hex-int-negative-with-space"/imm32
4393 e8/call check-ints-equal/disp32
4395 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4397 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4401 # assumes 'in' starts a positive unsigned integer
4402 # returns the value of the integer
4403 # side-effect: modifies 'in' to skip past the integer
4404 next-positive-hex-int: # in: (addr slice) -> result/eax
4407 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4415 31/xor 3/mod/direct 7/rm32/edi . . . 7/r32/edi . . # clear edi
4417 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
4419 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx
4420 # curr/ecx = in->start
4421 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
4422 # negate?/ebx = false
4423 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
4425 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
4426 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4427 $next-positive-hex-int:initial-0:
4428 # skip past leading '0x'
4429 # . if (*curr != '0') jump to loop
4430 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4431 3d/compare-eax-and 0x30/imm32/0
4432 75/jump-if-!= $next-positive-hex-int:loop/disp8
4435 $next-positive-hex-int:initial-0x:
4436 # . if (curr >= in->end) return result
4437 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
4438 73/jump-if-addr>= $next-positive-hex-int:end/disp8
4439 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
4440 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
4441 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4442 3d/compare-eax-and 0x78/imm32/x
4443 75/jump-if-!= $next-positive-hex-int:loop/disp8
4446 $next-positive-hex-int:loop:
4447 # if (curr >= in->end) break
4448 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
4449 73/jump-if-addr>= $next-positive-hex-int:end/disp8
4450 # if (!hex-digit?(*curr)) break
4452 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4453 # . eax = hex-digit?(*curr)
4457 e8/call hex-digit?/disp32
4459 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4460 # . if (eax == false) break
4461 3d/compare-eax-and 0/imm32/false
4462 74/jump-if-= $next-positive-hex-int:end/disp8
4463 # eax = from-hex-char(*curr)
4464 # . . copy arg to eax
4465 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
4467 e8/call from-hex-char/disp32
4468 # result = result * 16 + eax
4469 c1/shift 4/subop/left 3/mod/direct 7/rm32/edi . . . . . 4/imm8 # shift edi left by 4 bits
4470 01/add 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # add eax to edi
4474 eb/jump $next-positive-hex-int:loop/disp8
4475 $next-positive-hex-int:end:
4476 # word-slice->start = curr
4477 89/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy ecx to *esi
4479 89/copy 3/mod/direct 0/rm32/eax . . . 7/r32/edi . . # copy edi to eax
4480 # . restore registers
4487 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4491 test-next-positive-hex-int-single-digit:
4494 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4496 b8/copy-to-eax "a)"/imm32
4497 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4498 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
4499 05/add-to-eax 4/imm32
4500 # var slice/ecx = {eax, ecx}
4503 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4504 # eax = next-positive-hex-int(slice)
4508 e8/call next-positive-hex-int/disp32
4510 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4511 # check-ints-equal(eax, 0xa, msg)
4513 68/push "F - test-next-positive-hex-int-single-digit"/imm32
4517 e8/call check-ints-equal/disp32
4519 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4521 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4525 test-next-positive-hex-int-multi-digit:
4528 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4529 # (eax..ecx) = "34a)"
4530 b8/copy-to-eax "34a)"/imm32
4531 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4532 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
4533 05/add-to-eax 4/imm32
4534 # var slice/ecx = {eax, ecx}
4537 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4538 # eax = next-positive-hex-int(slice)
4542 e8/call next-positive-hex-int/disp32
4544 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4545 # check-ints-equal(eax, 0x34a, msg)
4547 68/push "F - test-next-positive-hex-int-multi-digit"/imm32
4551 e8/call check-ints-equal/disp32
4553 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4555 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4559 test-next-positive-hex-int-0x-prefix:
4562 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4563 # (eax..ecx) = "0x34)"
4564 b8/copy-to-eax "0x34)"/imm32
4565 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4566 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
4567 05/add-to-eax 4/imm32
4568 # var slice/ecx = {eax, ecx}
4571 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4572 # eax = next-positive-hex-int(slice)
4576 e8/call next-positive-hex-int/disp32
4578 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4579 # check-ints-equal(eax, 0x34, msg)
4581 68/push "F - test-next-positive-hex-int-0x-prefix"/imm32
4585 e8/call check-ints-equal/disp32
4587 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4589 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4593 test-next-positive-hex-int-zero:
4596 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4598 b8/copy-to-eax "0"/imm32
4599 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4600 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
4601 05/add-to-eax 4/imm32
4602 # var slice/ecx = {eax, ecx}
4605 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4606 # eax = next-positive-hex-int(slice)
4610 e8/call next-positive-hex-int/disp32
4612 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4613 # check-ints-equal(eax, 0, msg)
4615 68/push "F - test-next-positive-hex-int-zero"/imm32
4619 e8/call check-ints-equal/disp32
4621 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4623 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4627 test-next-positive-hex-int-0-prefix:
4630 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
4631 # (eax..ecx) = "03)"
4632 b8/copy-to-eax "03)"/imm32
4633 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
4634 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
4635 05/add-to-eax 4/imm32
4636 # var slice/ecx = {eax, ecx}
4639 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
4640 # eax = next-positive-hex-int(slice)
4644 e8/call next-positive-hex-int/disp32
4646 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
4647 # check-ints-equal(eax, 3, msg)
4649 68/push "F - test-next-positive-hex-int-0-prefix"/imm32
4653 e8/call check-ints-equal/disp32
4655 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
4657 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
4661 # . . vim:nowrap:textwidth=0