about summary refs log tree commit diff stats
path: root/095stack.subx
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 /095stack.subx
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.
Diffstat (limited to '095stack.subx')
-rw-r--r--095stack.subx413
1 files changed, 413 insertions, 0 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