From 5ef9597631302f6288e5e26d52fde957bfebd237 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 23 Sep 2019 09:21:40 -0700 Subject: 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. --- 095stack.subx | 413 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 095stack.subx (limited to '095stack.subx') 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 -- cgit 1.4.1-2-gfad0