about summary refs log tree commit diff stats
path: root/apps/survey_baremetal.subx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/survey_baremetal.subx')
-rw-r--r--apps/survey_baremetal.subx2720
1 files changed, 0 insertions, 2720 deletions
diff --git a/apps/survey_baremetal.subx b/apps/survey_baremetal.subx
deleted file mode 100644
index c42cd900..00000000
--- a/apps/survey_baremetal.subx
+++ /dev/null
@@ -1,2720 +0,0 @@
-# Assign addresses (co-ordinates) to instructions (landmarks) in a program
-# (landscape).
-# Use the addresses assigned to replace labels.
-#
-# To build:
-#   $ ./bootstrap translate init.linux [01]*.subx apps/subx-params.subx apps/survey_baremetal.subx  -o apps/survey_baremetal
-#
-# The expected input is a stream of bytes and some interspersed labels.
-# Comments and '==' segment headers are allowed, but ignored. The emitted code
-# will all lie in a single header, and start at address 0x9400.
-#   $ cat x
-#   == code
-#   l1:
-#   aa bb l1/imm8
-#   cc dd l2/disp32
-#   l2:
-#   ee foo/imm32
-#   == data
-#   foo:
-#     00
-#
-# The output is the stream of bytes without segment headers or label definitions,
-# and with label references replaced with numeric values/displacements.
-#
-#   $ cat x  |./bootstrap run apps/survey_baremetal
-#   aa bb nn  # some computed address
-#   cc dd nn nn nn nn  # some computed displacement
-#   ee nn nn nn nn  # address right after this instruction
-#   # data segment interleaved with code
-#   00
-
-== code
-#   instruction                     effective address                                                   register    displacement    immediate
-# . op          subop               mod             rm32          base        index         scale       r32
-# . 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
-
-Entry:  # run tests if necessary, convert stdin if not
-    # . prologue
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-
-    # Heap = new-segment(Heap-size)
-    # . . push args
-    68/push  Heap/imm32
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
-    # . . call
-    e8/call  new-segment/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # initialize-trace-stream(Trace-size)
-    # . . push args
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-size/disp32                 # push *Heap-size
-    # . . call
-    e8/call  initialize-trace-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-
-    # - if argc > 1 and argv[1] == "test", then return run_tests()
-    # if (argc <= 1) goto interactive
-    81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
-    7e/jump-if-<=  $subx-survey-main:interactive/disp8
-    # if (!kernel-string-equal?(argv[1], "test")) goto interactive
-    # . eax = kernel-string-equal?(argv[1], "test")
-    # . . push args
-    68/push  "test"/imm32
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  kernel-string-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax == false) goto interactive
-    3d/compare-eax-and  0/imm32/false
-    74/jump-if-=  $subx-survey-main:interactive/disp8
-    # run-tests()
-    e8/call  run-tests/disp32
-    # syscall(exit, *Num-test-failures)
-    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
-    eb/jump  $subx-survey-main:end/disp8
-$subx-survey-main:interactive:
-    # - otherwise convert stdin
-    # subx-survey(Stdin, Stdout)
-    # . . push args
-    68/push  Stdout/imm32
-    68/push  Stdin/imm32
-    # . . call
-    e8/call  subx-survey/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, Trace-stream)
-#?     # . . push args
-#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # syscall(exit, 0)
-    bb/copy-to-ebx  0/imm32
-$subx-survey-main:end:
-    e8/call  syscall_exit/disp32
-
-subx-survey:  # infile: (addr buffered-file), out: (addr buffered-file)
-    # pseudocode
-    #   var in: (stream byte Input-size)
-    #   slurp(infile, in)
-    #   var labels: (stream {label-name, address} Max-labels)
-    #   compute-offsets(in, labels)
-    #   rewind-stream(in)
-    #   emit-output(in, out, labels)
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    51/push-ecx
-    52/push-edx
-    56/push-esi
-    # var labels/edx: (stream {label-name, address} Max-labels)
-    # (we get more rows than Max-labels advertises because row size is smaller than in survey_elf)
-    # . data
-    2b/subtract                     0/mod/indirect  5/rm32/.disp32            .             .           4/r32/esp   Max-labels/disp32                 # subtract *Max-labels from esp
-    # . size
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Max-labels/disp32                 # push *Max-labels
-    # . read
-    68/push  0/imm32/read
-    # . write
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # var in/esi: (stream byte Input-size)
-    # . data
-    2b/subtract                     0/mod/indirect  5/rm32/.disp32            .             .           4/r32/esp   Input-size/disp32                 # subtract *Input-size from esp
-    # . size
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Input-size/disp32                 # push *Input-size
-    # . read
-    68/push  0/imm32/read
-    # . write
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
-    # slurp(infile, in)
-    # . . push args
-    56/push-esi
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  slurp/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # compute-offsets(in, labels)
-    # . . push args
-    52/push-edx
-    56/push-esi
-    # . . call
-    e8/call  compute-offsets/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # rewind-stream(in)
-    # . . push args
-    56/push-esi
-    # . . call
-    e8/call  rewind-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # emit-output(in, out, labels)
-    # . . push args
-    52/push-edx
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    56/push-esi
-    # . . call
-    e8/call  emit-output/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # flush(out)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  flush/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-$subx-survey:end:
-    # . reclaim locals
-    03/add                          0/mod/indirect  5/rm32/.disp32            .             .           4/r32/esp   Max-labels/disp32                 # add *Max-labels to esp
-    03/add                          0/mod/indirect  5/rm32/.disp32            .             .           4/r32/esp   Input-size/disp32                 # add *Input-size to esp
-    # . restore registers
-    5e/pop-to-esi
-    5a/pop-to-edx
-    59/pop-to-ecx
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-subx-survey-computes-addresses:
-    # input:
-    #   == code
-    #   Entry:
-    #   ab x/imm32
-    #   == data
-    #   x:
-    #     01
-    #
-    # trace contains (in any order):
-    #   label x is at address 0x9405
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream($_test-input-buffered-file->buffer)
-    # . . push args
-    68/push  $_test-input-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream($_test-output-buffered-file->buffer)
-    # . . push args
-    68/push  $_test-output-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "== code\n")
-    # . . push args
-    68/push  "== code\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "Entry:\n")
-    # . . push args
-    68/push  "Entry:\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ab x/imm32\n")
-    # . . push args
-    68/push  "ab x/imm32\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "== data\n")
-    # . . push args
-    68/push  "== data\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "x:\n")
-    # . . push args
-    68/push  "x:\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "01\n")
-    # . . push args
-    68/push  "01\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # subx-survey(_test-input-buffered-file, _test-output-buffered-file)
-    # . . push args
-    68/push  _test-output-buffered-file/imm32
-    68/push  _test-input-buffered-file/imm32
-    # . . call
-    e8/call  subx-survey/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # check trace
-#?     # dump *Trace-stream {{{
-#?     # . write(2/stderr, "^")
-#?     # . . push args
-#?     68/push  "^"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, *Trace-stream)
-#?     # . . push args
-#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-    # . check-trace-contains("label 'x' is at address 0x00009405.", msg)
-    # . . push args
-    68/push  "F - test-subx-survey-computes-addresses/0"/imm32
-    68/push  "label 'x' is at address 0x00009405."/imm32
-    # . . call
-    e8/call  check-trace-contains/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-compute-offsets:  # in: (addr stream byte), labels: (addr stream {(handle array byte), address})
-    # pseudocode:
-    #   var current-address = 0x9400
-    #   var line: (stream byte 512)
-    #   while true                                  # line loop
-    #     clear-stream(line)
-    #     read-line(in, line)
-    #     if (line->write == 0) break               # end of file
-    #     while true                                # word loop
-    #       word-slice = next-word(line)
-    #       if slice-empty?(word-slice)             # end of line
-    #         break
-    #       else if slice-starts-with?(word-slice, "#")  # comment
-    #         break                                 # end of line
-    #       else if slice-equal?(word-slice, "==")  # no need for segment header
-    #         break
-    #       else if is-label?(word-slice)
-    #         strip trailing ':' from word-slice
-    #         trace("label '" word-slice "' is at address " current-address ".")
-    #         # labels occupy no space, so no need to increment offsets
-    #       else
-    #         width = compute-width-of-slice(word-slice)
-    #         current-address += width
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    50/push-eax
-    51/push-ecx
-    52/push-edx
-    53/push-ebx
-    56/push-esi
-    57/push-edi
-    # var current-address/esi: int = 0x9400
-    be/copy-to-esi  0x9400/imm32
-    # var line/ecx: (stream byte 512)
-    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x200/imm32       # subtract from esp
-    68/push  0x200/imm32/size
-    68/push  0/imm32/read
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-    # var word-slice/edx: (addr slice)
-    68/push  0/imm32
-    68/push  0/imm32
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-$compute-offsets:line-loop:
-    # clear-stream(line)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # read-line(in, line)
-    # . . push args
-    51/push-ecx
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  read-line/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # if (line->write == 0) break
-    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
-    3d/compare-eax-and  0/imm32
-    0f 84/jump-if-=  $compute-offsets:end/disp32
-#?     # dump line {{{
-#?     # . write(2/stderr, "LL: ")
-#?     # . . push args
-#?     68/push  "LL: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # write-stream(2/stderr, line)
-#?     # . . push args
-#?     51/push-ecx
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . rewind-stream(line)
-#?     # . . push args
-#?     51/push-ecx
-#?     # . . call
-#?     e8/call  rewind-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # }}}
-$compute-offsets:word-loop:
-    # next-word(line, word-slice)
-    52/push-edx
-    51/push-ecx
-    e8/call  next-word/disp32
-    # . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-$compute-offsets:case-empty:
-    # if slice-empty?(word-slice) break
-    # . eax = slice-empty?(word-slice)
-    52/push-edx
-    e8/call  slice-empty?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $compute-offsets:line-loop/disp32
-$compute-offsets:case-comment:
-    # if slice-starts-with?(word-slice, "#") break
-    68/push  "#"/imm32
-    52/push-edx
-    e8/call  slice-starts-with?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $compute-offsets:line-loop/disp32
-$compute-offsets:case-segment-header:
-    # if slice-equal?(word-slice, "==") break
-    # . eax = slice-equal?(word-slice, "==")
-    68/push  "=="/imm32
-    52/push-edx
-    e8/call  slice-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $compute-offsets:line-loop/disp32
-$compute-offsets:case-label:
-    # if (!is-label?(word-slice)) goto next case
-    # . eax = is-label?(word-slice)
-    # . . push args
-    52/push-edx
-    # . . call
-    e8/call  is-label?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax == false) goto next case
-    3d/compare-eax-and  0/imm32/false
-    0f 84/jump-if-=  $compute-offsets:case-default/disp32
-    # strip trailing ':' from word-slice
-    ff          1/subop/decrement   1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # decrement *(edx+4)
-    # var tmp/eax: (addr int) = get-or-insert-slice(labels, word-slice, row-size=12)
-    # . . push args
-    68/push  Heap/imm32
-    68/push  0xc/imm32/row-size
-    52/push-edx
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  get-or-insert-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # *tmp = current-address
-    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           6/r32/esi   .               .                 # copy esi to *eax
-    # trace-slsns("label '" word-slice "' is at address " current-address ".")
-    # . . push args
-    68/push  "."/imm32
-    56/push-esi
-    68/push  "' is at address "/imm32
-    52/push-edx
-    68/push  "label '"/imm32
-    # . . call
-    e8/call  trace-slsns/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
-    # continue
-    e9/jump  $compute-offsets:word-loop/disp32
-$compute-offsets:case-default:
-    # width/eax = compute-width-of-slice(word-slice)
-    # . . push args
-    52/push-edx
-    # . . call
-    e8/call compute-width-of-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # current-address += width
-    01/add                          3/mod/direct    6/rm32/esi    .           .             .           0/r32/eax   .               .                 # add eax to *esi
-#?     # dump segment-offset {{{
-#?     # . write(2/stderr, "segment-offset: ")
-#?     # . . push args
-#?     68/push  "segment-offset: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . clear-stream($Stderr->buffer)
-#?     # . . push args
-#?     68/push  $Stderr->buffer/imm32
-#?     # . . call
-#?     e8/call  clear-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write-int32-hex-buffered(Stderr, segment-offset)
-#?     # . . push args
-#?     52/push-edx
-#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           compute-offsets:segment-offset/disp32  # push *segment-offset
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  write-int32-hex-buffered/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . flush(Stderr)
-#?     # . . push args
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  flush/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write(2/stderr, "\n")
-#?     # . . push args
-#?     68/push  Newline/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-    e9/jump $compute-offsets:word-loop/disp32
-$compute-offsets:end:
-    # . reclaim locals
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x214/imm32       # add to esp
-    # . restore registers
-    5f/pop-to-edi
-    5e/pop-to-esi
-    5b/pop-to-ebx
-    5a/pop-to-edx
-    59/pop-to-ecx
-    58/pop-to-eax
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-$compute-offsets:abort:
-    # . _write(2/stderr, error)
-    # . . push args
-    68/push  "'==' must be followed by segment name and segment-start\n"/imm32
-    68/push  2/imm32/stderr
-    # . . call
-    e8/call  _write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    e8/call  syscall_exit/disp32
-    # never gets here
-
-test-compute-offsets:
-    # input:
-    #   == code
-    #   ab x/imm32  # skip comment
-    #   == data
-    #   00
-    #   x:
-    #     34
-    #
-    # trace contains (in any order):
-    #   label 'x' is at address 0x9406.
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # var labels/edx: (stream byte 2*12)
-    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x18/imm32        # subtract from esp
-    68/push  0x18/imm32/size
-    68/push  0/imm32/read
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # initialize input
-    # . write(_test-input-stream, "== code\n")
-    # . . push args
-    68/push  "== code\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ab x/imm32  # skip comment\n")
-    # . . push args
-    68/push  "ab x/imm32  # skip comment\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "== data\n")
-    # . . push args
-    68/push  "== data\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "00\n")
-    # . . push args
-    68/push  "00\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "x:\n")
-    # . . push args
-    68/push  "x:\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "34\n")
-    # . . push args
-    68/push  "34\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # compute-offsets(_test-input-stream, labels)
-    # . . push args
-    52/push-edx
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  compute-offsets/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32          # add to esp
-#?     # dump *Trace-stream {{{
-#?     # . write(2/stderr, "^")
-#?     # . . push args
-#?     68/push  "^"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, *Trace-stream)
-#?     # . . push args
-#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-    # . check-trace-contains("label 'x' is at address 0x00009406.", msg)
-    # . . push args
-    68/push  "F - test-compute-offsets"/imm32
-    68/push  "label 'x' is at address 0x00009406."/imm32
-    # . . call
-    e8/call  check-trace-contains/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . check-ints-equal(labels->write, 0xc, msg)
-    # . . push args
-    68/push  "F - test-compute-offsets-maintains-labels-write-index"/imm32
-    68/push  0xc/imm32/1-entry
-    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . reclaim locals
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x24/imm32        # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-# global scratch space for emit-output
-== data
-
-emit-output:datum:  # slice
-  0/imm32/start
-  0/imm32/end
-
-== code
-
-emit-output:  # in: (addr stream byte), out: (addr buffered-file), labels: (addr stream {(handle array byte), address})
-    # pseudocode:
-    #   var address-of-next-instruction = 0x9400
-    #   var line: (stream byte 512)
-    #   line-loop:
-    #   while true
-    #     clear-stream(line)
-    #     read-line(in, line)
-    #     if (line->write == 0) break               # end of file
-    #     address-of-next-instruction += num-bytes(line)
-    #     var is-far-jump-or-call? = is-far-jump-or-call?(line)
-    #     rewind-stream(line)
-    #     while true
-    #       var word-slice = next-word(line)
-    #       if slice-empty?(word-slice)             # end of line
-    #         break
-    #       if slice-starts-with?(word-slice, "#")  # comment
-    #         break
-    #       if is-label?(word-slice)                # no need for label declarations anymore
-    #         goto line-loop                        # don't insert empty lines
-    #       if slice-equal?(word-slice, "==")       # no need for segment header lines
-    #         goto line-loop                        # don't insert empty lines
-    #       if length(word-slice) == 2
-    #         write-slice-buffered(out, word-slice)
-    #         write-buffered(out, " ")
-    #         continue
-    #       var datum: (addr slice) = next-token-from-slice(word-slice->start, word-slice->end, "/")
-    #       var address: (addr int) = get-slice(labels, datum)
-    #       if has-metadata?(word-slice, "imm8")
-    #         abort
-    #       else if has-metadata?(word-slice, "imm32")
-    #         emit(out, *address, 4)
-    #       else if has-metadata?(word-slice, "disp8")
-    #         value = *address - address-of-next-instruction
-    #         emit(out, value, 1)
-    #       else if has-metadata?(word-slice, "disp32")
-    #         if is-far-jump-or-call?
-    #           value = *address - address-of-next-instruction
-    #         else
-    #           value = *address
-    #         emit(out, value, 4)
-    #       else
-    #         abort
-    #     write-buffered(out, "\n")
-    #
-    # registers:
-    #   line: ecx
-    #   word-slice: edx
-    #   address-of-next-instruction: ebx
-    #   is-far-jump-or-call?: edi
-    #   address: esi (inner loop only)
-    #   temporaries: eax, esi (outer loop)
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    50/push-eax
-    51/push-ecx
-    52/push-edx
-    53/push-ebx
-    56/push-esi
-    57/push-edi
-    # var line/ecx: (stream byte 512)
-    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0x200/imm32       # subtract from esp
-    68/push  0x200/imm32/size
-    68/push  0/imm32/read
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-    # var word-slice/edx: slice
-    68/push  0/imm32/end
-    68/push  0/imm32/start
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # var address-of-next-instruction/ebx = 0x9400
-    bb/copy-to-ebx  0x9400/imm32
-$emit-output:line-loop:
-    # clear-stream(line)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # read-line(in, line)
-    # . . push args
-    51/push-ecx
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  read-line/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # dump line {{{
-#?     # . write(2/stderr, "LL: ")
-#?     # . . push args
-#?     68/push  "LL: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # write-stream(2/stderr, line)
-#?     # . . push args
-#?     51/push-ecx
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . rewind-stream(line)
-#?     # . . push args
-#?     51/push-ecx
-#?     # . . call
-#?     e8/call  rewind-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # }}}
-$emit-output:check-for-end-of-input:
-    # if (line->write == 0) break
-    81          7/subop/compare     0/mod/indirect  1/rm32/ecx    .           .             .           .           .               0/imm32           # compare *ecx
-    0f 84/jump-if-=  $emit-output:end/disp32
-    # address-of-next-instruction += num-bytes(line)
-    # . eax = num-bytes(line)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . ebx += eax
-    01/add                          3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # add eax to ebx
-    # var is-far-jump-or-call?/edi: boolean = is-far-jump-or-call?(line)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call  is-far-jump-or-call?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # rewind-stream(line)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call  rewind-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-$emit-output:word-loop:
-    # next-word(line, word-slice)
-    # . . push args
-    52/push-edx
-    51/push-ecx
-    # . . call
-    e8/call  next-word/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # dump word-slice {{{
-#?     # . write(2/stderr, "w: ")
-#?     # . . push args
-#?     68/push  "w: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-slice-buffered(Stderr, word-slice)
-#?     # . . push args
-#?     52/push-edx
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  write-slice-buffered/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . flush(Stderr)
-#?     # . . push args
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  flush/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-$emit-output:check-for-end-of-line:
-    # if (slice-empty?(word-slice)) break
-    # . eax = slice-empty?(word-slice)
-    # . . push args
-    52/push-edx
-    # . . call
-    e8/call  slice-empty?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax != 0) break
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-output:next-line/disp32
-$emit-output:check-for-comment:
-    # if (slice-starts-with?(word-slice, "#")) break
-    # . start/esi = word-slice->start
-    8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           6/r32/esi   .               .                 # copy *edx to esi
-    # . c/eax = *start
-    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
-    8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
-    # . if (eax == '#') break
-    3d/compare-eax-and  0x23/imm32/hash
-    0f 84/jump-if-=  $emit-output:next-line/disp32
-$emit-output:check-for-label:
-    # if is-label?(word-slice) break
-    # . eax = is-label?(word-slice)
-    # . . push args
-    52/push-edx
-    # . . call
-    e8/call  is-label?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-output:line-loop/disp32
-$emit-output:check-for-segment-header:
-    # if (slice-equal?(word-slice, "==")) break
-    # . eax = slice-equal?(word-slice, "==")
-    # . . push args
-    68/push  "=="/imm32
-    52/push-edx
-    # . . call
-    e8/call  slice-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-output:line-loop/disp32
-$emit-output:2-character:
-    # if (size(word-slice) != 2) goto next check
-    # . eax = size(word-slice)
-    8b/copy                         1/mod/*+disp8   2/rm32/edx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(edx+4) to eax
-    2b/subtract                     0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # subtract *edx from eax
-    # . if (eax != 2) goto next check
-    3d/compare-eax-and  2/imm32
-    75/jump-if-!=  $emit-output:check-metadata/disp8
-    # write-slice-buffered(out, word-slice)
-    # . . push args
-    52/push-edx
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  write-slice-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # write-buffered(out, " ")
-    # . . push args
-    68/push  Space/imm32
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  write-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # continue
-    e9/jump  $emit-output:word-loop/disp32
-$emit-output:check-metadata:
-    # - if we get here, 'word-slice' must be a label to be looked up
-    # datum = next-token-from-slice(word-slice->start, word-slice->end, "/")
-    # . . push args
-    68/push  emit-output:datum/imm32
-    68/push  0x2f/imm32/slash
-    ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
-    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
-    # . . call
-    e8/call  next-token-from-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-#?     # dump datum {{{
-#?     # . write(2/stderr, "datum: ")
-#?     # . . push args
-#?     68/push  "datum: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-slice-buffered(Stderr, datum)
-#?     # . . push args
-#?     68/push  emit-output:datum/imm32
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  write-slice-buffered/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . flush(Stderr)
-#?     # . . push args
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  flush/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-    # address/esi: (addr int) = get-slice(labels, datum, row-size=12, "label table")
-    # . eax = get-slice(labels, datum, row-size=24, "label table")
-    # . . push args
-    68/push  "label table"/imm32
-    68/push  0xc/imm32/row-size
-    68/push  emit-output:datum/imm32
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
-    # . . call
-    e8/call  get-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # . esi = eax
-    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy eax to esi
-$emit-output:check-imm8:
-    # if (has-metadata?(word-slice, "imm8")) abort
-    # . eax = has-metadata?(edx, "imm8")
-    # . . push args
-    68/push  "imm8"/imm32
-    52/push-edx
-    # . . call
-    e8/call  has-metadata?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) abort
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $emit-output:imm8-abort/disp32
-$emit-output:check-imm32:
-    # if (!has-metadata?(word-slice, "imm32")) goto next check
-    # . eax = has-metadata?(edx, "imm32")
-    # . . push args
-    68/push  "imm32"/imm32
-    52/push-edx
-    # . . call
-    e8/call  has-metadata?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax == false) goto next check
-    3d/compare-eax-and  0/imm32/false
-    74/jump-if-=  $emit-output:check-disp8/disp8
-#?     # dump *address {{{
-#?     # . write(2/stderr, "*address: ")
-#?     # . . push args
-#?     68/push  "*address: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-int32-hex-buffered(Stderr, *address)
-#?     # . . push args
-#?     ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  write-int32-hex-buffered/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . flush(Stderr)
-#?     # . . push args
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  flush/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-$emit-output:emit-imm32:
-    # emit-hex(out, *address, 4)
-    # . . push args
-    68/push  4/imm32
-    ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  emit-hex/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # continue
-    e9/jump  $emit-output:word-loop/disp32
-$emit-output:check-disp8:
-    # if (!has-metadata?(word-slice, "disp8")) goto next check
-    # . eax = has-metadata?(edx, "disp8")
-    # . . push args
-    68/push  "disp8"/imm32
-    52/push-edx
-    # . . call
-    e8/call  has-metadata?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax == false) goto next check
-    3d/compare-eax-and  0/imm32/false
-    74/jump-if-=  $emit-output:check-disp32/disp8
-$emit-output:emit-disp8:
-    # emit-hex(out, *address - address-of-next-instruction, 1)
-    # . . push args
-    68/push  1/imm32
-    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
-    29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
-    50/push-eax
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  emit-hex/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # continue
-    e9/jump  $emit-output:word-loop/disp32
-$emit-output:check-disp32:
-    # if (!has-metadata?(word-slice, "disp32")) abort
-    # . eax = has-metadata?(edx, "disp32")
-    # . . push args
-    68/push  "disp32"/imm32
-    52/push-edx
-    # . . call
-    e8/call  has-metadata?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax == false) abort
-    3d/compare-eax-and  0/imm32/false
-    0f 84/jump-if-=  $emit-output:abort/disp32
-$emit-output:emit-disp32:
-    # var value/eax = *address
-    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
-    # if (is-far-jump-or-call?) value -= address-of-next-instruction
-    81          7/subop/compare     3/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32/false     # compare edi
-    74/jump-if-=  $emit-output:really-emit-disp32/disp8
-    29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # subtract ebx from eax
-$emit-output:really-emit-disp32:
-    # emit-hex(out, value, 4)
-    # . . push args
-    68/push  4/imm32
-    50/push-eax
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  emit-hex/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # continue
-    e9/jump  $emit-output:word-loop/disp32
-$emit-output:next-line:
-    # write-buffered(out, "\n")
-    # . . push args
-    68/push  Newline/imm32
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    # . . call
-    e8/call  write-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # loop
-    e9/jump  $emit-output:line-loop/disp32
-$emit-output:end:
-    # . reclaim locals
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x214/imm32       # add to esp
-    # . restore registers
-    5f/pop-to-edi
-    5e/pop-to-esi
-    5b/pop-to-ebx
-    5a/pop-to-edx
-    59/pop-to-ecx
-    58/pop-to-eax
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-$emit-output:global-variable-abort:
-    # . _write(2/stderr, error)
-    # . . push args
-    68/push  "emit-output: must refer to global variables with /disp32 or /imm32"/imm32
-    68/push  2/imm32/stderr
-    # . . call
-    e8/call  _write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    e8/call  syscall_exit/disp32
-    # never gets here
-
-$emit-output:imm8-abort:
-    # . _write(2/stderr, error)
-    # . . push args
-    68/push  "emit-output: cannot refer to code labels with /imm8"/imm32
-    68/push  2/imm32/stderr
-    # . . call
-    e8/call  _write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    e8/call  syscall_exit/disp32
-    # never gets here
-
-$emit-output:abort:
-    # print(stderr, "missing metadata in " word-slice)
-    # . _write(2/stderr, "missing metadata in word ")
-    # . . push args
-    68/push  "emit-output: missing metadata in "/imm32
-    68/push  2/imm32/stderr
-    # . . call
-    e8/call  _write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write-slice-buffered(Stderr, word-slice)
-    # . . push args
-    52/push-edx
-    68/push  Stderr/imm32
-    # . . call
-    e8/call  write-slice-buffered/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . flush(Stderr)
-    # . . push args
-    68/push  Stderr/imm32
-    # . . call
-    e8/call  flush/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    e8/call  syscall_exit/disp32
-    # never gets here
-
-test-emit-output-non-far-control-flow:
-    # labels turn into absolute addresses if opcodes are not far jumps or calls
-    #
-    # input:
-    #   in:
-    #     == code
-    #     ab cd ef gh
-    #     ij x/disp32
-    #     == data
-    #     00
-    #     34
-    #   labels:
-    #     - 'x': 0x11223344
-    #
-    # output:
-    #   ab cd ef gh
-    #   ij 44 33 22 11
-    #   00
-    #   34
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream($_test-output-buffered-file->buffer)
-    # . . push args
-    68/push  $_test-output-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . var labels/edx: (stream byte 8*24)
-    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc0/imm32        # subtract from esp
-    68/push  0xc0/imm32/size
-    68/push  0/imm32/read
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # . var h/ebx: (handle array byte)
-    68/push  0/imm32
-    68/push  0/imm32
-    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
-    # initialize input
-    # . write(_test-input-stream, "== code\n")
-    # . . push args
-    68/push  "== code\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ab cd ef gh\n")
-    # . . push args
-    68/push  "ab cd ef gh\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ij x/disp32\n")
-    # . . push args
-    68/push  "ij x/disp32\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "== data\n")
-    # . . push args
-    68/push  "== data\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "00\n")
-    # . . push args
-    68/push  "00\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "34\n")
-    # . . push args
-    68/push  "34\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . stream-add2(labels, "x", 0x11223344)
-    68/push  0x11223344/imm32/label-address
-    # . . push handle for "x"
-    53/push-ebx
-    68/push  "x"/imm32
-    68/push  Heap/imm32
-    e8/call  copy-array/disp32
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    ff          6/subop/push        1/mod/*+disp8   3/rm32/ebx    .           .             .           .           4/disp8         .                 # push *(ebx+4)
-    ff          6/subop/push        0/mod/indirect  3/rm32/ebx    .           .             .           .           .               .                 # push *ebx
-    # . . push labels
-    52/push-edx
-    # . . call
-    e8/call  stream-add2/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # component under test
-    # . emit-output(_test-input-stream, _test-output-buffered-file, labels)
-    # . . push args
-    52/push-edx
-    68/push  _test-output-buffered-file/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  emit-output/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # checks
-    # . flush(_test-output-buffered-file)
-    # . . push args
-    68/push  _test-output-buffered-file/imm32
-    # . . call
-    e8/call  flush/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # dump output {{{
-#?     # . write(2/stderr, "result: ^")
-#?     # . . push args
-#?     68/push  "result: ^"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, _test-output-stream)
-#?     # . . push args
-#?     68/push  _test-output-stream/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . rewind-stream(_test-output-stream)
-#?     # . . push args
-#?     68/push  _test-output-stream/imm32
-#?     # . . call
-#?     e8/call  rewind-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # }}}
-    # . check-next-stream-line-equal(_test-output-stream, "ab cd ef gh ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-non-far-control-flow/0"/imm32
-    68/push  "ab cd ef gh "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "ij 44 33 22 11 ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-non-far-control-flow/1"/imm32
-    68/push  "ij 44 33 22 11 "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "00 ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-non-far-control-flow/2"/imm32
-    68/push  "00 "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "34 ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-non-far-control-flow/3"/imm32
-    68/push  "34 "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-emit-output-code-label:
-    # labels turn into PC-relative addresses if opcodes are far jumps or calls
-    #
-    # input:
-    #   in:
-    #     == code
-    #     ab cd
-    #     ef gh
-    #     e8 l1/disp32
-    #   labels:
-    #     - 'l1': 0x9410
-    #
-    # output:
-    #   ab cd
-    #   ef gh
-    #   e8 07 00 00 00  # 0x9410 - 0x9409 = 7
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream($_test-output-buffered-file->buffer)
-    # . . push args
-    68/push  $_test-output-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . var labels/edx: (stream byte 8*24)
-    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc0/imm32        # subtract from esp
-    68/push  0xc0/imm32/size
-    68/push  0/imm32/read
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # . var h/ebx: (handle array byte)
-    68/push  0/imm32
-    68/push  0/imm32
-    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
-    # initialize input
-    # . write(_test-input-stream, "== code\n")
-    # . . push args
-    68/push  "== code\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ab cd\n")
-    # . . push args
-    68/push  "ab cd\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ef gh\n")
-    # . . push args
-    68/push  "ef gh\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "e8 l1/disp32\n")
-    # . . push args
-    68/push  "e8 l1/disp32\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . stream-add2(labels, "l1", 0x9410)
-    68/push  0x9410/imm32/label-address
-    # . . push handle for "l1"
-    53/push-ebx
-    68/push  "l1"/imm32
-    68/push  Heap/imm32
-    e8/call  copy-array/disp32
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    ff          6/subop/push        1/mod/*+disp8   3/rm32/ebx    .           .             .           .           4/disp8         .                 # push *(ebx+4)
-    ff          6/subop/push        0/mod/indirect  3/rm32/ebx    .           .             .           .           .               .                 # push *ebx
-    # . . push labels
-    52/push-edx
-    # . . call
-    e8/call  stream-add2/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # component under test
-    # . emit-output(_test-input-stream, _test-output-buffered-file, labels)
-    # . . push args
-    52/push-edx
-    68/push  _test-output-buffered-file/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  emit-output/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # checks
-    # . flush(_test-output-buffered-file)
-    # . . push args
-    68/push  _test-output-buffered-file/imm32
-    # . . call
-    e8/call  flush/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # dump output {{{
-#?     # . write(2/stderr, "result: ^")
-#?     # . . push args
-#?     68/push  "result: ^"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, _test-output-stream)
-#?     # . . push args
-#?     68/push  _test-output-stream/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . rewind-stream(_test-output-stream)
-#?     # . . push args
-#?     68/push  _test-output-stream/imm32
-#?     # . . call
-#?     e8/call  rewind-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # }}}
-    # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-code-label/0"/imm32
-    68/push  "ab cd "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-code-label/1"/imm32
-    68/push  "ef gh "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "e8 07 00 00 00 ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-code-label/2"/imm32
-    68/push  "e8 07 00 00 00 "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-emit-output-code-label-absolute:
-    # labels can also convert to absolute addresses
-    #
-    # input:
-    #   in:
-    #     == code
-    #     ab cd
-    #     ef gh
-    #     ij l1/imm32
-    #   labels:
-    #     - 'l1': 0x1056
-    #
-    # output:
-    #   ab cd
-    #   ef gh
-    #   ij 56 10 00 00
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream($_test-output-buffered-file->buffer)
-    # . . push args
-    68/push  $_test-output-buffered-file->buffer/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . var labels/edx: (stream byte 8*24)
-    81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc0/imm32        # subtract from esp
-    68/push  0xc0/imm32/size
-    68/push  0/imm32/read
-    68/push  0/imm32/write
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # . var h/ebx: (handle array byte)
-    68/push  0/imm32
-    68/push  0/imm32
-    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
-    # initialize input
-    # . write(_test-input-stream, "== code 0x1000\n")
-    # . . push args
-    68/push  "== code\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ab cd\n")
-    # . . push args
-    68/push  "ab cd\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ef gh\n")
-    # . . push args
-    68/push  "ef gh\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . write(_test-input-stream, "ij l1/imm32\n")
-    # . . push args
-    68/push  "ij l1/imm32\n"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . stream-add2(labels, "l1", 0x1056)
-    68/push  0x1056/imm32/label-address
-    # . . push handle for "l1"
-    53/push-ebx
-    68/push  "l1"/imm32
-    68/push  Heap/imm32
-    e8/call  copy-array/disp32
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    ff          6/subop/push        1/mod/*+disp8   3/rm32/ebx    .           .             .           .           4/disp8         .                 # push *(ebx+4)
-    ff          6/subop/push        0/mod/indirect  3/rm32/ebx    .           .             .           .           .               .                 # push *ebx
-    # . . push labels
-    52/push-edx
-    # . . call
-    e8/call  stream-add2/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # component under test
-    # . emit-output(_test-input-stream, _test-output-buffered-file, labels)
-    # . . push args
-    52/push-edx
-    68/push  _test-output-buffered-file/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  emit-output/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # checks
-    # . flush(_test-output-buffered-file)
-    # . . push args
-    68/push  _test-output-buffered-file/imm32
-    # . . call
-    e8/call  flush/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # dump output {{{
-#?     # . write(2/stderr, "result: ^")
-#?     # . . push args
-#?     68/push  "result: ^"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, _test-output-stream)
-#?     # . . push args
-#?     68/push  _test-output-stream/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . rewind-stream(_test-output-stream)
-#?     # . . push args
-#?     68/push  _test-output-stream/imm32
-#?     # . . call
-#?     e8/call  rewind-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # }}}
-    # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-code-label-absolute/0"/imm32
-    68/push  "ab cd "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-code-label-absolute/1"/imm32
-    68/push  "ef gh "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg)
-    # . . push args
-    68/push  "F - test-emit-output-code-label-absolute/2"/imm32
-    68/push  "ij 56 10 00 00 "/imm32
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  check-next-stream-line-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-# reads line to make some checks
-# don't assume the read state of line after calling this function
-is-far-jump-or-call?:  # line: (addr stream byte) -> result/edi: boolean
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    50/push-eax
-    51/push-ecx
-    52/push-edx
-    53/push-ebx
-    # ecx = line
-    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
-    # var word-slice/edx: slice
-    68/push  0/imm32/end
-    68/push  0/imm32/start
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-    # var datum-slice/ebx: slice
-    68/push  0/imm32/end
-    68/push  0/imm32/start
-    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
-    # result = false
-    bf/copy-to-edi  0/imm32/false
-$is-far-jump-or-call?:check-first-word:
-    # next-word(line, word-slice)
-    # . . push args
-    52/push-edx
-    51/push-ecx
-    # . . call
-    e8/call  next-word/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # if (slice-empty?(word-slice)) return false
-    # . eax = slice-empty?(word-slice)
-    # . . push args
-    52/push-edx
-    # . . call
-    e8/call  slice-empty?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax != 0) return
-    3d/compare-eax-and  0/imm32/false
-    0f 85/jump-if-!=  $is-far-jump-or-call?:end/disp32
-    # datum = next-token-from-slice(word-slice->start, word-slice->end, "/")
-    # . . push args
-    53/push-ebx
-    68/push  0x2f/imm32/slash
-    ff          6/subop/push        1/mod/*+disp8   2/rm32/edx    .           .             .           .           4/disp8         .                 # push *(edx+4)
-    ff          6/subop/push        0/mod/indirect  2/rm32/edx    .           .             .           .           .               .                 # push *edx
-    # . . call
-    e8/call  next-token-from-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # if (datum-slice == "e8") return true
-    # . eax = slice-equal?(datum-slice, "e8")
-    # . . push args
-    68/push  "e8"/imm32
-    53/push-ebx
-    # . . call
-    e8/call  slice-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) return true
-    3d/compare-eax-and  0/imm32/false
-    75/jump-if-!=  $is-far-jump-or-call?:return-true/disp8
-    # if (datum-slice == "e9") return true
-    # . eax = slice-equal?(datum-slice, "e9")
-    # . . push args
-    68/push  "e9"/imm32
-    53/push-ebx
-    # . . call
-    e8/call  slice-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) return true
-    3d/compare-eax-and  0/imm32/false
-    75/jump-if-!=  $is-far-jump-or-call?:return-true/disp8
-    # if (datum-slice != "0f") return false
-    # . eax = slice-equal?(datum-slice, "0f")
-    # . . push args
-    68/push  "0f"/imm32
-    53/push-ebx
-    # . . call
-    e8/call  slice-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax == false) return
-    3d/compare-eax-and  0/imm32/false
-    74/jump-if-=  $is-far-jump-or-call?:end/disp8
-$is-far-jump-or-call?:check-second-word:
-    # next-word(line, word-slice)
-    # . . push args
-    52/push-edx
-    51/push-ecx
-    # . . call
-    e8/call  next-word/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # if (slice-empty?(word-slice)) return false
-    # . eax = slice-empty?(word-slice)
-    # . . push args
-    52/push-edx
-    # . . call
-    e8/call  slice-empty?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax != 0) return
-    3d/compare-eax-and  0/imm32/false
-    75/jump-if-!=  $is-far-jump-or-call?:end/disp8
-    # if datum of word-slice does not start with "8", return false
-    # . start/eax = word-slice->start
-    8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy *edx to eax
-    # . c/eax = *start
-    8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           0/r32/AL    .               .                 # copy byte at *eax to AL
-    81          4/subop/and         3/mod/direct    0/rm32/eax    .           .             .           .           .               0xff/imm32        # bitwise and of eax
-    # . if (eax != '8') return
-    3d/compare-eax-and  0x38/imm32/8
-    75/jump-if-!=  $is-far-jump-or-call?:end/disp8
-    # otherwise return true
-$is-far-jump-or-call?:return-true:
-    bf/copy-to-edi  1/imm32/true
-$is-far-jump-or-call?:end:
-    # . reclaim locals
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
-    # . restore registers
-    5b/pop-to-ebx
-    5a/pop-to-edx
-    59/pop-to-ecx
-    58/pop-to-eax
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-# - some helpers for tests
-
-stream-add2:  # in: (addr stream byte), key: handle, val: int
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    50/push-eax
-    51/push-ecx
-    52/push-edx
-    56/push-esi
-    # esi = in
-    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
-    # curr/eax = &in->data[in->write]
-    # . eax = in->write
-    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
-    # . eax = esi+eax+12
-    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
-    # max/edx = &in->data[in->size]
-    # . edx = in->size
-    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           2/r32/edx   8/disp8         .                 # copy *(esi+8) to edx
-    # . edx = esi+edx+12
-    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  2/index/edx   .           2/r32/edx   0xc/disp8       .                 # copy esi+edx+12 to edx
-    # if (curr >= max) abort
-    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
-    73/jump-if-addr>=  $stream-add2:abort/disp8
-    # *curr = key->alloc-id
-    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
-    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
-    # curr += 4
-    05/add-to-eax  4/imm32
-    # if (curr >= max) abort
-    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
-    73/jump-if-addr>=  $stream-add2:abort/disp8
-    # *curr = key->payload
-    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0x10/disp8      .                 # copy *(ebp+16) to ecx
-    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
-    # curr += 4
-    05/add-to-eax  4/imm32
-    # if (curr >= max) abort
-    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax with edx
-    73/jump-if-addr>=  $stream-add2:abort/disp8
-    # *curr = val
-    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   0x14/disp8      .                 # copy *(ebp+20) to ecx
-    89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to *eax
-    # in->write += 0xc
-    81          0/subop/add         0/mod/indirect  6/rm32/esi    .           .             .           .           .               0xc/imm32         # add to *esi
-$stream-add2:end:
-    # . restore registers
-    5e/pop-to-esi
-    5a/pop-to-edx
-    59/pop-to-ecx
-    58/pop-to-eax
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-$stream-add2:abort:
-    # . _write(2/stderr, error)
-    # . . push args
-    68/push  "overflow in stream-add2\n"/imm32
-    68/push  2/imm32/stderr
-    # . . call
-    e8/call  _write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    e8/call  syscall_exit/disp32
-    # never gets here
-
-# some variants of 'trace' that take multiple arguments in different combinations of types:
-#   n: int
-#   c: character [4-bytes, will eventually be UTF-8]
-#   s: (addr array byte)
-#   l: (addr slice)
-# one gotcha: 's5' must not be empty
-
-trace-slsns:  # s1: (addr array byte), l2: (addr slice), s3: (addr array byte), n4: int, s5: (addr array byte)
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # write(*Trace-stream, s1)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # write-slice(*Trace-stream, l2)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-    # . . call
-    e8/call  write-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # write(*Trace-stream, s3)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # write-int32-hex(*Trace-stream, n4)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
-    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-    # . . call
-    e8/call  write-int32-hex/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # trace(s5)  # implicitly adds a newline and finalizes the trace line
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x18/disp8      .                 # push *(ebp+24)
-    # . . call
-    e8/call  trace/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-$trace-slsns:end:
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-trace-slsns:
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . *Trace-stream->write = 0
-    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/eax   Trace-stream/disp32               # copy *Trace-stream to eax
-    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # clear *eax
-    # (eax..ecx) = "b"
-    b8/copy-to-eax  "b"/imm32
-    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
-    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
-    05/add-to-eax  4/imm32
-    # var b/ebx: slice = {eax, ecx}
-    51/push-ecx
-    50/push-eax
-    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           4/r32/esp   .               .                 # copy esp to ebx
-    # trace-slsls("A" b "c " 3 " e")
-    # . . push args
-    68/push  " e"/imm32
-    68/push  3/imm32
-    68/push  "c "/imm32
-    53/push-ebx
-    68/push  "A"/imm32
-    # . . call
-    e8/call  trace-slsns/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x14/imm32        # add to esp
-#?     # dump *Trace-stream {{{
-#?     # . write(2/stderr, "^")
-#?     # . . push args
-#?     68/push  "^"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write-stream(2/stderr, *Trace-stream)
-#?     # . . push args
-#?     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Trace-stream/disp32               # push *Trace-stream
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-    # check-trace-contains("Abc 0x00000003 e")
-    # . . push args
-    68/push  "F - test-trace-slsls"/imm32
-    68/push  "Abc 0x00000003 e"/imm32
-    # . . call
-    e8/call  check-trace-contains/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-num-bytes:  # line: (addr stream byte) -> eax: int
-    # pseudocode:
-    #   result = 0
-    #   while true
-    #     var word-slice = next-word(line)
-    #     if slice-empty?(word-slice)             # end of line
-    #       break
-    #     if slice-starts-with?(word-slice, "#")  # comment
-    #       break
-    #     if is-label?(word-slice)                # no need for label declarations anymore
-    #       break
-    #     if slice-equal?(word-slice, "==")
-    #       break                                 # no need for segment header lines
-    #     result += compute-width(word-slice)
-    #   return result
-    #
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # . save registers
-    51/push-ecx
-    52/push-edx
-    53/push-ebx
-    # var result/eax = 0
-    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
-    # var word-slice/ecx: slice
-    68/push  0/imm32/end
-    68/push  0/imm32/start
-    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-#?     # dump line {{{
-#?     # . write(2/stderr, "LL: ")
-#?     # . . push args
-#?     68/push  "LL: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # write-stream(2/stderr, line)
-#?     # . . push args
-#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-    # . rewind-stream(line)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  rewind-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-$num-bytes:loop:
-    # next-word(line, word-slice)
-    # . . push args
-    51/push-ecx
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  next-word/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # dump word-slice {{{
-#?     # . write(2/stderr, "AA: ")
-#?     # . . push args
-#?     68/push  "AA: "/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . clear-stream($Stderr->buffer)
-#?     # . . push args
-#?     68/push  $Stderr->buffer/imm32
-#?     # . . call
-#?     e8/call  clear-stream/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write-slice-buffered(Stderr, word-slice)
-#?     # . . push args
-#?     51/push-ecx
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  write-slice-buffered/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # . flush(Stderr)
-#?     # . . push args
-#?     68/push  Stderr/imm32
-#?     # . . call
-#?     e8/call  flush/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-#?     # . write(2/stderr, "$\n")
-#?     # . . push args
-#?     68/push  "$\n"/imm32
-#?     68/push  2/imm32/stderr
-#?     # . . call
-#?     e8/call  write/disp32
-#?     # . . discard args
-#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-#?     # }}}
-$num-bytes:check0:
-    # if (slice-empty?(word-slice)) break
-    # . save result
-    50/push-eax
-    # . eax = slice-empty?(word-slice)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call  slice-empty?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    # . restore result now that ZF is set
-    58/pop-to-eax
-    75/jump-if-!=  $num-bytes:end/disp8
-$num-bytes:check-for-comment:
-    # if (slice-starts-with?(word-slice, "#")) break
-    # . start/edx = word-slice->start
-    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # copy *ecx to edx
-    # . c/ebx = *start
-    31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
-    8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           3/r32/BL    .               .                 # copy byte at *edx to BL
-    # . if (ebx == '#') break
-    81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x23/imm32/hash   # compare ebx
-    74/jump-if-=  $num-bytes:end/disp8
-$num-bytes:check-for-label:
-    # if (slice-ends-with?(word-slice, ":")) break
-    # . end/edx = word-slice->end
-    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           2/r32/edx   4/disp8         .                 # copy *(ecx+4) to edx
-    # . c/ebx = *(end-1)
-    31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
-    8a/copy-byte                    1/mod/*+disp8   2/rm32/edx    .           .             .           3/r32/BL    -1/disp8        .                 # copy byte at *ecx to BL
-    # . if (ebx == ':') break
-    81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x3a/imm32/colon  # compare ebx
-    74/jump-if-=  $num-bytes:end/disp8
-$num-bytes:check-for-segment-header:
-    # if (slice-equal?(word-slice, "==")) break
-    # . push result
-    50/push-eax
-    # . eax = slice-equal?(word-slice, "==")
-    # . . push args
-    68/push  "=="/imm32
-    51/push-ecx
-    # . . call
-    e8/call  slice-equal?/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . if (eax != false) break
-    3d/compare-eax-and  0/imm32/false
-    # . restore result now that ZF is set
-    58/pop-to-eax
-    75/jump-if-!=  $num-bytes:end/disp8
-$num-bytes:loop-body:
-    # result += compute-width-of-slice(word-slice)
-    # . copy result to edx
-    89/copy                         3/mod/direct    2/rm32/edx    .           .             .           0/r32/eax   .               .                 # copy eax to edx
-    # . eax = compute-width-of-slice(word-slice)
-    # . . push args
-    51/push-ecx
-    # . . call
-    e8/call compute-width-of-slice/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . eax += result
-    01/add                          3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # add edx to eax
-    e9/jump  $num-bytes:loop/disp32
-$num-bytes:end:
-    # . rewind-stream(line)
-    # . . push args
-    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-    # . . call
-    e8/call  rewind-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . reclaim locals
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # . restore registers
-    5b/pop-to-ebx
-    5a/pop-to-edx
-    59/pop-to-ecx
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-handles-empty-string:
-    # if a line starts with '#', return 0
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # no contents in input
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 0, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-handles-empty-string"/imm32
-    68/push  0/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-ignores-comments:
-    # if a line starts with '#', return 0
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "# abcd")
-    # . . push args
-    68/push  "# abcd"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 0, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-ignores-comments"/imm32
-    68/push  0/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-ignores-labels:
-    # if the first word ends with ':', return 0
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "ab: # cd")
-    # . . push args
-    68/push  "ab: # cd"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 0, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-ignores-labels"/imm32
-    68/push  0/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-ignores-segment-headers:
-    # if the first word is '==', return 0
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "== ab cd")
-    # . . push args
-    68/push  "== ab cd"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 0, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-ignores-segment-headers"/imm32
-    68/push  0/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-counts-words-by-default:
-    # without metadata, count words
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "ab cd ef")
-    # . . push args
-    68/push  "ab cd ef"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 3, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-counts-words-by-default"/imm32
-    68/push  3/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-ignores-trailing-comment:
-    # trailing comments appropriately ignored
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "ab cd # ef")
-    # . . push args
-    68/push  "ab cd # ef"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 2, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-ignores-trailing-comment"/imm32
-    68/push  2/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-test-num-bytes-handles-imm32:
-    # if a word has the /imm32 metadata, count it as 4 bytes
-    # . prologue
-    55/push-ebp
-    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-    # setup
-    # . clear-stream(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # . clear-stream(_test-output-stream)
-    # . . push args
-    68/push  _test-output-stream/imm32
-    # . . call
-    e8/call  clear-stream/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # initialize input
-    # . write(_test-input-stream, "ab cd/imm32 ef")
-    # . . push args
-    68/push  "ab cd/imm32 ef"/imm32
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  write/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-    # eax = num-bytes(_test-input-stream)
-    # . . push args
-    68/push  _test-input-stream/imm32
-    # . . call
-    e8/call  num-bytes/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-    # check-ints-equal(eax, 6, msg)
-    # . . push args
-    68/push  "F - test-num-bytes-handles-imm32"/imm32
-    68/push  6/imm32/true
-    50/push-eax
-    # . . call
-    e8/call  check-ints-equal/disp32
-    # . . discard args
-    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-    # . epilogue
-    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-    5d/pop-to-ebp
-    c3/return
-
-# . . vim:nowrap:textwidth=0