about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-09-23 09:21:40 -0700
committerKartik Agaram <vc@akkartik.com>2019-09-23 09:21:40 -0700
commit5ef9597631302f6288e5e26d52fde957bfebd237 (patch)
tree886aeb1783a15553f15ec8b8aad193d3c656e6c2
parent31bbb6ac955a9043777c8f7c1926184d622a9626 (diff)
downloadmu-5ef9597631302f6288e5e26d52fde957bfebd237.tar.gz
5687
Move stack operations to a layer of their own.

It was some short-term pain to take out the syntax sugar from it, but we
need access to this layer from braces, which can't depend on sugar since
it's part of sugar. Just simpler to keep one clear line and not have to
build sometimes with some sugar but not others.
-rw-r--r--095stack.subx413
-rwxr-xr-xapps/assortbin41753 -> 42953 bytes
-rwxr-xr-xapps/bracesbin43032 -> 42998 bytes
-rw-r--r--apps/braces.subx274
-rwxr-xr-xapps/callsbin46491 -> 47691 bytes
-rwxr-xr-xapps/crenshaw2-1bin41164 -> 42364 bytes
-rwxr-xr-xapps/crenshaw2-1bbin41723 -> 42923 bytes
-rwxr-xr-xapps/dquotesbin45445 -> 46645 bytes
-rwxr-xr-xapps/factorialbin40176 -> 41376 bytes
-rwxr-xr-xapps/handlebin41069 -> 42269 bytes
-rwxr-xr-xapps/hexbin44119 -> 45319 bytes
-rwxr-xr-xapps/packbin54414 -> 55614 bytes
-rwxr-xr-xapps/sigilsbin54454 -> 55654 bytes
-rwxr-xr-xapps/surveybin51010 -> 52210 bytes
-rwxr-xr-xapps/testsbin40538 -> 41738 bytes
15 files changed, 413 insertions, 274 deletions
diff --git a/095stack.subx b/095stack.subx
new file mode 100644
index 00000000..e776e7d2
--- /dev/null
+++ b/095stack.subx
@@ -0,0 +1,413 @@
+# A stack looks like this:
+#   top: int
+#   data: (array byte)  # prefixed by length as usual
+
+== 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
+
+clear-stack:  # s : (address stack)
+    # . prolog
+    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
+    # eax = s
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+    # ecx = &s->data[s->length]
+    8b/copy                         1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(eax+4) to eax
+    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   8/disp8         .                 # copy eax+ecx+8 to ecx
+    # s->top = 0
+    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm32           # copy to *eax
+    # eax = s->data
+    81          0/subop/add         3/mod/direct    0/rm32/eax    .           .             .           .           .               8/imm32           # add to eax
+$clear-stack:loop:
+    # if (eax >= ecx) break
+    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+    73/jump-if-greater-or-equal-unsigned  $clear-stack:end/disp8
+    # *eax = 0
+    c6          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0/imm8            # copy byte to *eax
+    # ++eax
+    40/increment-eax
+    eb/jump $clear-stack:loop/disp8
+$clear-stack:end:
+    # . restore registers
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+test-clear-stack:
+    # . prolog
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # var stack/ecx = stack of size 8 with random data in it
+    68/push 34/imm32
+    68/push 35/imm32
+    68/push 8/imm32/length
+    68/push 14/imm32/top
+    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+    # clear(stack)
+    # . . push args
+    51/push-ecx
+    # . . call
+    e8/call  clear-stack/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # top should be 0
+    58/pop-to-eax
+    # . check-ints-equal(eax, 0, msg)
+    # . . push args
+    68/push  "F - test-clear-stack: top"/imm32
+    68/push  0/imm32
+    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
+    # length should remain 8
+    58/pop-to-eax
+    # . check-ints-equal(eax, 8, msg)
+    # . . push args
+    68/push  "F - test-clear-stack: length"/imm32
+    68/push  8/imm32
+    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
+    # first word is 0
+    58/pop-to-eax
+    # . check-ints-equal(eax, 0, msg)
+    # . . push args
+    68/push  "F - test-clear-stack: data[0..3]"/imm32
+    68/push  0/imm32
+    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
+    # second word is 0
+    58/pop-to-eax
+    # . check-ints-equal(eax, 0, msg)
+    # . . push args
+    68/push  "F - test-clear-stack: data[4..7]"/imm32
+    68/push  0/imm32
+    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
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+push:  # s : (address stack), n : int
+    # . prolog
+    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
+    56/push-esi
+    # esi = s
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+    # ecx = s->top
+    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+    # if (s->top >= s->length) abort
+    39/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare *(esi+4) and ecx
+    7e/jump-if-lesser-or-equal  $push:abort/disp8
+    # s->data[s->top] = n
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
+    89/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy eax to *(esi+ecx+8)
+    # s->top += 4
+    81          0/subop/add         0/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # subtract from *esi
+$push:end:
+    # . restore registers
+    5e/pop-to-esi
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+$push:abort:
+    # print(stderr, "error: push: no space left")
+    # . write-buffered(Stderr, "error: push: no space left")
+    # . . push args
+    68/push  "error: push: no space left"/imm32
+    68/push  Stderr/imm32
+    # . . call
+    e8/call  write-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
+    b8/copy-to-eax  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
+test-push:
+    # . prolog
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # var stack/ecx = empty stack of size 8
+    68/push 0/imm32
+    68/push 0/imm32
+    68/push 8/imm32/length
+    68/push 0/imm32/top
+    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+    # push(stack, 0x42)
+    # . . push args
+    68/push  0x42/imm32
+    51/push-ecx
+    # . . call
+    e8/call  push/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+    # check top
+    58/pop-to-eax
+    # . check-ints-equal(eax, 4, msg)
+    # . . push args
+    68/push  "F - test-push: top"/imm32
+    68/push  4/imm32
+    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
+    # check length
+    58/pop-to-eax
+    # . check-ints-equal(eax, 8, msg)
+    # . . push args
+    68/push  "F - test-push: length"/imm32
+    68/push  8/imm32
+    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
+    # first word is 0x42
+    58/pop-to-eax
+    # . check-ints-equal(eax, 0x42, msg)
+    # . . push args
+    68/push  "F - test-push: data[0..3]"/imm32
+    68/push  0x42/imm32
+    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
+    # second word is 0
+    58/pop-to-eax
+    # . check-ints-equal(eax, 0, msg)
+    # . . push args
+    68/push  "F - test-push: data[4..7]"/imm32
+    68/push  0/imm32
+    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
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+pop:  # s : (address stack) -> n/eax : int
+    # . prolog
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # . save registers
+    51/push-ecx
+    56/push-esi
+    # esi = s
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+    # if (s->top <= 0) abort
+    81          7/subop/compare     0/mod/indirect  6/rm32/esi    .           .             .           .           .               0/imm32           # compare *esi
+    7e/jump-if-lesser-or-equal  $pop:abort/disp8
+    # s->top -= 4
+    81          5/subop/subtract    0/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # subtract from *esi
+    # eax = s->data[s->top]
+    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+    8b/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy *(esi+ecx+8) to eax
+    # s->data[s->top] = 0
+    c7          0/subop/copy        1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         0/imm32           # copy to *(esi+ecx+8)
+$pop:end:
+    # . restore registers
+    5e/pop-to-esi
+    59/pop-to-ecx
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+$pop:abort:
+    # print(stderr, "error: pop: nothing left in stack")
+    # . write-buffered(Stderr, "error: pop: nothing left in stack")
+    # . . push args
+    68/push  "error: pop: nothing left in stack"/imm32
+    68/push  Stderr/imm32
+    # . . call
+    e8/call  write-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
+    b8/copy-to-eax  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
+test-pop:
+    # . prolog
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # var stack/ecx = stack of size 8 containing just 0x42
+    68/push 0/imm32
+    68/push 0x42/imm32
+    68/push 8/imm32/length
+    68/push 4/imm32/top
+    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+    # eax = pop(stack)
+    # . . push args
+    51/push-ecx
+    # . . call
+    e8/call  pop/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # check-ints-equal(eax, 0x42, msg)
+    # . . push args
+    68/push  "F - test-pop: result"/imm32
+    68/push  0x42/imm32
+    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
+    # check top
+    58/pop-to-eax
+    # . check-ints-equal(eax, 0, msg)
+    # . . push args
+    68/push  "F - test-pop: top"/imm32
+    68/push  0/imm32
+    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
+    # check length
+    58/pop-to-eax
+    # . check-ints-equal(eax, 8, msg)
+    # . . push args
+    68/push  "F - test-pop: length"/imm32
+    68/push  8/imm32
+    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
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+top:  # s : (address stack) -> n/eax : int
+    # . prolog
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # . save registers
+    51/push-ecx
+    56/push-esi
+    # esi = s
+    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+    # if (s->top <= 0) abort
+    81          7/subop/compare     0/mod/indirect  6/rm32/esi    .           .             .           .           .               0/imm32           # compare *esi
+    7e/jump-if-lesser-or-equal  $top:abort/disp8
+    # eax = s->data[s->top - 4]
+    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
+    81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
+    8b/copy                         1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   8/disp8         .                 # copy *(esi+ecx+8) to eax
+$top:end:
+    # . restore registers
+    5e/pop-to-esi
+    59/pop-to-ecx
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+    5d/pop-to-ebp
+    c3/return
+
+$top:abort:
+    # print(stderr, "error: top: nothing left in stack")
+    # . write-buffered(Stderr, "error: top: nothing left in stack")
+    # . . push args
+    68/push  "error: top: nothing left in stack"/imm32
+    68/push  Stderr/imm32
+    # . . call
+    e8/call  write-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
+    b8/copy-to-eax  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
+test-top:
+    # . prolog
+    55/push-ebp
+    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+    # var stack/ecx = stack of size 8 containing just 0x42
+    68/push  0/imm32
+    68/push  0x42/imm32
+    68/push  8/imm32/length
+    68/push  4/imm32/top
+    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+    # eax = top(stack)
+    # . . push args
+    51/push-ecx
+    # . . call
+    e8/call  top/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+    # check-ints-equal(eax, 42, msg")
+    # . . push args
+    68/push  "F - test-top: result"/imm32
+    68/push  0x42/imm32
+    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
+    # . epilog
+    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
diff --git a/apps/assort b/apps/assort
index 2fc33f34..e60a40a8 100755
--- a/apps/assort
+++ b/apps/assort
Binary files differdiff --git a/apps/braces b/apps/braces
index 06ffb9fe..40164153 100755
--- a/apps/braces
+++ b/apps/braces
Binary files differdiff --git a/apps/braces.subx b/apps/braces.subx
index 0b70c7a0..32042539 100644
--- a/apps/braces.subx
+++ b/apps/braces.subx
@@ -376,277 +376,3 @@ test-subx-braces-2:
     89/<- %esp 5/r32/ebp
     5d/pop-to-ebp
     c3/return
-
-# let's just put stack primitives here for now
-# we need to think about how to maintain layers of the library at different levels of syntax sugar
-
-# A stack looks like this:
-#   top: int
-#   data: (array byte)  # prefixed by length as usual
-
-clear-stack:  # s : (address stack)
-    # . prolog
-    55/push-ebp
-    89/<- %ebp 4/r32/esp
-    # . save registers
-    50/push-eax
-    51/push-ecx
-    # eax = s
-    8b/-> *(ebp+8) 0/r32/eax
-    # ecx = s->length
-    8b/-> *(eax+4) 1/r32/ecx
-    # ecx = &s->data[s->length]
-    8d/copy-address *(eax+ecx+8) 1/r32/ecx
-    # s->top = 0
-    c7/copy 0/subop/copy *eax 0/imm32
-    # eax = s->data
-    81 0/subop/add %eax 8/imm32
-$clear-stack:loop:
-    # if (eax >= ecx) break
-    39/compare %eax 1/r32/ecx
-    73/jump-if-greater-or-equal-unsigned $clear-stack:end/disp8
-    # *eax = 0
-    c6 0/subop/copy-byte *eax 0/imm8
-    # ++eax
-    40/increment-eax
-    eb/jump $clear-stack:loop/disp8
-$clear-stack:end:
-    # . restore registers
-    59/pop-to-ecx
-    58/pop-to-eax
-    # . epilog
-    89/<- %esp 5/r32/ebp
-    5d/pop-to-ebp
-    c3/return
-
-test-clear-stack:
-    # var ecx : (address stack) = stack of size 8 with random data in it
-    68/push 34/imm32
-    68/push 35/imm32
-    68/push 8/imm32/length
-    68/push 14/imm32/top
-    89/<- %ecx 4/r32/esp
-    # clear
-    (clear-stack %ecx)
-    # top should be 0
-    58/pop-to-eax
-    (check-ints-equal %eax 0 "F - test-clear-stack: top")
-    # length should remain 8
-    58/pop-to-eax
-    (check-ints-equal %eax 8 "F - test-clear-stack: length")
-    # first word is 0
-    58/pop-to-eax
-    (check-ints-equal %eax 0 "F - test-clear-stack: data[0..3]")
-    # second word is 0
-    58/pop-to-eax
-    (check-ints-equal %eax 0 "F - test-clear-stack: data[4..7]")
-    c3/return
-
-push:  # s : (address stack), n : int
-    # . prolog
-    55/push-ebp
-    89/<- %ebp 4/r32/esp
-    # . save registers
-    50/push-eax
-    51/push-ecx
-    56/push-esi
-    # esi = s
-    8b/-> *(ebp+8) 6/r32/esi
-    # ecx = s->top
-    8b/-> *esi 1/r32/ecx
-    # if (s->top >= s->length) abort
-    39/compare *(esi+4) 1/r32/ecx
-    7e/jump-if-lesser-or-equal $push:abort/disp8
-    # s->data[s->top] = n
-    8b/-> *(ebp+0xc) 0/r32/eax
-    89/<- *(esi+ecx+8) 0/r32/eax
-    # s->top += 4
-    81 0/subop/add *esi 4/imm32
-$push:end:
-    # . restore registers
-    5e/pop-to-esi
-    59/pop-to-ecx
-    58/pop-to-eax
-    # . epilog
-    89/<- %esp 5/r32/ebp
-    5d/pop-to-ebp
-    c3/return
-
-$push:abort:
-    # print(stderr, "error: push: no space left")
-    # . write-buffered(Stderr, "error: push: no space left")
-    # . . push args
-    68/push "error: push: no space left"/imm32
-    68/push Stderr/imm32
-    # . . call
-    e8/call write-buffered/disp32
-    # . . discard args
-    81 0/subop/add %esp 8/imm32
-    # . flush(Stderr)
-    # . . push args
-    68/push Stderr/imm32
-    # . . call
-    e8/call flush/disp32
-    # . . discard args
-    81 0/subop/add %esp 4/imm32
-    # . syscall(exit, 1)
-    bb/copy-to-ebx 1/imm32
-    b8/copy-to-eax 1/imm32/exit
-    cd/syscall 0x80/imm8
-    # never gets here
-
-test-push:
-    # var ecx : (address stack) = empty stack of size 8
-    68/push 0/imm32
-    68/push 0/imm32
-    68/push 8/imm32/length
-    68/push 0/imm32/top
-    89/<- %ecx 4/r32/esp
-    #
-    (push %ecx 42)
-    # top
-    58/pop-to-eax
-    (check-ints-equal %eax 4 "F - test-push: top")
-    # length
-    58/pop-to-eax
-    (check-ints-equal %eax 8 "F - test-push: length")
-    # first word is 42
-    58/pop-to-eax
-    (check-ints-equal %eax 42 "F - test-push: data[0..3]")
-    # second word is 0
-    58/pop-to-eax
-    (check-ints-equal %eax 0 "F - test-push: data[4..7]")
-    c3/return
-
-pop:  # s : (address stack) -> n/eax : int
-    # . prolog
-    55/push-ebp
-    89/<- %ebp 4/r32/esp
-    # . save registers
-    51/push-ecx
-    56/push-esi
-    # esi = s
-    8b/-> *(ebp+8) 6/r32/esi
-    # if (s->top <= 0) abort
-    81 7/subop/compare *esi 0/imm32
-    7e/jump-if-lesser-or-equal $pop:abort/disp8
-    # s->top -= 4
-    81 5/subop/subtract *esi 4/imm32
-    # eax = s->data[s->top]
-    8b/-> *esi 1/r32/ecx/top
-    8b/-> *(esi+ecx+8) 0/r32/eax
-$pop:end:
-    # . restore registers
-    5e/pop-to-esi
-    59/pop-to-ecx
-    # . epilog
-    89/<- %esp 5/r32/ebp
-    5d/pop-to-ebp
-    c3/return
-
-$pop:abort:
-    # print(stderr, "error: pop: nothing left in stack")
-    # . write-buffered(Stderr, "error: pop: nothing left in stack")
-    # . . push args
-    68/push "error: pop: nothing left in stack"/imm32
-    68/push Stderr/imm32
-    # . . call
-    e8/call write-buffered/disp32
-    # . . discard args
-    81 0/subop/add %esp 8/imm32
-    # . flush(Stderr)
-    # . . push args
-    68/push Stderr/imm32
-    # . . call
-    e8/call flush/disp32
-    # . . discard args
-    81 0/subop/add %esp 4/imm32
-    # . syscall(exit, 1)
-    bb/copy-to-ebx 1/imm32
-    b8/copy-to-eax 1/imm32/exit
-    cd/syscall 0x80/imm8
-    # never gets here
-
-test-pop:
-    # var ecx : (address stack) = stack of size 8 containing just 42
-    68/push 0/imm32
-    68/push 42/imm32
-    68/push 8/imm32/length
-    68/push 4/imm32/top
-    89/<- %ecx 4/r32/esp
-    #
-    (pop %ecx)  # => eax
-    # result
-    (check-ints-equal %eax 42 "F - test-pop: result")
-    # top
-    58/pop-to-eax
-    (check-ints-equal %eax 0 "F - test-pop: top")
-    # length
-    58/pop-to-eax
-    (check-ints-equal %eax 8 "F - test-pop: length")
-    # clean up
-    81 0/subop/add %esp 8/imm32
-    c3/return
-
-top:  # s : (address stack) -> n/eax : int
-    # . prolog
-    55/push-ebp
-    89/<- %ebp 4/r32/esp
-    # . save registers
-    51/push-ecx
-    56/push-esi
-    # esi = s
-    8b/-> *(ebp+8) 6/r32/esi
-    # if (s->top <= 0) abort
-    81 7/subop/compare *esi 0/imm32
-    7e/jump-if-lesser-or-equal $top:abort/disp8
-    # eax = s->data[s->top - 4]
-    8b/-> *esi 1/r32/ecx/top
-    81 5/subop/subtract %ecx 4/imm32
-    8b/-> *(esi+ecx+8) 0/r32/eax
-$top:end:
-    # . restore registers
-    5e/pop-to-esi
-    59/pop-to-ecx
-    # . epilog
-    89/<- %esp 5/r32/ebp
-    5d/pop-to-ebp
-    c3/return
-
-$top:abort:
-    # print(stderr, "error: top: nothing left in stack")
-    # . write-buffered(Stderr, "error: top: nothing left in stack")
-    # . . push args
-    68/push "error: top: nothing left in stack"/imm32
-    68/push Stderr/imm32
-    # . . call
-    e8/call write-buffered/disp32
-    # . . discard args
-    81 0/subop/add %esp 8/imm32
-    # . flush(Stderr)
-    # . . push args
-    68/push Stderr/imm32
-    # . . call
-    e8/call flush/disp32
-    # . . discard args
-    81 0/subop/add %esp 4/imm32
-    # . syscall(exit, 1)
-    bb/copy-to-ebx 1/imm32
-    b8/copy-to-eax 1/imm32/exit
-    cd/syscall 0x80/imm8
-    # never gets here
-
-test-top:
-    # var ecx : (address stack) = stack of size 8 containing just 42
-    68/push 0/imm32
-    68/push 42/imm32
-    68/push 8/imm32/length
-    68/push 4/imm32/top
-    89/<- %ecx 4/r32/esp
-    #
-    (top %ecx)  # => eax
-    # result
-    (check-ints-equal %eax 42 "F - test-top: result")
-    # clean up
-    81 0/subop/add %esp 0x10/imm32
-    c3/return
diff --git a/apps/calls b/apps/calls
index dbe3c0ae..7cabc825 100755
--- a/apps/calls
+++ b/apps/calls
Binary files differdiff --git a/apps/crenshaw2-1 b/apps/crenshaw2-1
index 096d5342..ca629e9c 100755
--- a/apps/crenshaw2-1
+++ b/apps/crenshaw2-1
Binary files differdiff --git a/apps/crenshaw2-1b b/apps/crenshaw2-1b
index af0e221a..dd1292ed 100755
--- a/apps/crenshaw2-1b
+++ b/apps/crenshaw2-1b
Binary files differdiff --git a/apps/dquotes b/apps/dquotes
index cfe72703..351742e6 100755
--- a/apps/dquotes
+++ b/apps/dquotes
Binary files differdiff --git a/apps/factorial b/apps/factorial
index f104624c..e3e02af5 100755
--- a/apps/factorial
+++ b/apps/factorial
Binary files differdiff --git a/apps/handle b/apps/handle
index 14441a0c..c0f4a4fb 100755
--- a/apps/handle
+++ b/apps/handle
Binary files differdiff --git a/apps/hex b/apps/hex
index 172bf918..eade5fa7 100755
--- a/apps/hex
+++ b/apps/hex
Binary files differdiff --git a/apps/pack b/apps/pack
index cbab4e72..a2cd9595 100755
--- a/apps/pack
+++ b/apps/pack
Binary files differdiff --git a/apps/sigils b/apps/sigils
index f2d07269..d8cdaf55 100755
--- a/apps/sigils
+++ b/apps/sigils
Binary files differdiff --git a/apps/survey b/apps/survey
index 14843f57..6595e7cf 100755
--- a/apps/survey
+++ b/apps/survey
Binary files differdiff --git a/apps/tests b/apps/tests
index 426650be..0dd18754 100755
--- a/apps/tests
+++ b/apps/tests
Binary files differ