.
[mu.git] / linux / sigils.subx
blobae2fc57625ae4efd05c96eddedc4145f37abdac4
1 # Syntax sugar for addressing modes that expand into /rm32 and other related
2 # arguments.
4 # To run:
5 #   $ bootstrap/bootstrap translate [012]*.subx subx-params.subx sigils.subx  -o sigils
7 # We currently support the following notations:
9 # 1.
10 #   $ echo '%eax'  |  bootstrap/bootstrap run sigils
11 #   3/mod 0/rm32
13 # 2.
14 #   $ echo '*eax'  |  bootstrap/bootstrap run sigils
15 #   0/mod 0/rm32
17 # 3.
18 #   $ echo '*(eax+4)'  |  bootstrap/bootstrap run sigils
19 #   2/mod 0/rm32 4/disp32
21 # 4.
22 #   $ echo '*(eax+ecx)'  |  bootstrap/bootstrap run sigils
23 #   0/mod 4/rm32 0/base 1/index 0/scale
25 # 5.
26 #   $ echo '*(eax+ecx+4)'  |  bootstrap/bootstrap run sigils
27 #   2/mod 4/rm32 0/base 1/index 0/scale 4/disp32
29 # 6.
30 #   $ echo '*(eax+ecx<<2+4)'  |  bootstrap/bootstrap run sigils
31 #   2/mod 4/rm32 0/base 1/index 2/scale 4/disp32
33 # 7.
34 #   $ echo '*Foo'  |  bootstrap/bootstrap run sigils
35 #   0/mod 5/rm32/.disp32 Foo/disp32
37 # TODO: *(Foo+ecx<<2)
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
42 # or index or scale.
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
53 == code
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
59     # . prologue
60     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
62     # initialize heap
63     # . Heap = new-segment(Heap-size)
64     # . . push args
65     68/push  Heap/imm32
66     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
67     # . . call
68     e8/call  new-segment/disp32
69     # . . discard args
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")
78     # . . push args
79     68/push  "test"/imm32
80     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
81     # . . call
82     e8/call  kernel-string-equal?/disp32
83     # . . discard args
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
88     # run-tests()
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)
96     # . . push args
97     68/push  Stdout/imm32
98     68/push  Stdin/imm32
99     # . . call
100     e8/call  subx-sigils/disp32
101     # . . discard args
102     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
103     # syscall_exit(0)
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)
111     # pseudocode:
112     #   var line: (stream byte 512)
113     #   while true
114     #     clear-stream(line)
115     #     read-line-buffered(in, line)
116     #     if (line->write == 0) break                     # end of file
117     #     while true
118     #       var word-slice = next-word-or-expression(line)
119     #       if slice-empty?(word-slice)                   # end of line
120     #         break
121     #       if slice-starts-with?(word-slice, "#")        # comment
122     #         continue
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)
128     #         else
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 '*(...)'")
133     #       else
134     #         write-slice-buffered(out, word-slice)
135     #       write(out, " ")
136     #     write(out, "\n")
137     #   flush(out)
138     #
139     # . prologue
140     55/push-ebp
141     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
142     # . save registers
143     50/push-eax
144     51/push-ecx
145     52/push-edx
146     53/push-ebx
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
150     68/push  0/imm32/read
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
154     68/push  0/imm32/end
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:
158     # clear-stream(line)
159     # . . push args
160     51/push-ecx
161     # . . call
162     e8/call  clear-stream/disp32
163     # . . discard args
164     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
165     # read-line-buffered(in, line)
166     # . . push args
167     51/push-ecx
168     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
169     # . . call
170     e8/call  read-line-buffered/disp32
171     # . . discard args
172     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
173 $subx-sigils:check0:
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)
179     # . . push args
180     52/push-edx
181     51/push-ecx
182     # . . call
183     e8/call  next-word-or-expression/disp32
184     # . . discard args
185     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
186 $subx-sigils:check1:
187     # if (slice-empty?(word-slice)) break
188     # . eax = slice-empty?(word-slice)
189     # . . push args
190     52/push-edx
191     # . . call
192     e8/call  slice-empty?/disp32
193     # . . discard args
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
202     # . c/eax = *start
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: ")
215 #?     # . . push args
216 #?     68/push  "w: "/imm32
217 #?     68/push  2/imm32/stderr
218 #?     # . . call
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)
223 #?     # . . push args
224 #?     68/push  $Stderr->buffer/imm32
225 #?     # . . call
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)
230 #?     # . . push args
231 #?     52/push-edx
232 #?     68/push  Stderr/imm32
233 #?     # . . call
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
237 #?     # . flush(Stderr)
238 #?     # . . push args
239 #?     68/push  Stderr/imm32
240 #?     # . . call
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")
245 #?     # . . push args
246 #?     68/push  "$\n"/imm32
247 #?     68/push  2/imm32/stderr
248 #?     # . . call
249 #?     e8/call  write/disp32
250 #?     # . . discard args
251 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
252 #?     # }}}
253     # emit-direct-mode(out, word-slice)
254     # . . push args
255     52/push-edx
256     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
257     # . . call
258     e8/call  emit-direct-mode/disp32
259     # . . discard args
260     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
261     # continue
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)
269     # . . push args
270     52/push-edx
271     # . . call
272     e8/call  disp32-mode?/disp32
273     # . . discard args
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)
280     # . . push args
281     52/push-edx
282     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
283     # . . call
284     e8/call  emit-indirect-disp32/disp32
285     # . . discard args
286     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
287     # continue
288     e9/jump  $subx-sigils:next-word/disp32
289 $subx-sigils:indirect-mode:
290     # spill registers
291     50/push-eax
292     51/push-ecx
293     52/push-edx
294     53/push-ebx
295     # base/eax, index/ecx, scale/edx, disp/ebx = parse-effective-address(word-slice)
296     # . . push args
297     52/push-edx
298     # . . call
299     e8/call  parse-effective-address/disp32
300     # . . discard args
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)
303     # . . push args
304     53/push-ebx
305     52/push-edx
306     51/push-ecx
307     50/push-eax
308     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
309     # . . call
310     e8/call  emit-indirect-mode/disp32
311     # . . discard args
312     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
313     # restore registers
314     5b/pop-to-ebx
315     5a/pop-to-edx
316     59/pop-to-ecx
317     58/pop-to-eax
318     # continue
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)
330     # . . push args
331     52/push-edx
332     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
333     # . . call
334     e8/call  write-slice-buffered/disp32
335     # . . discard args
336     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
337     # fall through
338 $subx-sigils:next-word:
339     # write-buffered(out, " ")
340     # . . push args
341     68/push  Space/imm32
342     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
343     # . . call
344     e8/call  write-buffered/disp32
345     # . . discard args
346     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
347     # loop
348     e9/jump  $subx-sigils:word-loop/disp32
349 $subx-sigils:next-line:
350     # write-buffered(out, "\n")
351     # . . push args
352     68/push  Newline/imm32
353     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
354     # . . call
355     e8/call  write-buffered/disp32
356     # . . discard args
357     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
358     # loop
359     e9/jump  $subx-sigils:line-loop/disp32
360 $subx-sigils:break:
361     # flush(out)
362     # . . push args
363     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
364     # . . call
365     e8/call  flush/disp32
366     # . . discard args
367     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
368 $subx-sigils:end:
369     # . reclaim locals
370     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x214/imm32       # add to esp
371     # . restore registers
372     5b/pop-to-ebx
373     5a/pop-to-edx
374     59/pop-to-ecx
375     58/pop-to-eax
376     # . epilogue
377     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
378     5d/pop-to-ebp
379     c3/return
381 $subx-sigils:error1:
382     # print(stderr, "error: '" eax "' only permitted within '*(...)' in '" line "'")
383     # . write-buffered(Stderr, "error: '")
384     # . . push args
385     68/push  "error: '"/imm32
386     68/push  Stderr/imm32
387     # . . call
388     e8/call  write-buffered/disp32
389     # . . discard args
390     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
391     # . write-byte-buffered(Stderr, eax)
392     # . . push args
393     50/push-eax
394     68/push  Stderr/imm32
395     # . . call
396     e8/call  write-byte-buffered/disp32
397     # . . discard args
398     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
399     # . write-buffered(Stderr, "' only permitted within '*(...)' in '")
400     # . . push args
401     68/push  "' only permitted within '*(...)' in '"/imm32
402     68/push  Stderr/imm32
403     # . . call
404     e8/call  write-buffered/disp32
405     # . . discard args
406     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
407     # . write-stream-data(Stderr, line)
408     # . . push args
409     51/push-ecx
410     68/push  Stderr/imm32
411     # . . call
412     e8/call  write-stream-data/disp32
413     # . . discard args
414     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
415     # . write-buffered(Stderr, "'")
416     # . . push args
417     68/push  "'"/imm32
418     68/push  Stderr/imm32
419     # . . call
420     e8/call  write-buffered/disp32
421     # . . discard args
422     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
423     # . flush(Stderr)
424     # . . push args
425     68/push  Stderr/imm32
426     # . . call
427     e8/call  flush/disp32
428     # . . discard args
429     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
430     # . syscall_exit(1)
431     bb/copy-to-ebx  1/imm32
432     e8/call  syscall_exit/disp32
433     # never gets here
435 test-subx-sigils-passes-most-words-through:
436     # . prologue
437     55/push-ebp
438     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
439     # setup
440     # . clear-stream(_test-input-stream)
441     # . . push args
442     68/push  _test-input-stream/imm32
443     # . . call
444     e8/call  clear-stream/disp32
445     # . . discard args
446     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
447     # . clear-stream($_test-input-buffered-file->buffer)
448     # . . push args
449     68/push  $_test-input-buffered-file->buffer/imm32
450     # . . call
451     e8/call  clear-stream/disp32
452     # . . discard args
453     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
454     # . clear-stream(_test-output-stream)
455     # . . push args
456     68/push  _test-output-stream/imm32
457     # . . call
458     e8/call  clear-stream/disp32
459     # . . discard args
460     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
461     # . clear-stream($_test-output-buffered-file->buffer)
462     # . . push args
463     68/push  $_test-output-buffered-file->buffer/imm32
464     # . . call
465     e8/call  clear-stream/disp32
466     # . . discard args
467     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
468     # initialize input
469     # . write(_test-input-stream, "== abcd 0x1")
470     # . . push args
471     68/push  "== abcd 0x1"/imm32
472     68/push  _test-input-stream/imm32
473     # . . call
474     e8/call  write/disp32
475     # . . discard args
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)
478     # . . push args
479     68/push  _test-output-buffered-file/imm32
480     68/push  _test-input-buffered-file/imm32
481     # . . call
482     e8/call  subx-sigils/disp32
483     # . . discard args
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)
487     # . . push args
488     68/push  _test-output-buffered-file/imm32
489     # . . call
490     e8/call  flush/disp32
491     # . . discard args
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, "^")
495 #?     # . . push args
496 #?     68/push  "^"/imm32
497 #?     68/push  2/imm32/stderr
498 #?     # . . call
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)
503 #?     # . . push args
504 #?     68/push  _test-output-stream/imm32
505 #?     68/push  2/imm32/stderr
506 #?     # . . call
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")
511 #?     # . . push args
512 #?     68/push  "$\n"/imm32
513 #?     68/push  2/imm32/stderr
514 #?     # . . call
515 #?     e8/call  write/disp32
516 #?     # . . discard args
517 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
518 #?     # }}}
519     # . check-stream-equal(_test-output-stream, "== abcd 0x1 \n", msg)
520     # . . push args
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
524     # . . call
525     e8/call  check-stream-equal/disp32
526     # . . discard args
527     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
528     # . epilogue
529     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
530     5d/pop-to-ebp
531     c3/return
533 test-subx-sigils-direct-mode:
534     # . prologue
535     55/push-ebp
536     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
537     # setup
538     # . clear-stream(_test-input-stream)
539     # . . push args
540     68/push  _test-input-stream/imm32
541     # . . call
542     e8/call  clear-stream/disp32
543     # . . discard args
544     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
545     # . clear-stream($_test-input-buffered-file->buffer)
546     # . . push args
547     68/push  $_test-input-buffered-file->buffer/imm32
548     # . . call
549     e8/call  clear-stream/disp32
550     # . . discard args
551     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
552     # . clear-stream(_test-output-stream)
553     # . . push args
554     68/push  _test-output-stream/imm32
555     # . . call
556     e8/call  clear-stream/disp32
557     # . . discard args
558     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
559     # . clear-stream($_test-output-buffered-file->buffer)
560     # . . push args
561     68/push  $_test-output-buffered-file->buffer/imm32
562     # . . call
563     e8/call  clear-stream/disp32
564     # . . discard args
565     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
566     # initialize input
567     # . write(_test-input-stream, "ab %ecx")
568     # . . push args
569     68/push  "ab %ecx"/imm32
570     68/push  _test-input-stream/imm32
571     # . . call
572     e8/call  write/disp32
573     # . . discard args
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)
576     # . . push args
577     68/push  _test-output-buffered-file/imm32
578     68/push  _test-input-buffered-file/imm32
579     # . . call
580     e8/call  subx-sigils/disp32
581     # . . discard args
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)
585     # . . push args
586     68/push  _test-output-buffered-file/imm32
587     # . . call
588     e8/call  flush/disp32
589     # . . discard args
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, "^")
593 #?     # . . push args
594 #?     68/push  "^"/imm32
595 #?     68/push  2/imm32/stderr
596 #?     # . . call
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)
601 #?     # . . push args
602 #?     68/push  _test-output-stream/imm32
603 #?     68/push  2/imm32/stderr
604 #?     # . . call
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")
609 #?     # . . push args
610 #?     68/push  "$\n"/imm32
611 #?     68/push  2/imm32/stderr
612 #?     # . . call
613 #?     e8/call  write/disp32
614 #?     # . . discard args
615 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
616 #?     # }}}
617     # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg)
618     # . . push args
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
622     # . . call
623     e8/call  check-stream-equal/disp32
624     # . . discard args
625     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
626     # . epilogue
627     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
628     5d/pop-to-ebp
629     c3/return
631 test-subx-sigils-direct-mode-with-metadata:
632     # . prologue
633     55/push-ebp
634     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
635     # setup
636     # . clear-stream(_test-input-stream)
637     # . . push args
638     68/push  _test-input-stream/imm32
639     # . . call
640     e8/call  clear-stream/disp32
641     # . . discard args
642     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
643     # . clear-stream($_test-input-buffered-file->buffer)
644     # . . push args
645     68/push  $_test-input-buffered-file->buffer/imm32
646     # . . call
647     e8/call  clear-stream/disp32
648     # . . discard args
649     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
650     # . clear-stream(_test-output-stream)
651     # . . push args
652     68/push  _test-output-stream/imm32
653     # . . call
654     e8/call  clear-stream/disp32
655     # . . discard args
656     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
657     # . clear-stream($_test-output-buffered-file->buffer)
658     # . . push args
659     68/push  $_test-output-buffered-file->buffer/imm32
660     # . . call
661     e8/call  clear-stream/disp32
662     # . . discard args
663     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
664     # initialize input
665     # . write(_test-input-stream, "ab %ecx/foo")
666     # . . push args
667     68/push  "ab %ecx/foo"/imm32
668     68/push  _test-input-stream/imm32
669     # . . call
670     e8/call  write/disp32
671     # . . discard args
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)
674     # . . push args
675     68/push  _test-output-buffered-file/imm32
676     68/push  _test-input-buffered-file/imm32
677     # . . call
678     e8/call  subx-sigils/disp32
679     # . . discard args
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)
683     # . . push args
684     68/push  _test-output-buffered-file/imm32
685     # . . call
686     e8/call  flush/disp32
687     # . . discard args
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)
690     # . . push args
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
694     # . . call
695     e8/call  check-stream-equal/disp32
696     # . . discard args
697     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
698     # . epilogue
699     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
700     5d/pop-to-ebp
701     c3/return
703 test-subx-sigils-register-indirect-mode:
704     # . prologue
705     55/push-ebp
706     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
707     # setup
708     # . clear-stream(_test-input-stream)
709     # . . push args
710     68/push  _test-input-stream/imm32
711     # . . call
712     e8/call  clear-stream/disp32
713     # . . discard args
714     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
715     # . clear-stream($_test-input-buffered-file->buffer)
716     # . . push args
717     68/push  $_test-input-buffered-file->buffer/imm32
718     # . . call
719     e8/call  clear-stream/disp32
720     # . . discard args
721     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
722     # . clear-stream(_test-output-stream)
723     # . . push args
724     68/push  _test-output-stream/imm32
725     # . . call
726     e8/call  clear-stream/disp32
727     # . . discard args
728     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
729     # . clear-stream($_test-output-buffered-file->buffer)
730     # . . push args
731     68/push  $_test-output-buffered-file->buffer/imm32
732     # . . call
733     e8/call  clear-stream/disp32
734     # . . discard args
735     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
736     # initialize input
737     # . write(_test-input-stream, "ab *ecx")
738     # . . push args
739     68/push  "ab *ecx"/imm32
740     68/push  _test-input-stream/imm32
741     # . . call
742     e8/call  write/disp32
743     # . . discard args
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)
746     # . . push args
747     68/push  _test-output-buffered-file/imm32
748     68/push  _test-input-buffered-file/imm32
749     # . . call
750     e8/call  subx-sigils/disp32
751     # . . discard args
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)
755     # . . push args
756     68/push  _test-output-buffered-file/imm32
757     # . . call
758     e8/call  flush/disp32
759     # . . discard args
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, "^")
763 #?     # . . push args
764 #?     68/push  "^"/imm32
765 #?     68/push  2/imm32/stderr
766 #?     # . . call
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)
771 #?     # . . push args
772 #?     68/push  _test-output-stream/imm32
773 #?     68/push  2/imm32/stderr
774 #?     # . . call
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")
779 #?     # . . push args
780 #?     68/push  "$\n"/imm32
781 #?     68/push  2/imm32/stderr
782 #?     # . . call
783 #?     e8/call  write/disp32
784 #?     # . . discard args
785 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
786 #?     # }}}
787     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg)
788     # . . push args
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
792     # . . call
793     e8/call  check-stream-equal/disp32
794     # . . discard args
795     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
796     # . epilogue
797     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
798     5d/pop-to-ebp
799     c3/return
801 test-subx-sigils-register-indirect-mode-with-metadata:
802     # . prologue
803     55/push-ebp
804     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
805     # setup
806     # . clear-stream(_test-input-stream)
807     # . . push args
808     68/push  _test-input-stream/imm32
809     # . . call
810     e8/call  clear-stream/disp32
811     # . . discard args
812     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
813     # . clear-stream($_test-input-buffered-file->buffer)
814     # . . push args
815     68/push  $_test-input-buffered-file->buffer/imm32
816     # . . call
817     e8/call  clear-stream/disp32
818     # . . discard args
819     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
820     # . clear-stream(_test-output-stream)
821     # . . push args
822     68/push  _test-output-stream/imm32
823     # . . call
824     e8/call  clear-stream/disp32
825     # . . discard args
826     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
827     # . clear-stream($_test-output-buffered-file->buffer)
828     # . . push args
829     68/push  $_test-output-buffered-file->buffer/imm32
830     # . . call
831     e8/call  clear-stream/disp32
832     # . . discard args
833     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
834     # initialize input
835     # . write(_test-input-stream, "ab *ecx/foo")
836     # . . push args
837     68/push  "ab *ecx/foo"/imm32
838     68/push  _test-input-stream/imm32
839     # . . call
840     e8/call  write/disp32
841     # . . discard args
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)
844     # . . push args
845     68/push  _test-output-buffered-file/imm32
846     68/push  _test-input-buffered-file/imm32
847     # . . call
848     e8/call  subx-sigils/disp32
849     # . . discard args
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)
853     # . . push args
854     68/push  _test-output-buffered-file/imm32
855     # . . call
856     e8/call  flush/disp32
857     # . . discard args
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)
860     # . . push args
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
864     # . . call
865     e8/call  check-stream-equal/disp32
866     # . . discard args
867     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
868     # . epilogue
869     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
870     5d/pop-to-ebp
871     c3/return
873 test-subx-sigils-register-indirect-mode-without-displacement:
874     # . prologue
875     55/push-ebp
876     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
877     # setup
878     # . clear-stream(_test-input-stream)
879     # . . push args
880     68/push  _test-input-stream/imm32
881     # . . call
882     e8/call  clear-stream/disp32
883     # . . discard args
884     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
885     # . clear-stream($_test-input-buffered-file->buffer)
886     # . . push args
887     68/push  $_test-input-buffered-file->buffer/imm32
888     # . . call
889     e8/call  clear-stream/disp32
890     # . . discard args
891     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
892     # . clear-stream(_test-output-stream)
893     # . . push args
894     68/push  _test-output-stream/imm32
895     # . . call
896     e8/call  clear-stream/disp32
897     # . . discard args
898     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
899     # . clear-stream($_test-output-buffered-file->buffer)
900     # . . push args
901     68/push  $_test-output-buffered-file->buffer/imm32
902     # . . call
903     e8/call  clear-stream/disp32
904     # . . discard args
905     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
906     # initialize input
907     # . write(_test-input-stream, "ab *(ecx)")
908     # . . push args
909     68/push  "ab *(ecx)"/imm32
910     68/push  _test-input-stream/imm32
911     # . . call
912     e8/call  write/disp32
913     # . . discard args
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)
916     # . . push args
917     68/push  _test-output-buffered-file/imm32
918     68/push  _test-input-buffered-file/imm32
919     # . . call
920     e8/call  subx-sigils/disp32
921     # . . discard args
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)
925     # . . push args
926     68/push  _test-output-buffered-file/imm32
927     # . . call
928     e8/call  flush/disp32
929     # . . discard args
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, "^")
933 #?     # . . push args
934 #?     68/push  "^"/imm32
935 #?     68/push  2/imm32/stderr
936 #?     # . . call
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)
941 #?     # . . push args
942 #?     68/push  _test-output-stream/imm32
943 #?     68/push  2/imm32/stderr
944 #?     # . . call
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")
949 #?     # . . push args
950 #?     68/push  "$\n"/imm32
951 #?     68/push  2/imm32/stderr
952 #?     # . . call
953 #?     e8/call  write/disp32
954 #?     # . . discard args
955 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
956 #?     # }}}
957     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 1/rm32 \n", msg)
958     # . . push args
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
962     # . . call
963     e8/call  check-stream-equal/disp32
964     # . . discard args
965     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
966     # . epilogue
967     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
968     5d/pop-to-ebp
969     c3/return
971 test-subx-sigils-register-indirect-mode-with-displacement:
972     # . prologue
973     55/push-ebp
974     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
975     # setup
976     # . clear-stream(_test-input-stream)
977     # . . push args
978     68/push  _test-input-stream/imm32
979     # . . call
980     e8/call  clear-stream/disp32
981     # . . discard args
982     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
983     # . clear-stream($_test-input-buffered-file->buffer)
984     # . . push args
985     68/push  $_test-input-buffered-file->buffer/imm32
986     # . . call
987     e8/call  clear-stream/disp32
988     # . . discard args
989     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
990     # . clear-stream(_test-output-stream)
991     # . . push args
992     68/push  _test-output-stream/imm32
993     # . . call
994     e8/call  clear-stream/disp32
995     # . . discard args
996     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
997     # . clear-stream($_test-output-buffered-file->buffer)
998     # . . push args
999     68/push  $_test-output-buffered-file->buffer/imm32
1000     # . . call
1001     e8/call  clear-stream/disp32
1002     # . . discard args
1003     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1004     # initialize input
1005     # . write(_test-input-stream, "ab *(ecx+4)")
1006     # . . push args
1007     68/push  "ab *(ecx+4)"/imm32
1008     68/push  _test-input-stream/imm32
1009     # . . call
1010     e8/call  write/disp32
1011     # . . discard args
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)
1014     # . . push args
1015     68/push  _test-output-buffered-file/imm32
1016     68/push  _test-input-buffered-file/imm32
1017     # . . call
1018     e8/call  subx-sigils/disp32
1019     # . . discard args
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)
1023     # . . push args
1024     68/push  _test-output-buffered-file/imm32
1025     # . . call
1026     e8/call  flush/disp32
1027     # . . discard args
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, "^")
1031 #?     # . . push args
1032 #?     68/push  "^"/imm32
1033 #?     68/push  2/imm32/stderr
1034 #?     # . . call
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)
1039 #?     # . . push args
1040 #?     68/push  _test-output-stream/imm32
1041 #?     68/push  2/imm32/stderr
1042 #?     # . . call
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")
1047 #?     # . . push args
1048 #?     68/push  "$\n"/imm32
1049 #?     68/push  2/imm32/stderr
1050 #?     # . . call
1051 #?     e8/call  write/disp32
1052 #?     # . . discard args
1053 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1054 #?     # }}}
1055     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 1/rm32 4/disp32 \n", msg)
1056     # . . push args
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
1060     # . . call
1061     e8/call  check-stream-equal/disp32
1062     # . . discard args
1063     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1064     # . epilogue
1065     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1066     5d/pop-to-ebp
1067     c3/return
1069 # boss level
1070 test-subx-sigils-register-indirect-mode-with-sib-byte:
1071     # . prologue
1072     55/push-ebp
1073     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1074     # setup
1075     # . clear-stream(_test-input-stream)
1076     # . . push args
1077     68/push  _test-input-stream/imm32
1078     # . . call
1079     e8/call  clear-stream/disp32
1080     # . . discard args
1081     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1082     # . clear-stream($_test-input-buffered-file->buffer)
1083     # . . push args
1084     68/push  $_test-input-buffered-file->buffer/imm32
1085     # . . call
1086     e8/call  clear-stream/disp32
1087     # . . discard args
1088     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1089     # . clear-stream(_test-output-stream)
1090     # . . push args
1091     68/push  _test-output-stream/imm32
1092     # . . call
1093     e8/call  clear-stream/disp32
1094     # . . discard args
1095     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1096     # . clear-stream($_test-output-buffered-file->buffer)
1097     # . . push args
1098     68/push  $_test-output-buffered-file->buffer/imm32
1099     # . . call
1100     e8/call  clear-stream/disp32
1101     # . . discard args
1102     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1103     # initialize input
1104     # . write(_test-input-stream, "ab *(ecx + edx<<3 + 4)")
1105     # . . push args
1106     68/push  "ab *(ecx + edx<<3 + 4)"/imm32
1107     68/push  _test-input-stream/imm32
1108     # . . call
1109     e8/call  write/disp32
1110     # . . discard args
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)
1113     # . . push args
1114     68/push  _test-output-buffered-file/imm32
1115     68/push  _test-input-buffered-file/imm32
1116     # . . call
1117     e8/call  subx-sigils/disp32
1118     # . . discard args
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)
1122     # . . push args
1123     68/push  _test-output-buffered-file/imm32
1124     # . . call
1125     e8/call  flush/disp32
1126     # . . discard args
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, "^")
1130 #?     # . . push args
1131 #?     68/push  "^"/imm32
1132 #?     68/push  2/imm32/stderr
1133 #?     # . . call
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)
1138 #?     # . . push args
1139 #?     68/push  _test-output-stream/imm32
1140 #?     68/push  2/imm32/stderr
1141 #?     # . . call
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")
1146 #?     # . . push args
1147 #?     68/push  "$\n"/imm32
1148 #?     68/push  2/imm32/stderr
1149 #?     # . . call
1150 #?     e8/call  write/disp32
1151 #?     # . . discard args
1152 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1153 #?     # }}}
1154     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale 4/disp32 \n", msg)
1155     # . . push args
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
1159     # . . call
1160     e8/call  check-stream-equal/disp32
1161     # . . discard args
1162     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1163     # . epilogue
1164     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1165     5d/pop-to-ebp
1166     c3/return
1168 test-subx-sigils-register-indirect-mode-with-sib-byte-negative-displacement:
1169     # . prologue
1170     55/push-ebp
1171     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1172     # setup
1173     # . clear-stream(_test-input-stream)
1174     # . . push args
1175     68/push  _test-input-stream/imm32
1176     # . . call
1177     e8/call  clear-stream/disp32
1178     # . . discard args
1179     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1180     # . clear-stream($_test-input-buffered-file->buffer)
1181     # . . push args
1182     68/push  $_test-input-buffered-file->buffer/imm32
1183     # . . call
1184     e8/call  clear-stream/disp32
1185     # . . discard args
1186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1187     # . clear-stream(_test-output-stream)
1188     # . . push args
1189     68/push  _test-output-stream/imm32
1190     # . . call
1191     e8/call  clear-stream/disp32
1192     # . . discard args
1193     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1194     # . clear-stream($_test-output-buffered-file->buffer)
1195     # . . push args
1196     68/push  $_test-output-buffered-file->buffer/imm32
1197     # . . call
1198     e8/call  clear-stream/disp32
1199     # . . discard args
1200     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1201     # initialize input
1202     # . write(_test-input-stream, "ab *(ecx + edx<<3 - 4)")
1203     # . . push args
1204     68/push  "ab *(ecx + edx<<3 - 4)"/imm32
1205     68/push  _test-input-stream/imm32
1206     # . . call
1207     e8/call  write/disp32
1208     # . . discard args
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)
1211     # . . push args
1212     68/push  _test-output-buffered-file/imm32
1213     68/push  _test-input-buffered-file/imm32
1214     # . . call
1215     e8/call  subx-sigils/disp32
1216     # . . discard args
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)
1220     # . . push args
1221     68/push  _test-output-buffered-file/imm32
1222     # . . call
1223     e8/call  flush/disp32
1224     # . . discard args
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, "^")
1228 #?     # . . push args
1229 #?     68/push  "^"/imm32
1230 #?     68/push  2/imm32/stderr
1231 #?     # . . call
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)
1236 #?     # . . push args
1237 #?     68/push  _test-output-stream/imm32
1238 #?     68/push  2/imm32/stderr
1239 #?     # . . call
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")
1244 #?     # . . push args
1245 #?     68/push  "$\n"/imm32
1246 #?     68/push  2/imm32/stderr
1247 #?     # . . call
1248 #?     e8/call  write/disp32
1249 #?     # . . discard args
1250 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1251 #?     # }}}
1252     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale -4/disp32 \n", msg)
1253     # . . push args
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
1257     # . . call
1258     e8/call  check-stream-equal/disp32
1259     # . . discard args
1260     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1261     # . epilogue
1262     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1263     5d/pop-to-ebp
1264     c3/return
1266 test-subx-sigils-indirect-mode-without-register:
1267     # . prologue
1268     55/push-ebp
1269     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1270     # setup
1271     # . clear-stream(_test-input-stream)
1272     # . . push args
1273     68/push  _test-input-stream/imm32
1274     # . . call
1275     e8/call  clear-stream/disp32
1276     # . . discard args
1277     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1278     # . clear-stream($_test-input-buffered-file->buffer)
1279     # . . push args
1280     68/push  $_test-input-buffered-file->buffer/imm32
1281     # . . call
1282     e8/call  clear-stream/disp32
1283     # . . discard args
1284     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1285     # . clear-stream(_test-output-stream)
1286     # . . push args
1287     68/push  _test-output-stream/imm32
1288     # . . call
1289     e8/call  clear-stream/disp32
1290     # . . discard args
1291     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1292     # . clear-stream($_test-output-buffered-file->buffer)
1293     # . . push args
1294     68/push  $_test-output-buffered-file->buffer/imm32
1295     # . . call
1296     e8/call  clear-stream/disp32
1297     # . . discard args
1298     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1299     # initialize input
1300     # . write(_test-input-stream, "ab *Foo")
1301     # . . push args
1302     68/push  "ab *Foo"/imm32
1303     68/push  _test-input-stream/imm32
1304     # . . call
1305     e8/call  write/disp32
1306     # . . discard args
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)
1309     # . . push args
1310     68/push  _test-output-buffered-file/imm32
1311     68/push  _test-input-buffered-file/imm32
1312     # . . call
1313     e8/call  subx-sigils/disp32
1314     # . . discard args
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)
1318     # . . push args
1319     68/push  _test-output-buffered-file/imm32
1320     # . . call
1321     e8/call  flush/disp32
1322     # . . discard args
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, "^")
1326 #?     # . . push args
1327 #?     68/push  "^"/imm32
1328 #?     68/push  2/imm32/stderr
1329 #?     # . . call
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)
1334 #?     # . . push args
1335 #?     68/push  _test-output-stream/imm32
1336 #?     68/push  2/imm32/stderr
1337 #?     # . . call
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")
1342 #?     # . . push args
1343 #?     68/push  "$\n"/imm32
1344 #?     68/push  2/imm32/stderr
1345 #?     # . . call
1346 #?     e8/call  write/disp32
1347 #?     # . . discard args
1348 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1349 #?     # }}}
1350     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 5/rm32/.disp32 Foo/disp32 \n", msg)
1351     # . . push args
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
1355     # . . call
1356     e8/call  check-stream-equal/disp32
1357     # . . discard args
1358     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1359     # . epilogue
1360     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1361     5d/pop-to-ebp
1362     c3/return
1364 emit-direct-mode:  # out: (addr buffered-file), word-slice: (addr slice)
1365     # . prologue
1366     55/push-ebp
1367     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1368     # . save registers
1369     50/push-eax
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 '%'
1376     # . ++(*eax)
1377     ff          0/subop/increment   0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # increment *eax
1378 #?     # write-slice-buffered(Stderr, word-slice) {{{
1379 #?     # . . push args
1380 #?     50/push-eax
1381 #?     68/push  Stderr/imm32
1382 #?     # . . call
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)
1387 #?     # . . push args
1388 #?     68/push  Stderr/imm32
1389 #?     # . . call
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")
1394 #?     # . . push args
1395 #?     68/push  "$\n"/imm32
1396 #?     68/push  2/imm32/stderr
1397 #?     # . . call
1398 #?     e8/call  write/disp32
1399 #?     # . . discard args
1400 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1401 #?     # }}}
1402     # local-slice = next-token-from-slice(local-slice->start, local-slice->end, "/")
1403     # . . push args
1404     50/push-eax
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
1408     # . . call
1409     e8/call  next-token-from-slice/disp32
1410     # . . discard args
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)
1413     # . . push args
1414     68/push  "Registers"/imm32
1415     68/push  0xc/imm32/row-size
1416     50/push-eax
1417     68/push  Registers/imm32
1418     # . . call
1419     e8/call  get-slice/disp32
1420     # . . discard args
1421     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
1422     # write-buffered(out, "3/mod/direct ")
1423     # . . push args
1424     68/push  "3/mod/direct "/imm32
1425     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
1426     # . . call
1427     e8/call  write-buffered/disp32
1428     # . . discard args
1429     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1430     # write-int32-hex-buffered(out, *reg-num)
1431     # . . push args
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)
1434     # . . call
1435     e8/call  write-int32-hex-buffered/disp32
1436     # . . discard args
1437     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1438     # write-buffered(out, "/rm32")
1439     # . . push args
1440     68/push  "/rm32"/imm32
1441     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
1442     # . . call
1443     e8/call  write-buffered/disp32
1444     # . . discard args
1445     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1446 $emit-direct-mode:end:
1447     # . reclaim locals
1448     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1449     # . restore registers
1450     58/pop-to-eax
1451     # . epilogue
1452     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1453     5d/pop-to-ebp
1454     c3/return
1456 test-emit-direct-mode:
1457     # . prologue
1458     55/push-ebp
1459     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1460     # setup
1461     # . clear-stream(_test-output-stream)
1462     # . . push args
1463     68/push  _test-output-stream/imm32
1464     # . . call
1465     e8/call  clear-stream/disp32
1466     # . . discard args
1467     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1468     # . clear-stream($_test-output-buffered-file->buffer)
1469     # . . push args
1470     68/push  $_test-output-buffered-file->buffer/imm32
1471     # . . call
1472     e8/call  clear-stream/disp32
1473     # . . discard args
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}
1481     51/push-ecx
1482     50/push-eax
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)
1485     # . . push args
1486     51/push-ecx
1487     68/push  _test-output-buffered-file/imm32
1488     # . . call
1489     e8/call  emit-direct-mode/disp32
1490     # . . discard args
1491     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32         # add to esp
1492     # . flush(_test-output-buffered-file)
1493     # . . push args
1494     68/push  _test-output-buffered-file/imm32
1495     # . . call
1496     e8/call  flush/disp32
1497     # . . discard args
1498     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1499 #?     # dump output {{{
1500 #?     # . write(2/stderr, "^")
1501 #?     # . . push args
1502 #?     68/push  "^"/imm32
1503 #?     68/push  2/imm32/stderr
1504 #?     # . . call
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)
1509 #?     # . . push args
1510 #?     68/push  _test-output-stream/imm32
1511 #?     68/push  2/imm32/stderr
1512 #?     # . . call
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")
1517 #?     # . . push args
1518 #?     68/push  "$\n"/imm32
1519 #?     68/push  2/imm32/stderr
1520 #?     # . . call
1521 #?     e8/call  write/disp32
1522 #?     # . . discard args
1523 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1524 #?     # }}}
1525     # check-stream-equal(_test-output-stream, "3/mod/direct 0/rm32", msg)
1526     # . . push args
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
1530     # . . call
1531     e8/call  check-stream-equal/disp32
1532     # . . discard args
1533     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1534     # . epilogue
1535     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1536     5d/pop-to-ebp
1537     c3/return
1539 test-emit-direct-mode-2:
1540     # . prologue
1541     55/push-ebp
1542     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1543     # setup
1544     # . clear-stream(_test-output-stream)
1545     # . . push args
1546     68/push  _test-output-stream/imm32
1547     # . . call
1548     e8/call  clear-stream/disp32
1549     # . . discard args
1550     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1551     # . clear-stream($_test-output-buffered-file->buffer)
1552     # . . push args
1553     68/push  $_test-output-buffered-file->buffer/imm32
1554     # . . call
1555     e8/call  clear-stream/disp32
1556     # . . discard args
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}
1564     51/push-ecx
1565     50/push-eax
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)
1568     # . . push args
1569     51/push-ecx
1570     68/push  _test-output-buffered-file/imm32
1571     # . . call
1572     e8/call  emit-direct-mode/disp32
1573     # . . discard args
1574     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32         # add to esp
1575     # . flush(_test-output-buffered-file)
1576     # . . push args
1577     68/push  _test-output-buffered-file/imm32
1578     # . . call
1579     e8/call  flush/disp32
1580     # . . discard args
1581     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1582 #?     # dump output {{{
1583 #?     # . write(2/stderr, "^")
1584 #?     # . . push args
1585 #?     68/push  "^"/imm32
1586 #?     68/push  2/imm32/stderr
1587 #?     # . . call
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)
1592 #?     # . . push args
1593 #?     68/push  _test-output-stream/imm32
1594 #?     68/push  2/imm32/stderr
1595 #?     # . . call
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")
1600 #?     # . . push args
1601 #?     68/push  "$\n"/imm32
1602 #?     68/push  2/imm32/stderr
1603 #?     # . . call
1604 #?     e8/call  write/disp32
1605 #?     # . . discard args
1606 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1607 #?     # }}}
1608     # check-stream-equal(_test-output-stream, "3/mod/direct 7/rm32", msg)
1609     # . . push args
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
1613     # . . call
1614     e8/call  check-stream-equal/disp32
1615     # . . discard args
1616     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1617     # . epilogue
1618     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1619     5d/pop-to-ebp
1620     c3/return
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)
1629     # pseudocode:
1630     #   skip-chars-matching(line, ' ')
1631     #   if line->read >= line->write              # end of line
1632     #     out = {0, 0}
1633     #     return
1634     #   out->start = &line->data[line->read]
1635     #   if line->data[line->read] == '#'          # comment
1636     #     out.end = &line->data[line->write]
1637     #     return
1638     #   if line->data[line->read] == '"'          # string literal
1639     #     skip-string(line)
1640     #   else if line->data[line->read] == '*'     # expression
1641     #     if line->data[line->read + 1] == ' '
1642     #       abort
1643     #     if line->data[line->read + 1] == '('
1644     #       skip-until-close-paren(line)
1645     #       if (line->data[line->read] != ')'
1646     #         abort
1647     #       ++line->data[line->read] to skip ')'
1648     #   skip-chars-not-matching-whitespace(line)
1649     #   out->end = &line->data[line->read]
1650     #
1651     # registers:
1652     #   ecx: often line->read
1653     #   eax: often line->data[line->read]
1654     #
1655     # . prologue
1656     55/push-ebp
1657     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1658     # . save registers
1659     50/push-eax
1660     51/push-ecx
1661     56/push-esi
1662     57/push-edi
1663     # esi = line
1664     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
1665     # edi = out
1666     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
1667     # skip-chars-matching(line, ' ')
1668     # . . push args
1669     68/push  0x20/imm32/space
1670     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
1671     # . . call
1672     e8/call  skip-chars-matching/disp32
1673     # . . discard args
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)
1705     # return
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:
1712     # skip-string(line)
1713     # . . push args
1714     56/push-esi
1715     # . . call
1716     e8/call  skip-string/disp32
1717     # . . discard args
1718     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1719     # skip rest of word
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)
1734     # . . push args
1735     56/push-esi
1736     # . . call
1737     e8/call  skip-until-close-paren/disp32
1738     # . . discard args
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
1747     # skip ')'
1748     ff          0/subop/increment   1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # increment *(esi+4)
1749     # fall through
1750 $next-word-or-expression:regular-word:
1751     # skip-chars-not-matching-whitespace(line)  # including trailing newline
1752     # . . push args
1753     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
1754     # . . call
1755     e8/call  skip-chars-not-matching-whitespace/disp32
1756     # . . discard args
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
1764     5f/pop-to-edi
1765     5e/pop-to-esi
1766     59/pop-to-ecx
1767     58/pop-to-eax
1768     # . epilogue
1769     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1770     5d/pop-to-ebp
1771     c3/return
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 '")
1776     # . . push args
1777     68/push  "error: no space allowed after '*' in '"/imm32
1778     68/push  Stderr/imm32
1779     # . . call
1780     e8/call  write-buffered/disp32
1781     # . . discard args
1782     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1783     # . write-stream-data(Stderr, line)
1784     # . . push args
1785     56/push-esi
1786     68/push  Stderr/imm32
1787     # . . call
1788     e8/call  write-stream-data/disp32
1789     # . . discard args
1790     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1791     # . write-buffered(Stderr, "'")
1792     # . . push args
1793     68/push  "'"/imm32
1794     68/push  Stderr/imm32
1795     # . . call
1796     e8/call  write-buffered/disp32
1797     # . . discard args
1798     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1799     # . flush(Stderr)
1800     # . . push args
1801     68/push  Stderr/imm32
1802     # . . call
1803     e8/call  flush/disp32
1804     # . . discard args
1805     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1806     # . syscall_exit(1)
1807     bb/copy-to-ebx  1/imm32
1808     e8/call  syscall_exit/disp32
1809     # never gets here
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 '")
1814     # . . push args
1815     68/push  "error: *(...) expression must be all on a single line in '"/imm32
1816     68/push  Stderr/imm32
1817     # . . call
1818     e8/call  write-buffered/disp32
1819     # . . discard args
1820     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1821     # . write-stream-data(Stderr, line)
1822     # . . push args
1823     56/push-esi
1824     68/push  Stderr/imm32
1825     # . . call
1826     e8/call  write-stream-data/disp32
1827     # . . discard args
1828     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1829     # . write-buffered(Stderr, "'")
1830     # . . push args
1831     68/push  "'"/imm32
1832     68/push  Stderr/imm32
1833     # . . call
1834     e8/call  write-buffered/disp32
1835     # . . discard args
1836     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
1837     # . flush(Stderr)
1838     # . . push args
1839     68/push  Stderr/imm32
1840     # . . call
1841     e8/call  flush/disp32
1842     # . . discard args
1843     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1844     # . syscall_exit(1)
1845     bb/copy-to-ebx  1/imm32
1846     e8/call  syscall_exit/disp32
1847     # never gets here
1849 test-next-word-or-expression:
1850     # . prologue
1851     55/push-ebp
1852     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1853     # setup
1854     # . clear-stream(_test-input-stream)
1855     # . . push args
1856     68/push  _test-input-stream/imm32
1857     # . . call
1858     e8/call  clear-stream/disp32
1859     # . . discard args
1860     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1861     # var slice/ecx: slice
1862     68/push  0/imm32/end
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")
1866     # . . push args
1867     68/push  "  ab"/imm32
1868     68/push  _test-input-stream/imm32
1869     # . . call
1870     e8/call  write/disp32
1871     # . . discard args
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)
1874     # . . push args
1875     51/push-ecx
1876     68/push  _test-input-stream/imm32
1877     # . . call
1878     e8/call  next-word-or-expression/disp32
1879     # . . discard args
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)
1882     # . . push args
1883     68/push  "F - test-next-word-or-expression/updates-stream-read-correctly"/imm32
1884     68/push  4/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)
1887     # . . call
1888     e8/call  check-ints-equal/disp32
1889     # . . discard args
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)
1893     # . . push args
1894     68/push  "F - test-next-word-or-expression: start"/imm32
1895     68/push  0xe/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
1899     50/push-eax
1900     # . . call
1901     e8/call  check-ints-equal/disp32
1902     # . . discard args
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)
1906     # . . push args
1907     68/push  "F - test-next-word-or-expression: end"/imm32
1908     68/push  0x10/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
1912     50/push-eax
1913     # . . call
1914     e8/call  check-ints-equal/disp32
1915     # . . discard args
1916     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1917     # . epilogue
1918     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1919     5d/pop-to-ebp
1920     c3/return
1922 test-next-word-or-expression-returns-whole-comment:
1923     # . prologue
1924     55/push-ebp
1925     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1926     # setup
1927     # . clear-stream(_test-input-stream)
1928     # . . push args
1929     68/push  _test-input-stream/imm32
1930     # . . call
1931     e8/call  clear-stream/disp32
1932     # . . discard args
1933     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
1934     # var slice/ecx: slice
1935     68/push  0/imm32/end
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")
1939     # . . push args
1940     68/push  "  # a"/imm32
1941     68/push  _test-input-stream/imm32
1942     # . . call
1943     e8/call  write/disp32
1944     # . . discard args
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)
1947     # . . push args
1948     51/push-ecx
1949     68/push  _test-input-stream/imm32
1950     # . . call
1951     e8/call  next-word-or-expression/disp32
1952     # . . discard args
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)
1955     # . . push args
1956     68/push  "F - test-next-word-or-expression-returns-whole-comment/updates-stream-read-correctly"/imm32
1957     68/push  5/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)
1960     # . . call
1961     e8/call  check-ints-equal/disp32
1962     # . . discard args
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)
1966     # . . push args
1967     68/push  "F - test-next-word-or-expression-returns-whole-comment: start"/imm32
1968     68/push  0xe/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
1972     50/push-eax
1973     # . . call
1974     e8/call  check-ints-equal/disp32
1975     # . . discard args
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)
1979     # . . push args
1980     68/push  "F - test-next-word-or-expression-returns-whole-comment: end"/imm32
1981     68/push  0x11/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
1985     50/push-eax
1986     # . . call
1987     e8/call  check-ints-equal/disp32
1988     # . . discard args
1989     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
1990     # . epilogue
1991     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
1992     5d/pop-to-ebp
1993     c3/return
1995 test-next-word-or-expression-returns-empty-slice-on-eof:
1996     # . prologue
1997     55/push-ebp
1998     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
1999     # setup
2000     # . clear-stream(_test-input-stream)
2001     # . . push args
2002     68/push  _test-input-stream/imm32
2003     # . . call
2004     e8/call  clear-stream/disp32
2005     # . . discard args
2006     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2007     # var slice/ecx: slice
2008     68/push  0/imm32/end
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)
2013     # . . push args
2014     51/push-ecx
2015     68/push  _test-input-stream/imm32
2016     # . . call
2017     e8/call  next-word-or-expression/disp32
2018     # . . discard args
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)
2021     # . . push args
2022     68/push  "F - test-next-word-or-expression-returns-empty-expression-on-eof"/imm32
2023     68/push  0/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
2027     50/push-eax
2028     # . . call
2029     e8/call  check-ints-equal/disp32
2030     # . . discard args
2031     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2032     # . epilogue
2033     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2034     5d/pop-to-ebp
2035     c3/return
2037 test-next-word-or-expression-returns-string-literal:
2038     # . prologue
2039     55/push-ebp
2040     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
2041     # setup
2042     # . clear-stream(_test-input-stream)
2043     # . . push args
2044     68/push  _test-input-stream/imm32
2045     # . . call
2046     e8/call  clear-stream/disp32
2047     # . . discard args
2048     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2049     # var slice/ecx: slice
2050     68/push  0/imm32/end
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 ")
2054     # . . push args
2055     68/push  " \"a b\"/imm32 "/imm32
2056     68/push  _test-input-stream/imm32
2057     # . . call
2058     e8/call  write/disp32
2059     # . . discard args
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)
2062     # . . push args
2063     51/push-ecx
2064     68/push  _test-input-stream/imm32
2065     # . . call
2066     e8/call  next-word-or-expression/disp32
2067     # . . discard args
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)
2071     # . . push args
2072     68/push  "F - test-next-word-or-expression-returns-string-literal: start"/imm32
2073     68/push  0xd/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
2077     50/push-eax
2078     # . . call
2079     e8/call  check-ints-equal/disp32
2080     # . . discard args
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)
2084     # . . push args
2085     68/push  "F - test-next-word-or-expression-returns-string-literal: end"/imm32
2086     68/push  0x18/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
2090     50/push-eax
2091     # . . call
2092     e8/call  check-ints-equal/disp32
2093     # . . discard args
2094     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2095     # . epilogue
2096     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2097     5d/pop-to-ebp
2098     c3/return
2100 test-next-word-or-expression-returns-string-with-escapes:
2101     # . prologue
2102     55/push-ebp
2103     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
2104     # setup
2105     # . clear-stream(_test-input-stream)
2106     # . . push args
2107     68/push  _test-input-stream/imm32
2108     # . . call
2109     e8/call  clear-stream/disp32
2110     # . . discard args
2111     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2112     # var slice/ecx: slice
2113     68/push  0/imm32/end
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")
2117     # . . push args
2118     68/push  " \"a\\\"b\"/x"/imm32
2119     68/push  _test-input-stream/imm32
2120     # . . call
2121     e8/call  write/disp32
2122     # . . discard args
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)
2125     # . . push args
2126     51/push-ecx
2127     68/push  _test-input-stream/imm32
2128     # . . call
2129     e8/call  next-word-or-expression/disp32
2130     # . . discard args
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)
2134     # . . push args
2135     68/push  "F - test-next-word-or-expression-returns-string-with-escapes: start"/imm32
2136     68/push  0xd/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
2140     50/push-eax
2141     # . . call
2142     e8/call  check-ints-equal/disp32
2143     # . . discard args
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)
2147     # . . push args
2148     68/push  "F - test-next-word-or-expression-returns-string-with-escapes: end"/imm32
2149     68/push  0x15/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
2153     50/push-eax
2154     # . . call
2155     e8/call  check-ints-equal/disp32
2156     # . . discard args
2157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2158     # . epilogue
2159     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2160     5d/pop-to-ebp
2161     c3/return
2163 test-next-word-or-expression-returns-whole-expression:
2164     # . prologue
2165     55/push-ebp
2166     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
2167     # setup
2168     # . clear-stream(_test-input-stream)
2169     # . . push args
2170     68/push  _test-input-stream/imm32
2171     # . . call
2172     e8/call  clear-stream/disp32
2173     # . . discard args
2174     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2175     # var slice/ecx: slice
2176     68/push  0/imm32/end
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 ")
2180     # . . push args
2181     68/push  " *(a b)/imm32 "/imm32
2182     68/push  _test-input-stream/imm32
2183     # . . call
2184     e8/call  write/disp32
2185     # . . discard args
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)
2188     # . . push args
2189     51/push-ecx
2190     68/push  _test-input-stream/imm32
2191     # . . call
2192     e8/call  next-word-or-expression/disp32
2193     # . . discard args
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)
2197     # . . push args
2198     68/push  "F - test-next-word-or-expression-returns-whole-expression: start"/imm32
2199     68/push  0xd/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
2203     50/push-eax
2204     # . . call
2205     e8/call  check-ints-equal/disp32
2206     # . . discard args
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)
2210     # . . push args
2211     68/push  "F - test-next-word-or-expression-returns-whole-expression: end"/imm32
2212     68/push  0x19/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
2216     50/push-eax
2217     # . . call
2218     e8/call  check-ints-equal/disp32
2219     # . . discard args
2220     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2221     # . epilogue
2222     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2223     5d/pop-to-ebp
2224     c3/return
2226 # Grammar:
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
2235     # pseudocode:
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)
2242     #     return
2243     #   }
2244     #   # compound expressions
2245     #   skip whitespace
2246     #   read register into base
2247     #   skip whitespace
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 '+'
2252     #   skip whitespace
2253     #   if next 3 characters don't make a register, goto displacement
2254     #   read register into index
2255     #   skip whitespace
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 '<'
2261     #     skip whitespace
2262     #     read integer into scale
2263     #     skip whitespace
2264     #     if (*local-slice->start == ')') goto end
2265     #   }
2266     #   if (*local-slice->start not in '+' '-') goto error3
2267     # displacement:
2268     #   read integer into disp
2269     #   skip whitespace
2270     #   if (*local-slice->start != ')') goto error4
2271     # . prologue
2272     55/push-ebp
2273     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
2274     # . save registers
2275     56/push-esi
2276     57/push-edi
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, "/")
2299     # . . push args
2300     56/push-esi
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
2304     # . . call
2305     e8/call  next-token-from-slice/disp32
2306     # . . discard args
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)
2310     # . . push args
2311     68/push  "Registers"/imm32
2312     68/push  0xc/imm32/row-size
2313     56/push-esi
2314     68/push  Registers/imm32
2315     # . . call
2316     e8/call  get-slice/disp32
2317     # . . discard args
2318     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
2319     # . base = *eax
2320     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           7/r32/edi   .               .                 # copy *eax to edi
2321     # return
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
2326     # skip whitespace
2327     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2328     # . . push args
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
2331     # . . call
2332     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2333     # . . discard args
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)
2339     # . . push args
2340     56/push-esi
2341     # . . call
2342     e8/call  next-register/disp32
2343     # . . discard args
2344     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2345     # . edi = *eax
2346     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           7/r32/edi   .               .                 # copy *eax to edi
2347     # skip whitespace
2348     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2349     # . . push args
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
2352     # . . call
2353     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2354     # . . discard args
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
2372     # skip whitespace
2373     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2374     # . . push args
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
2377     # . . call
2378     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2379     # . . discard args
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
2385     # . spill ecx
2386     51/push-ecx
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
2392     # . . push
2393     50/push-eax
2394     51/push-ecx
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)
2398     # . . push args
2399     68/push  0xc/imm32/row-size
2400     51/push-ecx
2401     68/push  Registers/imm32
2402     # . . call
2403     e8/call  maybe-get-slice/disp32
2404     # . . discard args
2405     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2406     # . reclaim tmp
2407     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2408     # . restore ecx
2409     59/pop-to-ecx
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)
2416     # . . push args
2417     56/push-esi
2418     # . . call
2419     e8/call  next-register/disp32
2420     # . . discard args
2421     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2422     # . ecx = *eax
2423     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
2424     # skip whitespace
2425     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2426     # . . push args
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
2429     # . . call
2430     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2431     # . . discard args
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
2454     # skip whitespace
2455     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2456     # . . push args
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
2459     # . . call
2460     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2461     # . . discard args
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)
2468     # . . push args
2469     56/push-esi
2470     # . . call
2471     e8/call  next-positive-hex-int/disp32
2472     # . . discard args
2473     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2474     # . edx = eax
2475     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to edx
2476     # skip whitespace
2477     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2478     # . . push args
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
2481     # . . call
2482     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2483     # . . discard args
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)
2502     # . . push args
2503     56/push-esi
2504     # . . call
2505     e8/call  next-hex-int/disp32
2506     # . . discard args
2507     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2508     # . ebx = eax
2509     89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
2510     # skip whitespace
2511     # . eax = skip-chars-matching-whitespace-in-slice(local-slice->start, local-slice->end)
2512     # . . push args
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
2515     # . . call
2516     e8/call  skip-chars-matching-whitespace-in-slice/disp32
2517     # . . discard args
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
2529     # . reclaim locals
2530     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2531     # . restore registers
2532     5f/pop-to-edi
2533     5e/pop-to-esi
2534     # . epilogue
2535     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2536     5d/pop-to-ebp
2537     c3/return
2539 $parse-effective-address:error1:
2540     # print(stderr, "error: unexpected character: " eax "\n")
2541     # . write-buffered(Stderr, "error: unexpected character: ")
2542     # . . push args
2543     68/push  "error: unexpected character: "/imm32
2544     68/push  Stderr/imm32
2545     # . . call
2546     e8/call  write-buffered/disp32
2547     # . . discard args
2548     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2549     # . write-int32-hex-buffered(out, eax)
2550     # . . push args
2551     50/push-eax
2552     68/push  Stderr/imm32
2553     # . . call
2554     e8/call  write-int32-hex-buffered/disp32
2555     # . . discard args
2556     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2557     # . write-buffered(Stderr, "\n")
2558     # . . push args
2559     68/push  Newline/imm32
2560     68/push  Stderr/imm32
2561     # . . call
2562     e8/call  write-buffered/disp32
2563     # . . discard args
2564     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2565     # . flush(Stderr)
2566     # . . push args
2567     68/push  Stderr/imm32
2568     # . . call
2569     e8/call  flush/disp32
2570     # . . discard args
2571     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2572     # . syscall_exit(1)
2573     bb/copy-to-ebx  1/imm32
2574     e8/call  syscall_exit/disp32
2575     # never gets here
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: ")
2580     # . . push args
2581     68/push  "error: '<' can only be followed by '<' but got: "/imm32
2582     68/push  Stderr/imm32
2583     # . . call
2584     e8/call  write-buffered/disp32
2585     # . . discard args
2586     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2587     # . write-int32-hex-buffered(out, eax)
2588     # . . push args
2589     50/push-eax
2590     68/push  Stderr/imm32
2591     # . . call
2592     e8/call  write-int32-hex-buffered/disp32
2593     # . . discard args
2594     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2595     # . write-buffered(Stderr, "\n")
2596     # . . push args
2597     68/push  Newline/imm32
2598     68/push  Stderr/imm32
2599     # . . call
2600     e8/call  write-buffered/disp32
2601     # . . discard args
2602     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2603     # . flush(Stderr)
2604     # . . push args
2605     68/push  Stderr/imm32
2606     # . . call
2607     e8/call  flush/disp32
2608     # . . discard args
2609     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2610     # . syscall_exit(1)
2611     bb/copy-to-ebx  1/imm32
2612     e8/call  syscall_exit/disp32
2613     # never gets here
2615 $parse-effective-address:error3:
2616     # print(stderr, "error: unexpected character before displacement: " eax "\n")
2617     # . write-buffered(Stderr, "error: unexpected character before displacement: ")
2618     # . . push args
2619     68/push  "error: unexpected character before displacement: "/imm32
2620     68/push  Stderr/imm32
2621     # . . call
2622     e8/call  write-buffered/disp32
2623     # . . discard args
2624     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2625     # . write-int32-hex-buffered(out, eax)
2626     # . . push args
2627     50/push-eax
2628     68/push  Stderr/imm32
2629     # . . call
2630     e8/call  write-int32-hex-buffered/disp32
2631     # . . discard args
2632     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2633     # . write-buffered(Stderr, "\n")
2634     # . . push args
2635     68/push  Newline/imm32
2636     68/push  Stderr/imm32
2637     # . . call
2638     e8/call  write-buffered/disp32
2639     # . . discard args
2640     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2641     # . flush(Stderr)
2642     # . . push args
2643     68/push  Stderr/imm32
2644     # . . call
2645     e8/call  flush/disp32
2646     # . . discard args
2647     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2648     # . syscall_exit(1)
2649     bb/copy-to-ebx  1/imm32
2650     e8/call  syscall_exit/disp32
2651     # never gets here
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: ")
2656     # . . push args
2657     68/push  "error: unexpected character after displacement: "/imm32
2658     68/push  Stderr/imm32
2659     # . . call
2660     e8/call  write-buffered/disp32
2661     # . . discard args
2662     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2663     # . write-int32-hex-buffered(out, eax)
2664     # . . push args
2665     50/push-eax
2666     68/push  Stderr/imm32
2667     # . . call
2668     e8/call  write-int32-hex-buffered/disp32
2669     # . . discard args
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")
2672     # . . push args
2673     68/push  "; expected ')' to wrap up\n"/imm32
2674     68/push  Stderr/imm32
2675     # . . call
2676     e8/call  write-buffered/disp32
2677     # . . discard args
2678     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2679     # . flush(Stderr)
2680     # . . push args
2681     68/push  Stderr/imm32
2682     # . . call
2683     e8/call  flush/disp32
2684     # . . discard args
2685     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
2686     # . syscall_exit(1)
2687     bb/copy-to-ebx  1/imm32
2688     e8/call  syscall_exit/disp32
2689     # never gets here
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
2694     # . prologue
2695     55/push-ebp
2696     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
2697     # . save registers
2698     51/push-ecx
2699     56/push-esi
2700     # esi = in
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
2705     50/push-eax
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
2708     # in->start += 3
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)
2711     # . . push args
2712     68/push  "next-register"/imm32
2713     68/push  0xc/imm32/row-size
2714     51/push-ecx
2715     68/push  Registers/imm32
2716     # . . call
2717     e8/call  get-slice/disp32
2718     # . . discard args
2719     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
2720 $next-register:end:
2721     # . reclaim locals
2722     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
2723     # . restore registers
2724     5e/pop-to-esi
2725     59/pop-to-ecx
2726     # . epilogue
2727     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2728     5d/pop-to-ebp
2729     c3/return
2731 test-parse-effective-address-simple:
2732     # . prologue
2733     55/push-ebp
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}
2741     51/push-ecx
2742     50/push-eax
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)
2745     # . . push args
2746     51/push-ecx
2747     # . . call
2748     e8/call  parse-effective-address/disp32
2749     # . . discard args
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)
2753     # . . push args
2754     68/push  "F - test-parse-effective-address-simple/base"/imm32
2755     68/push  6/imm32/esi
2756     50/push-eax
2757     # . . call
2758     e8/call  check-ints-equal/disp32
2759     # . . discard args
2760     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2761     # check-ints-equal(ecx, 4, msg)
2762     # . . push args
2763     68/push  "F - test-parse-effective-address-simple/index"/imm32
2764     68/push  4/imm32/none
2765     51/push-ecx
2766     # . . call
2767     e8/call  check-ints-equal/disp32
2768     # . . discard args
2769     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2770     # check-ints-equal(edx, 0, msg)
2771     # . . push args
2772     68/push  "F - test-parse-effective-address-simple/scale"/imm32
2773     68/push  0/imm32/none
2774     52/push-edx
2775     # . . call
2776     e8/call  check-ints-equal/disp32
2777     # . . discard args
2778     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2779     # check-ints-equal(ebx, 0, msg)
2780     # . . push args
2781     68/push  "F - test-parse-effective-address-simple/displacement"/imm32
2782     68/push  0/imm32/none
2783     53/push-ebx
2784     # . . call
2785     e8/call  check-ints-equal/disp32
2786     # . . discard args
2787     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2788     # . epilogue
2789     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2790     5d/pop-to-ebp
2791     c3/return
2793 test-parse-effective-address-base:
2794     # . prologue
2795     55/push-ebp
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}
2803     51/push-ecx
2804     50/push-eax
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)
2807     # . . push args
2808     51/push-ecx
2809     # . . call
2810     e8/call  parse-effective-address/disp32
2811     # . . discard args
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)
2815     # . . push args
2816     68/push  "F - test-parse-effective-address-base/base"/imm32
2817     68/push  6/imm32/esi
2818     50/push-eax
2819     # . . call
2820     e8/call  check-ints-equal/disp32
2821     # . . discard args
2822     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2823     # check-ints-equal(ecx, 4, msg)
2824     # . . push args
2825     68/push  "F - test-parse-effective-address-base/index"/imm32
2826     68/push  4/imm32/none
2827     51/push-ecx
2828     # . . call
2829     e8/call  check-ints-equal/disp32
2830     # . . discard args
2831     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2832     # check-ints-equal(edx, 0, msg)
2833     # . . push args
2834     68/push  "F - test-parse-effective-address-base/scale"/imm32
2835     68/push  0/imm32/none
2836     52/push-edx
2837     # . . call
2838     e8/call  check-ints-equal/disp32
2839     # . . discard args
2840     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2841     # check-ints-equal(ebx, 0, msg)
2842     # . . push args
2843     68/push  "F - test-parse-effective-address-base/displacement"/imm32
2844     68/push  0/imm32/none
2845     53/push-ebx
2846     # . . call
2847     e8/call  check-ints-equal/disp32
2848     # . . discard args
2849     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2850     # . epilogue
2851     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2852     5d/pop-to-ebp
2853     c3/return
2855 test-parse-effective-address-base-displacement:
2856     # . prologue
2857     55/push-ebp
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}
2865     51/push-ecx
2866     50/push-eax
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)
2869     # . . push args
2870     51/push-ecx
2871     # . . call
2872     e8/call  parse-effective-address/disp32
2873     # . . discard args
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)
2877     # . . push args
2878     68/push  "F - test-parse-effective-address-base-displacement/base"/imm32
2879     68/push  6/imm32/esi
2880     50/push-eax
2881     # . . call
2882     e8/call  check-ints-equal/disp32
2883     # . . discard args
2884     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2885     # check-ints-equal(ecx, 4, msg)
2886     # . . push args
2887     68/push  "F - test-parse-effective-address-base-displacement/index"/imm32
2888     68/push  4/imm32/none
2889     51/push-ecx
2890     # . . call
2891     e8/call  check-ints-equal/disp32
2892     # . . discard args
2893     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2894     # check-ints-equal(edx, 0, msg)
2895     # . . push args
2896     68/push  "F - test-parse-effective-address-base-displacement/scale"/imm32
2897     68/push  0/imm32/none
2898     52/push-edx
2899     # . . call
2900     e8/call  check-ints-equal/disp32
2901     # . . discard args
2902     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2903     # check-ints-equal(ebx, 3, msg)
2904     # . . push args
2905     68/push  "F - test-parse-effective-address-base-displacement/displacement"/imm32
2906     68/push  3/imm32
2907     53/push-ebx
2908     # . . call
2909     e8/call  check-ints-equal/disp32
2910     # . . discard args
2911     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2912     # . epilogue
2913     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2914     5d/pop-to-ebp
2915     c3/return
2917 test-parse-effective-address-base-negative-displacement:
2918     # . prologue
2919     55/push-ebp
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}
2927     51/push-ecx
2928     50/push-eax
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)
2931     # . . push args
2932     51/push-ecx
2933     # . . call
2934     e8/call  parse-effective-address/disp32
2935     # . . discard args
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)
2939     # . . push args
2940     68/push  "F - test-parse-effective-address-base-negative-displacement/base"/imm32
2941     68/push  6/imm32/esi
2942     50/push-eax
2943     # . . call
2944     e8/call  check-ints-equal/disp32
2945     # . . discard args
2946     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2947     # check-ints-equal(ecx, 4, msg)
2948     # . . push args
2949     68/push  "F - test-parse-effective-address-base-negative-displacement/index"/imm32
2950     68/push  4/imm32/none
2951     51/push-ecx
2952     # . . call
2953     e8/call  check-ints-equal/disp32
2954     # . . discard args
2955     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2956     # check-ints-equal(edx, 0, msg)
2957     # . . push args
2958     68/push  "F - test-parse-effective-address-base-negative-displacement/scale"/imm32
2959     68/push  0/imm32/none
2960     52/push-edx
2961     # . . call
2962     e8/call  check-ints-equal/disp32
2963     # . . discard args
2964     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2965     # check-ints-equal(ebx, -3, msg)
2966     # . . push args
2967     68/push  "F - test-parse-effective-address-base-negative-displacement/displacement"/imm32
2968     68/push  -3/imm32
2969     53/push-ebx
2970     # . . call
2971     e8/call  check-ints-equal/disp32
2972     # . . discard args
2973     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
2974     # . epilogue
2975     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
2976     5d/pop-to-ebp
2977     c3/return
2979 test-parse-effective-address-base-index:
2980     # . prologue
2981     55/push-ebp
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}
2989     51/push-ecx
2990     50/push-eax
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)
2993     # . . push args
2994     51/push-ecx
2995     # . . call
2996     e8/call  parse-effective-address/disp32
2997     # . . discard args
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)
3001     # . . push args
3002     68/push  "F - test-parse-effective-address-base-index/base"/imm32
3003     68/push  6/imm32/esi
3004     50/push-eax
3005     # . . call
3006     e8/call  check-ints-equal/disp32
3007     # . . discard args
3008     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3009     # check-ints-equal(ecx, 1, msg)
3010     # . . push args
3011     68/push  "F - test-parse-effective-address-base-index/index"/imm32
3012     68/push  1/imm32/none
3013     51/push-ecx
3014     # . . call
3015     e8/call  check-ints-equal/disp32
3016     # . . discard args
3017     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3018     # check-ints-equal(edx, 0, msg)
3019     # . . push args
3020     68/push  "F - test-parse-effective-address-base-index/scale"/imm32
3021     68/push  0/imm32/none
3022     52/push-edx
3023     # . . call
3024     e8/call  check-ints-equal/disp32
3025     # . . discard args
3026     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3027     # check-ints-equal(ebx, 0, msg)
3028     # . . push args
3029     68/push  "F - test-parse-effective-address-base-index/displacement"/imm32
3030     68/push  0/imm32
3031     53/push-ebx
3032     # . . call
3033     e8/call  check-ints-equal/disp32
3034     # . . discard args
3035     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3036     # . epilogue
3037     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3038     5d/pop-to-ebp
3039     c3/return
3041 test-parse-effective-address-base-index-scale:
3042     # . prologue
3043     55/push-ebp
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}
3051     51/push-ecx
3052     50/push-eax
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)
3055     # . . push args
3056     51/push-ecx
3057     # . . call
3058     e8/call  parse-effective-address/disp32
3059     # . . discard args
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)
3063     # . . push args
3064     68/push  "F - test-parse-effective-address-base-index-scale/base"/imm32
3065     68/push  6/imm32/esi
3066     50/push-eax
3067     # . . call
3068     e8/call  check-ints-equal/disp32
3069     # . . discard args
3070     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3071     # check-ints-equal(ecx, 1, msg)
3072     # . . push args
3073     68/push  "F - test-parse-effective-address-base-index-scale/index"/imm32
3074     68/push  1/imm32/none
3075     51/push-ecx
3076     # . . call
3077     e8/call  check-ints-equal/disp32
3078     # . . discard args
3079     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3080     # check-ints-equal(edx, 2, msg)
3081     # . . push args
3082     68/push  "F - test-parse-effective-address-base-index-scale/scale"/imm32
3083     68/push  2/imm32
3084     52/push-edx
3085     # . . call
3086     e8/call  check-ints-equal/disp32
3087     # . . discard args
3088     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3089     # check-ints-equal(ebx, 0, msg)
3090     # . . push args
3091     68/push  "F - test-parse-effective-address-base-index-scale/displacement"/imm32
3092     68/push  0/imm32
3093     53/push-ebx
3094     # . . call
3095     e8/call  check-ints-equal/disp32
3096     # . . discard args
3097     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3098     # . epilogue
3099     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3100     5d/pop-to-ebp
3101     c3/return
3103 test-parse-effective-address-base-index-scale-displacement:
3104     # . prologue
3105     55/push-ebp
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}
3113     51/push-ecx
3114     50/push-eax
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)
3117     # . . push args
3118     51/push-ecx
3119     # . . call
3120     e8/call  parse-effective-address/disp32
3121     # . . discard args
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)
3125     # . . push args
3126     68/push  "F - test-parse-effective-address-base-index-scale/base"/imm32
3127     68/push  6/imm32/esi
3128     50/push-eax
3129     # . . call
3130     e8/call  check-ints-equal/disp32
3131     # . . discard args
3132     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3133     # check-ints-equal(ecx, 1, msg)
3134     # . . push args
3135     68/push  "F - test-parse-effective-address-base-index-scale/index"/imm32
3136     68/push  1/imm32/none
3137     51/push-ecx
3138     # . . call
3139     e8/call  check-ints-equal/disp32
3140     # . . discard args
3141     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3142     # check-ints-equal(edx, 2, msg)
3143     # . . push args
3144     68/push  "F - test-parse-effective-address-base-index-scale/scale"/imm32
3145     68/push  2/imm32
3146     52/push-edx
3147     # . . call
3148     e8/call  check-ints-equal/disp32
3149     # . . discard args
3150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3151     # check-ints-equal(ebx, -0x34, msg)
3152     # . . push args
3153     68/push  "F - test-parse-effective-address-base-index-scale/displacement"/imm32
3154     68/push  -0x34/imm32
3155     53/push-ebx
3156     # . . call
3157     e8/call  check-ints-equal/disp32
3158     # . . discard args
3159     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3160     # . epilogue
3161     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3162     5d/pop-to-ebp
3163     c3/return
3165 # Code generation:
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
3170 # emit-sib:
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
3173     # . prologue
3174     55/push-ebp
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 ")
3191     # . . push args
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)
3194     # . . call
3195     e8/call  write-buffered/disp32
3196     # . . discard args
3197     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3198     # . write-int32-hex-buffered(out, base)
3199     # . . push args
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)
3202     # . . call
3203     e8/call  write-int32-hex-buffered/disp32
3204     # . . discard args
3205     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3206     # . write-buffered(out, "/base ")
3207     # . . push args
3208     68/push  "/base "/imm32
3209     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3210     # . . call
3211     e8/call  write-buffered/disp32
3212     # . . discard args
3213     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3214     # . write-int32-hex-buffered(out, index)
3215     # . . push args
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)
3218     # . . call
3219     e8/call  write-int32-hex-buffered/disp32
3220     # . . discard args
3221     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3222     # . write-buffered(out, "/index ")
3223     # . . push args
3224     68/push  "/index "/imm32
3225     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3226     # . . call
3227     e8/call  write-buffered/disp32
3228     # . . discard args
3229     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3230     # . write-int32-hex-buffered(out, scale)
3231     # . . push args
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)
3234     # . . call
3235     e8/call  write-int32-hex-buffered/disp32
3236     # . . discard args
3237     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3238     # . write-buffered(out, "/scale ")
3239     # . . push args
3240     68/push  "/scale "/imm32
3241     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3242     # . . call
3243     e8/call  write-buffered/disp32
3244     # . . discard args
3245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3246     # . write-int32-hex-buffered(out, disp)
3247     # . . push args
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)
3250     # . . call
3251     e8/call  write-int32-hex-buffered/disp32
3252     # . . discard args
3253     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3254     # . write-buffered(out, "/disp32")
3255     # . . push args
3256     68/push  "/disp32"/imm32
3257     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3258     # . . call
3259     e8/call  write-buffered/disp32
3260     # . . discard args
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 ")
3270     # . . push args
3271     68/push  "2/mod/*+disp32 "/imm32
3272     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3273     # . . call
3274     e8/call  write-buffered/disp32
3275     # . . discard args
3276     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3277     # . write-int32-hex-buffered(out, base)
3278     # . . push args
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)
3281     # . . call
3282     e8/call  write-int32-hex-buffered/disp32
3283     # . . discard args
3284     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3285     # . write-buffered(out, "/rm32 ")
3286     # . . push args
3287     68/push  "/rm32 "/imm32
3288     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3289     # . . call
3290     e8/call  write-buffered/disp32
3291     # . . discard args
3292     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3293     # . write-int32-hex-buffered(out, disp)
3294     # . . push args
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)
3297     # . . call
3298     e8/call  write-int32-hex-buffered/disp32
3299     # . . discard args
3300     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3301     # . write-buffered(out, "/disp32")
3302     # . . push args
3303     68/push  "/disp32"/imm32
3304     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3305     # . . call
3306     e8/call  write-buffered/disp32
3307     # . . discard args
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 ")
3313     # . . push args
3314     68/push  "0/mod/indirect "/imm32
3315     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3316     # . . call
3317     e8/call  write-buffered/disp32
3318     # . . discard args
3319     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3320     # . write-int32-hex-buffered(out, base)
3321     # . . push args
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)
3324     # . . call
3325     e8/call  write-int32-hex-buffered/disp32
3326     # . . discard args
3327     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3328     # . write-buffered(out, "/rm32")
3329     # . . push args
3330     68/push  "/rm32"/imm32
3331     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3332     # . . call
3333     e8/call  write-buffered/disp32
3334     # . . discard args
3335     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3336 $emit-indirect-mode:end:
3337     # . epilogue
3338     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3339     5d/pop-to-ebp
3340     c3/return
3342 test-emit-indirect-mode:
3343     # . prologue
3344     55/push-ebp
3345     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3346     # setup
3347     # . clear-stream(_test-output-stream)
3348     # . . push args
3349     68/push  _test-output-stream/imm32
3350     # . . call
3351     e8/call  clear-stream/disp32
3352     # . . discard args
3353     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3354     # . clear-stream($_test-output-buffered-file->buffer)
3355     # . . push args
3356     68/push  $_test-output-buffered-file->buffer/imm32
3357     # . . call
3358     e8/call  clear-stream/disp32
3359     # . . discard args
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)
3362     # . . write args
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
3368     # . . call
3369     e8/call  emit-indirect-mode/disp32
3370     # . . discard args
3371     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3372     # . flush(_test-output-buffered-file)
3373     # . . push args
3374     68/push  _test-output-buffered-file/imm32
3375     # . . call
3376     e8/call  flush/disp32
3377     # . . discard args
3378     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3379 #?     # dump output {{{
3380 #?     # . write(2/stderr, "^")
3381 #?     # . . push args
3382 #?     68/push  "^"/imm32
3383 #?     68/push  2/imm32/stderr
3384 #?     # . . call
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)
3389 #?     # . . push args
3390 #?     68/push  _test-output-stream/imm32
3391 #?     68/push  2/imm32/stderr
3392 #?     # . . call
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")
3397 #?     # . . push args
3398 #?     68/push  "$\n"/imm32
3399 #?     68/push  2/imm32/stderr
3400 #?     # . . call
3401 #?     e8/call  write/disp32
3402 #?     # . . discard args
3403 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3404 #?     # }}}
3405     # check-stream-equal(_test-output-stream, "0/mod/indirect 0/rm32", msg)
3406     # . . push args
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
3410     # . . call
3411     e8/call  check-stream-equal/disp32
3412     # . . discard args
3413     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3414     # . epilogue
3415     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3416     5d/pop-to-ebp
3417     c3/return
3419 test-emit-indirect-mode-2:
3420     # . prologue
3421     55/push-ebp
3422     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3423     # setup
3424     # . clear-stream(_test-output-stream)
3425     # . . push args
3426     68/push  _test-output-stream/imm32
3427     # . . call
3428     e8/call  clear-stream/disp32
3429     # . . discard args
3430     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3431     # . clear-stream($_test-output-buffered-file->buffer)
3432     # . . push args
3433     68/push  $_test-output-buffered-file->buffer/imm32
3434     # . . call
3435     e8/call  clear-stream/disp32
3436     # . . discard args
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)
3439     # . . write args
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
3445     # . . call
3446     e8/call  emit-indirect-mode/disp32
3447     # . . discard args
3448     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3449     # . flush(_test-output-buffered-file)
3450     # . . push args
3451     68/push  _test-output-buffered-file/imm32
3452     # . . call
3453     e8/call  flush/disp32
3454     # . . discard args
3455     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3456 #?     # dump output {{{
3457 #?     # . write(2/stderr, "^")
3458 #?     # . . push args
3459 #?     68/push  "^"/imm32
3460 #?     68/push  2/imm32/stderr
3461 #?     # . . call
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)
3466 #?     # . . push args
3467 #?     68/push  _test-output-stream/imm32
3468 #?     68/push  2/imm32/stderr
3469 #?     # . . call
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")
3474 #?     # . . push args
3475 #?     68/push  "$\n"/imm32
3476 #?     68/push  2/imm32/stderr
3477 #?     # . . call
3478 #?     e8/call  write/disp32
3479 #?     # . . discard args
3480 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3481 #?     # }}}
3482     # check-stream-equal(_test-output-stream, "0/mod/indirect 7/rm32", msg)
3483     # . . push args
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
3487     # . . call
3488     e8/call  check-stream-equal/disp32
3489     # . . discard args
3490     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3491     # . epilogue
3492     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3493     5d/pop-to-ebp
3494     c3/return
3496 test-emit-indirect-mode-with-disp:
3497     # . prologue
3498     55/push-ebp
3499     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3500     # setup
3501     # . clear-stream(_test-output-stream)
3502     # . . push args
3503     68/push  _test-output-stream/imm32
3504     # . . call
3505     e8/call  clear-stream/disp32
3506     # . . discard args
3507     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3508     # . clear-stream($_test-output-buffered-file->buffer)
3509     # . . push args
3510     68/push  $_test-output-buffered-file->buffer/imm32
3511     # . . call
3512     e8/call  clear-stream/disp32
3513     # . . discard args
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)
3516     # . . write args
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
3522     # . . call
3523     e8/call  emit-indirect-mode/disp32
3524     # . . discard args
3525     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3526     # . flush(_test-output-buffered-file)
3527     # . . push args
3528     68/push  _test-output-buffered-file/imm32
3529     # . . call
3530     e8/call  flush/disp32
3531     # . . discard args
3532     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3533 #?     # dump output {{{
3534 #?     # . write(2/stderr, "^")
3535 #?     # . . push args
3536 #?     68/push  "^"/imm32
3537 #?     68/push  2/imm32/stderr
3538 #?     # . . call
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)
3543 #?     # . . push args
3544 #?     68/push  _test-output-stream/imm32
3545 #?     68/push  2/imm32/stderr
3546 #?     # . . call
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")
3551 #?     # . . push args
3552 #?     68/push  "$\n"/imm32
3553 #?     68/push  2/imm32/stderr
3554 #?     # . . call
3555 #?     e8/call  write/disp32
3556 #?     # . . discard args
3557 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3558 #?     # }}}
3559     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 4/disp32", msg)
3560     # . . push args
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
3564     # . . call
3565     e8/call  check-stream-equal/disp32
3566     # . . discard args
3567     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3568     # . epilogue
3569     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3570     5d/pop-to-ebp
3571     c3/return
3573 test-emit-indirect-mode-with-disp-negative:
3574     # . prologue
3575     55/push-ebp
3576     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3577     # setup
3578     # . clear-stream(_test-output-stream)
3579     # . . push args
3580     68/push  _test-output-stream/imm32
3581     # . . call
3582     e8/call  clear-stream/disp32
3583     # . . discard args
3584     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3585     # . clear-stream($_test-output-buffered-file->buffer)
3586     # . . push args
3587     68/push  $_test-output-buffered-file->buffer/imm32
3588     # . . call
3589     e8/call  clear-stream/disp32
3590     # . . discard args
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)
3593     # . . write args
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
3599     # . . call
3600     e8/call  emit-indirect-mode/disp32
3601     # . . discard args
3602     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3603     # . flush(_test-output-buffered-file)
3604     # . . push args
3605     68/push  _test-output-buffered-file/imm32
3606     # . . call
3607     e8/call  flush/disp32
3608     # . . discard args
3609     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3610 #?     # dump output {{{
3611 #?     # . write(2/stderr, "^")
3612 #?     # . . push args
3613 #?     68/push  "^"/imm32
3614 #?     68/push  2/imm32/stderr
3615 #?     # . . call
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)
3620 #?     # . . push args
3621 #?     68/push  _test-output-stream/imm32
3622 #?     68/push  2/imm32/stderr
3623 #?     # . . call
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")
3628 #?     # . . push args
3629 #?     68/push  "$\n"/imm32
3630 #?     68/push  2/imm32/stderr
3631 #?     # . . call
3632 #?     e8/call  write/disp32
3633 #?     # . . discard args
3634 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3635 #?     # }}}
3636     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 -4/disp32", msg)
3637     # . . push args
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
3641     # . . call
3642     e8/call  check-stream-equal/disp32
3643     # . . discard args
3644     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3645     # . epilogue
3646     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3647     5d/pop-to-ebp
3648     c3/return
3650 test-emit-indirect-mode-with-sib:
3651     # . prologue
3652     55/push-ebp
3653     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3654     # setup
3655     # . clear-stream(_test-output-stream)
3656     # . . push args
3657     68/push  _test-output-stream/imm32
3658     # . . call
3659     e8/call  clear-stream/disp32
3660     # . . discard args
3661     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3662     # . clear-stream($_test-output-buffered-file->buffer)
3663     # . . push args
3664     68/push  $_test-output-buffered-file->buffer/imm32
3665     # . . call
3666     e8/call  clear-stream/disp32
3667     # . . discard args
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)
3670     # . . write args
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
3676     # . . call
3677     e8/call  emit-indirect-mode/disp32
3678     # . . discard args
3679     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3680     # . flush(_test-output-buffered-file)
3681     # . . push args
3682     68/push  _test-output-buffered-file/imm32
3683     # . . call
3684     e8/call  flush/disp32
3685     # . . discard args
3686     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3687 #?     # dump output {{{
3688 #?     # . write(2/stderr, "^")
3689 #?     # . . push args
3690 #?     68/push  "^"/imm32
3691 #?     68/push  2/imm32/stderr
3692 #?     # . . call
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)
3697 #?     # . . push args
3698 #?     68/push  _test-output-stream/imm32
3699 #?     68/push  2/imm32/stderr
3700 #?     # . . call
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")
3705 #?     # . . push args
3706 #?     68/push  "$\n"/imm32
3707 #?     68/push  2/imm32/stderr
3708 #?     # . . call
3709 #?     e8/call  write/disp32
3710 #?     # . . discard args
3711 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3712 #?     # }}}
3713     # check-stream-equal(_test-output-stream, "2/mod/indirect 4/rm32/sib 6/base 1/index 2/scale 4/disp", msg)
3714     # . . push args
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
3718     # . . call
3719     e8/call  check-stream-equal/disp32
3720     # . . discard args
3721     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3722     # . epilogue
3723     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3724     5d/pop-to-ebp
3725     c3/return
3727 test-emit-indirect-mode-ebp:
3728     # . prologue
3729     55/push-ebp
3730     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3731     # setup
3732     # . clear-stream(_test-output-stream)
3733     # . . push args
3734     68/push  _test-output-stream/imm32
3735     # . . call
3736     e8/call  clear-stream/disp32
3737     # . . discard args
3738     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3739     # . clear-stream($_test-output-buffered-file->buffer)
3740     # . . push args
3741     68/push  $_test-output-buffered-file->buffer/imm32
3742     # . . call
3743     e8/call  clear-stream/disp32
3744     # . . discard args
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)
3747     # . . write args
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
3753     # . . call
3754     e8/call  emit-indirect-mode/disp32
3755     # . . discard args
3756     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3757     # . flush(_test-output-buffered-file)
3758     # . . push args
3759     68/push  _test-output-buffered-file/imm32
3760     # . . call
3761     e8/call  flush/disp32
3762     # . . discard args
3763     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3764 #?     # dump output {{{
3765 #?     # . write(2/stderr, "^")
3766 #?     # . . push args
3767 #?     68/push  "^"/imm32
3768 #?     68/push  2/imm32/stderr
3769 #?     # . . call
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)
3774 #?     # . . push args
3775 #?     68/push  _test-output-stream/imm32
3776 #?     68/push  2/imm32/stderr
3777 #?     # . . call
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")
3782 #?     # . . push args
3783 #?     68/push  "$\n"/imm32
3784 #?     68/push  2/imm32/stderr
3785 #?     # . . call
3786 #?     e8/call  write/disp32
3787 #?     # . . discard args
3788 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3789 #?     # }}}
3790     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 4/rm32/sib 5/base/ebp 0/index 0/scale 0/disp32", msg)
3791     # . . push args
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
3795     # . . call
3796     e8/call  check-stream-equal/disp32
3797     # . . discard args
3798     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3799     # . epilogue
3800     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3801     5d/pop-to-ebp
3802     c3/return
3804 test-emit-indirect-mode-esp:
3805     # . prologue
3806     55/push-ebp
3807     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3808     # setup
3809     # . clear-stream(_test-output-stream)
3810     # . . push args
3811     68/push  _test-output-stream/imm32
3812     # . . call
3813     e8/call  clear-stream/disp32
3814     # . . discard args
3815     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3816     # . clear-stream($_test-output-buffered-file->buffer)
3817     # . . push args
3818     68/push  $_test-output-buffered-file->buffer/imm32
3819     # . . call
3820     e8/call  clear-stream/disp32
3821     # . . discard args
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)
3824     # . . write args
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
3830     # . . call
3831     e8/call  emit-indirect-mode/disp32
3832     # . . discard args
3833     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
3834     # . flush(_test-output-buffered-file)
3835     # . . push args
3836     68/push  _test-output-buffered-file/imm32
3837     # . . call
3838     e8/call  flush/disp32
3839     # . . discard args
3840     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
3841 #?     # dump output {{{
3842 #?     # . write(2/stderr, "^")
3843 #?     # . . push args
3844 #?     68/push  "^"/imm32
3845 #?     68/push  2/imm32/stderr
3846 #?     # . . call
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)
3851 #?     # . . push args
3852 #?     68/push  _test-output-stream/imm32
3853 #?     68/push  2/imm32/stderr
3854 #?     # . . call
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")
3859 #?     # . . push args
3860 #?     68/push  "$\n"/imm32
3861 #?     68/push  2/imm32/stderr
3862 #?     # . . call
3863 #?     e8/call  write/disp32
3864 #?     # . . discard args
3865 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3866 #?     # }}}
3867     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 4/rm32/sib 4/base/ebp 0/index 0/scale 0/disp32", msg)
3868     # . . push args
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
3872     # . . call
3873     e8/call  check-stream-equal/disp32
3874     # . . discard args
3875     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
3876     # . epilogue
3877     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3878     5d/pop-to-ebp
3879     c3/return
3881 disp32-mode?:  # in: (addr slice) -> reg/eax: boolean
3882     # . prologue
3883     55/push-ebp
3884     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3885     # . save registers
3886     56/push-esi
3887     57/push-edi
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, "/")
3903     # . . push args
3904     56/push-esi
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
3908     # . . call
3909     e8/call  next-token-from-slice/disp32
3910     # . . discard args
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)
3913     # . . push args
3914     68/push  0xc/imm32/row-size
3915     56/push-esi
3916     68/push  Registers/imm32
3917     # . . cal
3918     e8/call  maybe-get-slice/disp32
3919     # . . discard args
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
3924     # return true
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
3929 $disp32-mode?:end:
3930     # . reclaim locals
3931     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3932     # . restore registers
3933     5f/pop-to-edi
3934     5e/pop-to-esi
3935     # . epilogue
3936     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3937     5d/pop-to-ebp
3938     c3/return
3940 emit-indirect-disp32:  # out: (addr buffered-file), word-slice: (addr slice)
3941     # . prologue
3942     55/push-ebp
3943     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3944     # . save registers
3945     56/push-esi
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 ")
3954     # . . push args
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)
3957     # . . call
3958     e8/call  write-buffered/disp32
3959     # . . discard args
3960     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3961     # write-slice-buffered(out, local-slice)
3962     # . . push args
3963     56/push-esi
3964     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3965     # . . call
3966     e8/call  write-slice-buffered/disp32
3967     # . . discard args
3968     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3969     # write-buffered(out, "/disp32")
3970     # . . push args
3971     68/push  "/disp32"/imm32
3972     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
3973     # . . call
3974     e8/call  write-buffered/disp32
3975     # . . discard args
3976     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3977 $emit-indirect-disp32:end:
3978     # . reclaim locals
3979     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
3980     # . restore registers
3981     5e/pop-to-esi
3982     # . epilogue
3983     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
3984     5d/pop-to-ebp
3985     c3/return
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
3991     # . prologue
3992     55/push-ebp
3993     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
3994     # . save registers
3995     51/push-ecx
3996     52/push-edx
3997     53/push-ebx
3998     56/push-esi
3999     57/push-edi
4000     # result/edi = 0
4001     31/xor                          3/mod/direct    7/rm32/edi    .           .             .           7/r32/edi   .               .                 # clear edi
4002     # esi = in
4003     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
4004     # edx = in->end
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
4010     # eax = *curr
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
4017     # . ++curr
4018     41/increment-ecx
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:
4025     # . ++curr
4026     41/increment-ecx
4027     # . negate = true
4028     bb/copy-to-ebx  1/imm32/true
4029     # fall through
4030 $next-hex-int:skip-whitespace:
4031     # spill eax
4032     50/push-eax
4033     # eax = skip-chars-matching-whitespace-in-slice(word-slice->start, word-slice->end)
4034     # . . push args
4035     52/push-edx
4036     51/push-ecx
4037     # . . call
4038     e8/call  skip-chars-matching-whitespace-in-slice/disp32
4039     # . . discard args
4040     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
4041     # ecx = eax
4042     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
4043     # restore eax
4044     58/pop-to-eax
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
4051     # . ++curr
4052     41/increment-ecx
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
4062     # . ++curr
4063     41/increment-ecx
4064 $next-hex-int:loop:
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
4069     # . eax = *curr
4070     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
4071     # . eax = hex-digit?(*curr)
4072     # . . push args
4073     50/push-eax
4074     # . . call
4075     e8/call  hex-digit?/disp32
4076     # . . discard args
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
4084     # . . call
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
4089     # ++curr
4090     41/increment-ecx
4091     # loop
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
4099 $next-hex-int:end:
4100     # word-slice->start = curr
4101     89/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy ecx to *esi
4102     # return edi
4103     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           7/r32/edi   .               .                 # copy edi to eax
4104     # . restore registers
4105     5f/pop-to-edi
4106     5e/pop-to-esi
4107     5b/pop-to-ebx
4108     5a/pop-to-edx
4109     59/pop-to-ecx
4110     # . epilogue
4111     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4112     5d/pop-to-ebp
4113     c3/return
4115 $next-hex-int:abort:
4116     # . _write(2/stderr, error)
4117     # . . push args
4118     68/push  "next-hex-int: invalid hex char: "/imm32
4119     68/push  2/imm32/stderr
4120     # . . call
4121     e8/call  _write/disp32
4122     # . . discard args
4123     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
4124     # . clear-stream($Stderr->buffer)
4125     # . . save eax
4126     50/push-eax
4127     # . . push args
4128     68/push  $Stderr->buffer/imm32
4129     # . . call
4130     e8/call  clear-stream/disp32
4131     # . . discard args
4132     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4133     # . . restore eax
4134     58/pop-to-eax
4135     # . write-int32-hex-buffered(Stderr, eax)
4136     # . . push args
4137     50/push-eax
4138     68/push  Stderr/imm32
4139     # . . call
4140     e8/call  write-int32-hex-buffered/disp32
4141     # . . discard args
4142     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
4143     # . flush(Stderr)
4144     # . . push args
4145     68/push  Stderr/imm32
4146     # . . call
4147     e8/call  flush/disp32
4148     # . . discard args
4149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4150     # . _write(2/stderr, "\n")
4151     # . . push args
4152     68/push  Newline/imm32
4153     68/push  2/imm32/stderr
4154     # . . call
4155     e8/call  _write/disp32
4156     # . . discard args
4157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
4158     # . syscall_exit(1)
4159     bb/copy-to-ebx  1/imm32
4160     e8/call  syscall_exit/disp32
4161     # never gets here
4163 test-next-hex-int-single-digit:
4164     # . prologue
4165     55/push-ebp
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}
4173     51/push-ecx
4174     50/push-eax
4175     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4176     # eax = next-hex-int(slice)
4177     # . . push args
4178     51/push-ecx
4179     # . . call
4180     e8/call  next-hex-int/disp32
4181     # . . discard args
4182     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4183     # check-ints-equal(eax, 0xa, msg)
4184     # . . push args
4185     68/push  "F - test-next-hex-int-single-digit"/imm32
4186     68/push  0xa/imm32
4187     50/push-eax
4188     # . . call
4189     e8/call  check-ints-equal/disp32
4190     # . . discard args
4191     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4192     # . epilogue
4193     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4194     5d/pop-to-ebp
4195     c3/return
4197 test-next-hex-int-multi-digit:
4198     # . prologue
4199     55/push-ebp
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}
4207     51/push-ecx
4208     50/push-eax
4209     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4210     # eax = next-hex-int(slice)
4211     # . . push args
4212     51/push-ecx
4213     # . . call
4214     e8/call  next-hex-int/disp32
4215     # . . discard args
4216     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4217     # check-ints-equal(eax, 0x34a, msg)
4218     # . . push args
4219     68/push  "F - test-next-hex-int-multi-digit"/imm32
4220     68/push  0x34a/imm32
4221     50/push-eax
4222     # . . call
4223     e8/call  check-ints-equal/disp32
4224     # . . discard args
4225     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4226     # . epilogue
4227     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4228     5d/pop-to-ebp
4229     c3/return
4231 test-next-hex-int-0x-prefix:
4232     # . prologue
4233     55/push-ebp
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}
4241     51/push-ecx
4242     50/push-eax
4243     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4244     # eax = next-hex-int(slice)
4245     # . . push args
4246     51/push-ecx
4247     # . . call
4248     e8/call  next-hex-int/disp32
4249     # . . discard args
4250     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4251     # check-ints-equal(eax, 0x34, msg)
4252     # . . push args
4253     68/push  "F - test-next-hex-int-0x-prefix"/imm32
4254     68/push  0x34/imm32
4255     50/push-eax
4256     # . . call
4257     e8/call  check-ints-equal/disp32
4258     # . . discard args
4259     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4260     # . epilogue
4261     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4262     5d/pop-to-ebp
4263     c3/return
4265 test-next-hex-int-zero:
4266     # . prologue
4267     55/push-ebp
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}
4275     51/push-ecx
4276     50/push-eax
4277     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4278     # eax = next-hex-int(slice)
4279     # . . push args
4280     51/push-ecx
4281     # . . call
4282     e8/call  next-hex-int/disp32
4283     # . . discard args
4284     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4285     # check-ints-equal(eax, 0, msg)
4286     # . . push args
4287     68/push  "F - test-next-hex-int-zero"/imm32
4288     68/push  0/imm32
4289     50/push-eax
4290     # . . call
4291     e8/call  check-ints-equal/disp32
4292     # . . discard args
4293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4294     # . epilogue
4295     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4296     5d/pop-to-ebp
4297     c3/return
4299 test-next-hex-int-0-prefix:
4300     # . prologue
4301     55/push-ebp
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}
4309     51/push-ecx
4310     50/push-eax
4311     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4312     # eax = next-hex-int(slice)
4313     # . . push args
4314     51/push-ecx
4315     # . . call
4316     e8/call  next-hex-int/disp32
4317     # . . discard args
4318     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4319     # check-ints-equal(eax, 3, msg)
4320     # . . push args
4321     68/push  "F - test-next-hex-int-0-prefix"/imm32
4322     68/push  3/imm32
4323     50/push-eax
4324     # . . call
4325     e8/call  check-ints-equal/disp32
4326     # . . discard args
4327     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4328     # . epilogue
4329     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4330     5d/pop-to-ebp
4331     c3/return
4333 test-next-hex-int-negative:
4334     # . prologue
4335     55/push-ebp
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}
4343     51/push-ecx
4344     50/push-eax
4345     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4346     # eax = next-hex-int(slice)
4347     # . . push args
4348     51/push-ecx
4349     # . . call
4350     e8/call  next-hex-int/disp32
4351     # . . discard args
4352     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4353     # check-ints-equal(eax, -3, msg)
4354     # . . push args
4355     68/push  "F - test-next-hex-int-negative"/imm32
4356     68/push  -3/imm32
4357     50/push-eax
4358     # . . call
4359     e8/call  check-ints-equal/disp32
4360     # . . discard args
4361     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4362     # . epilogue
4363     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4364     5d/pop-to-ebp
4365     c3/return
4367 test-next-hex-int-negative-with-space:
4368     # . prologue
4369     55/push-ebp
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}
4377     51/push-ecx
4378     50/push-eax
4379     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4380     # eax = next-hex-int(slice)
4381     # . . push args
4382     51/push-ecx
4383     # . . call
4384     e8/call  next-hex-int/disp32
4385     # . . discard args
4386     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4387     # check-ints-equal(eax, -3, msg)
4388     # . . push args
4389     68/push  "F - test-next-hex-int-negative-with-space"/imm32
4390     68/push  -3/imm32
4391     50/push-eax
4392     # . . call
4393     e8/call  check-ints-equal/disp32
4394     # . . discard args
4395     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4396     # . epilogue
4397     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4398     5d/pop-to-ebp
4399     c3/return
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
4405     # . prologue
4406     55/push-ebp
4407     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
4408     # . save registers
4409     51/push-ecx
4410     52/push-edx
4411     53/push-ebx
4412     56/push-esi
4413     57/push-edi
4414     # result/edi = 0
4415     31/xor                          3/mod/direct    7/rm32/edi    .           .             .           7/r32/edi   .               .                 # clear edi
4416     # esi = in
4417     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
4418     # edx = in->end
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
4424     # eax = *curr
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
4433     # . ++curr
4434     41/increment-ecx
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
4444     # . ++curr
4445     41/increment-ecx
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
4451     # . eax = *curr
4452     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
4453     # . eax = hex-digit?(*curr)
4454     # . . push args
4455     50/push-eax
4456     # . . call
4457     e8/call  hex-digit?/disp32
4458     # . . discard args
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
4466     # . . call
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
4471     # ++curr
4472     41/increment-ecx
4473     # loop
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
4478     # return edi
4479     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           7/r32/edi   .               .                 # copy edi to eax
4480     # . restore registers
4481     5f/pop-to-edi
4482     5e/pop-to-esi
4483     5b/pop-to-ebx
4484     5a/pop-to-edx
4485     59/pop-to-ecx
4486     # . epilogue
4487     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4488     5d/pop-to-ebp
4489     c3/return
4491 test-next-positive-hex-int-single-digit:
4492     # . prologue
4493     55/push-ebp
4494     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
4495     # (eax..ecx) = "a)"
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}
4501     51/push-ecx
4502     50/push-eax
4503     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4504     # eax = next-positive-hex-int(slice)
4505     # . . push args
4506     51/push-ecx
4507     # . . call
4508     e8/call  next-positive-hex-int/disp32
4509     # . . discard args
4510     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4511     # check-ints-equal(eax, 0xa, msg)
4512     # . . push args
4513     68/push  "F - test-next-positive-hex-int-single-digit"/imm32
4514     68/push  0xa/imm32
4515     50/push-eax
4516     # . . call
4517     e8/call  check-ints-equal/disp32
4518     # . . discard args
4519     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4520     # . epilogue
4521     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4522     5d/pop-to-ebp
4523     c3/return
4525 test-next-positive-hex-int-multi-digit:
4526     # . prologue
4527     55/push-ebp
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}
4535     51/push-ecx
4536     50/push-eax
4537     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4538     # eax = next-positive-hex-int(slice)
4539     # . . push args
4540     51/push-ecx
4541     # . . call
4542     e8/call  next-positive-hex-int/disp32
4543     # . . discard args
4544     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4545     # check-ints-equal(eax, 0x34a, msg)
4546     # . . push args
4547     68/push  "F - test-next-positive-hex-int-multi-digit"/imm32
4548     68/push  0x34a/imm32
4549     50/push-eax
4550     # . . call
4551     e8/call  check-ints-equal/disp32
4552     # . . discard args
4553     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4554     # . epilogue
4555     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4556     5d/pop-to-ebp
4557     c3/return
4559 test-next-positive-hex-int-0x-prefix:
4560     # . prologue
4561     55/push-ebp
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}
4569     51/push-ecx
4570     50/push-eax
4571     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4572     # eax = next-positive-hex-int(slice)
4573     # . . push args
4574     51/push-ecx
4575     # . . call
4576     e8/call  next-positive-hex-int/disp32
4577     # . . discard args
4578     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4579     # check-ints-equal(eax, 0x34, msg)
4580     # . . push args
4581     68/push  "F - test-next-positive-hex-int-0x-prefix"/imm32
4582     68/push  0x34/imm32
4583     50/push-eax
4584     # . . call
4585     e8/call  check-ints-equal/disp32
4586     # . . discard args
4587     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4588     # . epilogue
4589     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4590     5d/pop-to-ebp
4591     c3/return
4593 test-next-positive-hex-int-zero:
4594     # . prologue
4595     55/push-ebp
4596     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
4597     # (eax..ecx) = "0"
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}
4603     51/push-ecx
4604     50/push-eax
4605     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4606     # eax = next-positive-hex-int(slice)
4607     # . . push args
4608     51/push-ecx
4609     # . . call
4610     e8/call  next-positive-hex-int/disp32
4611     # . . discard args
4612     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4613     # check-ints-equal(eax, 0, msg)
4614     # . . push args
4615     68/push  "F - test-next-positive-hex-int-zero"/imm32
4616     68/push  0/imm32
4617     50/push-eax
4618     # . . call
4619     e8/call  check-ints-equal/disp32
4620     # . . discard args
4621     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4622     # . epilogue
4623     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4624     5d/pop-to-ebp
4625     c3/return
4627 test-next-positive-hex-int-0-prefix:
4628     # . prologue
4629     55/push-ebp
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}
4637     51/push-ecx
4638     50/push-eax
4639     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
4640     # eax = next-positive-hex-int(slice)
4641     # . . push args
4642     51/push-ecx
4643     # . . call
4644     e8/call  next-positive-hex-int/disp32
4645     # . . discard args
4646     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
4647     # check-ints-equal(eax, 3, msg)
4648     # . . push args
4649     68/push  "F - test-next-positive-hex-int-0-prefix"/imm32
4650     68/push  3/imm32
4651     50/push-eax
4652     # . . call
4653     e8/call  check-ints-equal/disp32
4654     # . . discard args
4655     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
4656     # . epilogue
4657     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
4658     5d/pop-to-ebp
4659     c3/return
4661 # . . vim:nowrap:textwidth=0