diff options
-rw-r--r-- | subx/051test.subx | 17 | ||||
-rw-r--r-- | subx/052kernel_string_equal.subx | 20 | ||||
-rw-r--r-- | subx/053new_segment.subx | 4 | ||||
-rw-r--r-- | subx/054string_equal.subx | 13 | ||||
-rw-r--r-- | subx/055trace.subx | 34 | ||||
-rw-r--r-- | subx/056write.subx | 10 | ||||
-rw-r--r-- | subx/057stop.subx | 14 | ||||
-rw-r--r-- | subx/058read.subx | 48 | ||||
-rw-r--r-- | subx/059read-byte.subx | 41 | ||||
-rw-r--r-- | subx/060write-stream.subx | 42 | ||||
-rw-r--r-- | subx/apps/crenshaw2-1.subx | 136 | ||||
-rw-r--r-- | subx/apps/crenshaw2-1b.subx | 216 | ||||
-rw-r--r-- | subx/apps/factorial.subx | 20 | ||||
-rw-r--r-- | subx/examples/ex1.subx | 4 | ||||
-rw-r--r-- | subx/examples/ex10.subx | 11 | ||||
-rw-r--r-- | subx/examples/ex11.subx | 38 | ||||
-rw-r--r-- | subx/examples/ex12.subx | 4 | ||||
-rw-r--r-- | subx/examples/ex2.subx | 6 | ||||
-rw-r--r-- | subx/examples/ex3.subx | 4 | ||||
-rw-r--r-- | subx/examples/ex4.subx | 18 | ||||
-rw-r--r-- | subx/examples/ex5.subx | 18 | ||||
-rw-r--r-- | subx/examples/ex6.subx | 14 | ||||
-rw-r--r-- | subx/examples/ex7.subx | 21 | ||||
-rw-r--r-- | subx/examples/ex8.subx | 14 | ||||
-rw-r--r-- | subx/examples/ex9.subx | 11 |
25 files changed, 394 insertions, 384 deletions
diff --git a/subx/051test.subx b/subx/051test.subx index 2f93c914..e19b243c 100644 --- a/subx/051test.subx +++ b/subx/051test.subx @@ -7,14 +7,17 @@ # main: (manual test if this is the last file loaded) # check-ints-equal(34, 34) + # . . push args 68/push "error in check-ints-equal"/imm32 68/push 34/imm32 68/push 34/imm32 + # . . call e8/call check-ints-equal/disp32 + # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP # syscall(exit, 0) bb/copy-to-EBX 0/imm32 - b8/copy-to-EAX 1/imm32 + b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 # print msg to stderr if a != b, otherwise print "." @@ -28,10 +31,10 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean # load first 2 args into EAX and EBX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 0x8/disp8 . # copy *(EBP+8) to EAX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # if EAX == b/EBX + # if EAX == EBX success 39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX 75/jump-if-unequal $check-ints-equal:else/disp8 - # _write(2/stderr, '.') + # . _write(2/stderr, '.') # . . push args 68/push "."/imm32 68/push 2/imm32/stderr @@ -39,11 +42,11 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean e8/call _write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # return + # . return eb/jump $check-ints-equal:end/disp8 - # else: + # otherwise print error message $check-ints-equal:else: - # _write(2/stderr, msg) + # . _write(2/stderr, msg) # . . push args 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX 51/push-ECX @@ -52,7 +55,7 @@ $check-ints-equal:else: e8/call _write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # _write(2/stderr, Newline) + # . _write(2/stderr, Newline) # . . push args 68/push Newline/imm32 68/push 2/imm32/stderr diff --git a/subx/052kernel_string_equal.subx b/subx/052kernel_string_equal.subx index 696f0f8f..e288c5ee 100644 --- a/subx/052kernel_string_equal.subx +++ b/subx/052kernel_string_equal.subx @@ -1,4 +1,4 @@ -## Checking null-terminated ascii strings. +# Checking null-terminated ascii strings. # # By default we create strings with a 4-byte length prefix rather than a null suffix. # However we still need null-prefixed strings when interacting with the Linux @@ -21,7 +21,7 @@ # main: e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - # exit(Num-test-failures) + # 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 b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 @@ -109,7 +109,7 @@ $kernel-string-equal:end: 5d/pop-to-EBP c3/return -## tests +# - tests test-compare-null-kernel-string-with-empty-array: # EAX = kernel-string-equal(Null-kernel-string, "") @@ -120,7 +120,7 @@ test-compare-null-kernel-string-with-empty-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 1, msg) + # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32 68/push 1/imm32/true @@ -140,7 +140,7 @@ test-compare-null-kernel-string-with-non-empty-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0, msg) + # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32 68/push 0/imm32/false @@ -160,7 +160,7 @@ test-compare-kernel-string-with-equal-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 1, msg) + # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push 1/imm32/true @@ -180,7 +180,7 @@ test-compare-kernel-string-with-inequal-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0, msg) + # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push 0/imm32/false @@ -200,7 +200,7 @@ test-compare-kernel-string-with-empty-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0) + # check-ints-equal(EAX, 0) # . . push args 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push 0/imm32/false @@ -220,7 +220,7 @@ test-compare-kernel-string-with-shorter-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0) + # check-ints-equal(EAX, 0) # . . push args 68/push "F - test-compare-kernel-string-with-shorter-array"/imm32 68/push 0/imm32/false @@ -240,7 +240,7 @@ test-compare-kernel-string-with-longer-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0) + # check-ints-equal(EAX, 0) # . . push args 68/push "F - test-compare-kernel-string-with-longer-array"/imm32 68/push 0/imm32/false diff --git a/subx/053new_segment.subx b/subx/053new_segment.subx index 3809eee5..25efaf94 100644 --- a/subx/053new_segment.subx +++ b/subx/053new_segment.subx @@ -14,10 +14,10 @@ # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # store to *EAX + # write to *EAX to check that we have access to the newly-allocated segment c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX - # exit(EAX) + # syscall(exit, EAX) 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 diff --git a/subx/054string_equal.subx b/subx/054string_equal.subx index 44222e1e..69227074 100644 --- a/subx/054string_equal.subx +++ b/subx/054string_equal.subx @@ -6,8 +6,9 @@ # . 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 # main: + # run-tests() e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. - # exit(Num-test-failures) + # 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 b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 @@ -84,7 +85,7 @@ $string-equal:end: 5d/pop-to-EBP c3/return -## tests +# - tests test-compare-empty-with-empty-string: # EAX = string-equal("", "") @@ -95,7 +96,7 @@ test-compare-empty-with-empty-string: e8/call string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 1, msg) + # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-compare-empty-with-empty-string"/imm32 68/push 1/imm32/true @@ -115,7 +116,7 @@ test-compare-empty-with-non-empty-string: # also checks length-mismatch code pa e8/call string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0, msg) + # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-compare-empty-with-non-empty-string"/imm32 68/push 0/imm32/false @@ -135,7 +136,7 @@ test-compare-equal-strings: e8/call string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 1, msg) + # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-compare-equal-strings"/imm32 68/push 1/imm32/true @@ -155,7 +156,7 @@ test-compare-inequal-strings-equal-lengths: e8/call string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0, msg) + # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-compare-inequal-strings-equal-lengths"/imm32 68/push 0/imm32/false diff --git a/subx/055trace.subx b/subx/055trace.subx index 2f281ced..02bdc0fd 100644 --- a/subx/055trace.subx +++ b/subx/055trace.subx @@ -43,6 +43,7 @@ _test-trace-stream: # . 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 # main: + # run-tests() e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. # 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 @@ -87,12 +88,12 @@ trace: # t : (address trace-stream), line : string # EDX = t->length 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX # EAX = _append-3(&t->data[t->write], &t->data[t->length], line) - # push line + # . . push line 56/push-ESI - # push &t->data[t->length] + # . . push &t->data[t->length] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX 53/push-EBX - # push &t->data[t->write] + # . . push &t->data[t->write] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX 53/push-EBX # . . call @@ -107,12 +108,12 @@ trace: # t : (address trace-stream), line : string # refresh ECX = t->write 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX # EAX = _append-3(&t->data[t->write], &t->data[t->length], line) - # push line + # . . push line 68/push Newline/imm32 - # push &t->data[t->length] + # . . push &t->data[t->length] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy EDI+EDX+12 to EBX 53/push-EBX - # push &t->data[t->write] + # . . push &t->data[t->write] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 1/index/ECX . 3/r32/EBX 0xc/disp8 . # copy EDI+ECX+12 to EBX 53/push-EBX # . . call @@ -172,7 +173,7 @@ $clear-trace-stream:end: 5d/pop-to-EBP c3/return -## tests +# - tests test-trace-single: # clear-trace-stream(_test-trace-stream) @@ -194,7 +195,7 @@ test-trace-single: # . . push args 68/push "F - test-trace-single"/imm32 68/push 0x0a6241/imm32/Ab-newline - # push *_test-trace-stream.data + # . . push *_test-trace-stream.data b8/copy-to-EAX _test-trace-stream/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call @@ -232,7 +233,7 @@ test-trace-appends: # . . push args 68/push "F - test-trace-appends"/imm32 68/push 0x0a440a43/imm32/C-newline-D-newline - # push *_test-trace-stream.data + # . . push *_test-trace-stream.data b8/copy-to-EAX _test-trace-stream/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call @@ -262,7 +263,7 @@ test-trace-empty-line: # . . push args 68/push "F - test-trace-empty-line"/imm32 68/push 0/imm32 - # push *_test-trace-stream.data + # . . push *_test-trace-stream.data b8/copy-to-EAX _test-trace-stream/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call @@ -272,7 +273,7 @@ test-trace-empty-line: # end c3/return -## helpers +# - helpers # 3-argument variant of _append _append-3: # out : address, outend : address, s : (array byte) -> num_bytes_appended/EAX @@ -282,20 +283,17 @@ _append-3: # out : address, outend : address, s : (array byte) -> num_bytes_app # . save registers 51/push-ECX # _append-4(out, outend, &s.data[0], &s.data[s.length]) -> num_bytes_appended/EAX - # push &s.data[s.length] - # EAX = s + # . . push &s.data[s.length] 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX - # ECX = s.length 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - # ECX = &s.data[s.length] 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 51/push-ECX - # push &s.data[0] + # . . push &s.data[0] 8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy EAX+4 to ECX 51/push-ECX - # push outend + # . . push outend ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - # push out + # . . push out ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) # . . call e8/call _append-4/disp32 diff --git a/subx/056write.subx b/subx/056write.subx index 6638b174..a76dd12e 100644 --- a/subx/056write.subx +++ b/subx/056write.subx @@ -58,12 +58,12 @@ $write:fake: # EBX = f->length 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 8/disp8 . # copy *(ECX+8) to EBX # EAX = _append-3(&f->data[f->write], &f->data[f->length], s) - # push s + # . . push s ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - # push &f->data[f->length] + # . . push &f->data[f->length] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy ECX+EBX+12 to EBX 53/push-EBX - # push &f->data[f->write] + # . . push &f->data[f->write] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy ECX+EDX+12 to EBX 53/push-EBX # . . call @@ -149,7 +149,7 @@ test-write-single: # . . push args 68/push "F - test-write-single"/imm32 68/push 0x006241/imm32/Ab - # push *_test-stream->data + # . . push *_test-stream->data b8/copy-to-EAX _test-stream/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call @@ -187,7 +187,7 @@ test-write-appends: # . . push args 68/push "F - test-write-appends"/imm32 68/push 0x00004443/imm32/C-D - # push *_test-stream->data + # . . push *_test-stream->data b8/copy-to-EAX _test-stream/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call diff --git a/subx/057stop.subx b/subx/057stop.subx index b9ef4467..fd2afde2 100644 --- a/subx/057stop.subx +++ b/subx/057stop.subx @@ -65,7 +65,7 @@ tailor-exit-descriptor: # ed : (address exit-descriptor), nbytes : int -> <void # That's the value we need to return: X-nbytes-4 # # However, we also need to account for the perturbance to ESP caused by the - # . . call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 + # call to tailor-exit-descriptor. It pushes 8 bytes of args followed by 4 # bytes for the return address and 4 bytes to push EBP above. # So EBP at this point is X-16. # @@ -139,12 +139,12 @@ test-stop-skips-returns-on-exit: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call _test-stop-1(ed) + # . _test-stop-1(ed) # . . push args 50/push-EAX # . . call e8/call _test-stop-1/disp32 - ## registers except ESP may be clobbered at this point + # registers except ESP may be clobbered at this point # restore args 58/pop-to-EAX # check that _test-stop-1 tried to call exit(1) @@ -152,7 +152,7 @@ test-stop-skips-returns-on-exit: # . . push args 68/push "F - test-stop-skips-returns-on-exit"/imm32 68/push 2/imm32 - # push ed->value + # . . push ed->value ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) # . . call e8/call check-ints-equal/disp32 @@ -173,7 +173,7 @@ _test-stop-1: # ed : (address exit-descriptor) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call e8/call _test-stop-2/disp32 - ## should never get past this point + # should never get past this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP # signal test failed: check-ints-equal(1, 0, msg) @@ -194,13 +194,13 @@ _test-stop-2: # ed : (address exit-descriptor) # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . . call stop(ed, 1) + # . stop(ed, 1) # . . push args 68/push 1/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call e8/call stop/disp32 - ## should never get past this point + # should never get past this point # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP diff --git a/subx/058read.subx b/subx/058read.subx index ccd7e349..df301ca8 100644 --- a/subx/058read.subx +++ b/subx/058read.subx @@ -56,7 +56,7 @@ read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - ## if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor + # if (f < 0x08000000) return _read(f, s) # f can't be a user-mode address, so treat it as a kernel file descriptor 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) 7d/jump-if-greater-or-equal $read:fake/disp8 # . . push args @@ -69,7 +69,7 @@ read: # f : fd or (address stream), s : (address stream) -> num-bytes-read/EAX # return eb/jump $read:end/disp8 $read:fake: - ## otherwise, treat 'f' as a stream to scan from + # otherwise, treat 'f' as a stream to scan from # . save registers 56/push-ESI 57/push-EDI @@ -79,19 +79,19 @@ $read:fake: 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to ESI # EAX = _append-4(out = &s->data[s->write], outend = &s->data[s->length], # in = &f->data[f->read], inend = &f->data[f->write]) - # push &f->data[f->write] + # . . push &f->data[f->write] 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX 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 50/push-EAX - # push &f->data[f->read] + # . . push &f->data[f->read] 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX 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 50/push-EAX - # push &s->data[s->length] + # . . push &s->data[s->length] 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 8/disp8 . # copy *(EDI+8) to EAX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX 50/push-EAX - # push &s->data[s->write] + # . . push &s->data[s->write] 8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX 50/push-EAX @@ -112,7 +112,7 @@ $read:end: 5d/pop-to-EBP c3/return -## helpers +# - helpers # idea: a clear-if-empty method on streams that clears only if f.read == f.write # Unclear how I'd use it, though. Callers seem to need the check anyway. @@ -134,13 +134,13 @@ _read: # fd : int, s : (address stream) -> num-bytes-read/EAX # EDX = s->length 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX # syscall(read, fd, &s->data[s->write], s->length - s->write) - # fd : EBX + # . . fd : EBX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX - # data : ECX = &s->data[s->write] + # . . data : ECX = &s->data[s->write] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 1/r32/ECX 0xc/disp8 . # copy ESI+EAX+12 to ECX - # size : EDX = s->length - s->write + # . . size : EDX = s->length - s->write 29/subtract 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # subtract EAX from EDX - # syscall + # . . syscall b8/copy-to-EAX 3/imm32/read cd/syscall 0x80/imm8 # add the result EAX to s->write @@ -176,9 +176,10 @@ _read: # fd : int, s : (address stream) -> num-bytes-read/EAX # use one less register, but doesn't increase the amount of spilling (ECX # and EDX must be used, and EAX must be clobbered anyway). -## tests +# - tests test-read-single: + # - write a single character into _test-stream, then read from its buffered-file # clear-stream(_test-stream) # . . push args 68/push _test-stream/imm32 @@ -222,7 +223,7 @@ test-read-single: # . . push args 68/push "F - test-read-single"/imm32 68/push 0x006241/imm32/Ab - # push *_test-stream-buffer->data + # . . push *_test-stream-buffer->data b8/copy-to-EAX _test-stream-buffer/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call @@ -233,7 +234,7 @@ test-read-single: c3/return test-read-is-stateful: - ## make two consecutive reads, check that their results are appended + # - make two consecutive reads, check that their results are appended # clear-stream(_test-stream) # . . push args 68/push _test-stream/imm32 @@ -284,7 +285,7 @@ test-read-is-stateful: # . . push args 68/push "F - test-read-is-stateful"/imm32 68/push 0x00004443/imm32/C-D - # push *_test-stream-buffer->data + # . push *_test-stream-buffer->data b8/copy-to-EAX _test-stream-buffer/imm32 ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) # . . call @@ -295,22 +296,23 @@ test-read-is-stateful: c3/return test-read-returns-0-on-end-of-file: - ## read after hitting end-of-file, check that result is 0 - # clear-stream(_test-stream) + # - read after hitting end-of-file, check that result is 0 + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-stream-buffer) + # . clear-stream(_test-stream-buffer) # . . push args 68/push _test-stream-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(_test-stream, "Ab") + # . write(_test-stream, "Ab") # . . push args 68/push "Ab"/imm32 68/push _test-stream/imm32 @@ -318,8 +320,8 @@ test-read-returns-0-on-end-of-file: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## first read gets to end-of-file - # read(_test-stream, _test-stream-buffer) + # first read gets to end-of-file + # . read(_test-stream, _test-stream-buffer) # . . push args 68/push _test-stream-buffer/imm32 68/push _test-stream/imm32 @@ -327,8 +329,8 @@ test-read-returns-0-on-end-of-file: e8/call read/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## second read - # read(_test-stream, _test-stream-buffer) + # second read + # . read(_test-stream, _test-stream-buffer) # . . push args 68/push _test-stream-buffer/imm32 68/push _test-stream/imm32 diff --git a/subx/059read-byte.subx b/subx/059read-byte.subx index 39d818f4..b020442b 100644 --- a/subx/059read-byte.subx +++ b/subx/059read-byte.subx @@ -52,10 +52,11 @@ read-byte: # f : (address buffered-file) -> byte/EAX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI # ECX = f->read 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX - ## if (f->read < f->write) read byte from stream + # if (f->read < f->write) read byte from stream 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4) 7c/jump-if-lesser $read-byte:from-stream/disp8 - # clear-stream(stream = f+4) + # otherwise first populate stream from file + # . clear-stream(stream = f+4) # . . push args 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX 50/push-EAX @@ -63,7 +64,7 @@ read-byte: # f : (address buffered-file) -> byte/EAX e8/call clear-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # EAX = read(f->fd, stream = f+4) + # . EAX = read(f->fd, stream = f+4) # . . push args 50/push-EAX ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI @@ -77,6 +78,7 @@ read-byte: # f : (address buffered-file) -> byte/EAX b8/copy-to-EAX 0xffffffff/imm32 eb/jump $read-byte:end/disp8 $read-byte:from-stream: + # reading from stream # AL = f->data[f->read] 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy *(ESI+ECX+16) to AL @@ -94,18 +96,19 @@ $read-byte:end: # todo: how should write-byte look? What should it do when the output has no # space remaining? Maybe return an error code. -## tests +# - tests test-read-byte-single: - ## check that read-byte returns first byte of 'file' - # clear-stream(_test-stream) + # - check that read-byte returns first byte of 'file' + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -114,7 +117,7 @@ test-read-byte-single: e8/call clear-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # write(_test-stream, "Ab") + # . write(_test-stream, "Ab") # . . push args 68/push "Ab"/imm32 68/push _test-stream/imm32 @@ -138,19 +141,20 @@ test-read-byte-single: e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # end + # . end c3/return test-read-byte-multiple: - ## call read-byte twice, check that second call returns second byte - # clear-stream(_test-stream) + # - call read-byte twice, check that second call returns second byte + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -159,7 +163,7 @@ test-read-byte-multiple: e8/call clear-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # write(_test-stream, "Ab") + # . write(_test-stream, "Ab") # . . push args 68/push "Ab"/imm32 68/push _test-stream/imm32 @@ -190,19 +194,20 @@ test-read-byte-multiple: e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # end + # . end c3/return test-read-byte-end-of-file: - ## call read-byte on an empty 'file', check that it returns -1 - # clear-stream(_test-stream) + # - call read-byte on an empty 'file', check that it returns -1 + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -227,7 +232,7 @@ test-read-byte-end-of-file: e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # end + # . end c3/return == data diff --git a/subx/060write-stream.subx b/subx/060write-stream.subx index cf178bc1..59616a01 100644 --- a/subx/060write-stream.subx +++ b/subx/060write-stream.subx @@ -45,19 +45,19 @@ $write-stream:fake: # EDI = s 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI # EAX = _append-4(&f->data[f->write], &f->data[f->length], &s->data[s->read], &s->data[s->write]) - # push &s->data[s->write] + # . . push &s->data[s->write] 8b/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy *EDI to EAX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX 50/push-EAX - # push &s->data[s->read] + # . . push &s->data[s->read] 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy *(EDI+4) to EAX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/EDI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy EDI+EAX+12 to EAX 50/push-EAX - # push &f->data[f->length] + # . . push &f->data[f->length] 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX 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 50/push-EAX - # push &f->data[f->write] + # . . push &f->data[f->write] 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX 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 50/push-EAX @@ -97,13 +97,13 @@ _write-stream: # fd : int, s : (address stream) -> <void> # EDX = s->write 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX # syscall(write, fd, &s->data[s->read], s->write-s->read) - # fd : EBX + # . . fd : EBX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX - # data : ECX = &s->data[s->read] + # . . data : ECX = &s->data[s->read] 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 7/index/EDI . 1/r32/ECX 0xc/disp8 . # copy ESI+EDI+12 to ECX - # size : EDX = s->write - s->read + # . . size : EDX = s->write - s->read 29/subtract 3/mod/direct 2/rm32/EDX . . . 7/r32/EDI . . # subtract EDI from EDX - # syscall + # . . syscall b8/copy-to-EAX 4/imm32/write cd/syscall 0x80/imm8 # . restore registers @@ -119,21 +119,22 @@ _write-stream: # fd : int, s : (address stream) -> <void> c3/return test-write-stream-single: - # clear-stream(_test-stream) + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-stream2) + # . clear-stream(_test-stream2) # . . push args 68/push _test-stream2/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(_test-stream2, "Ab") + # . write(_test-stream2, "Ab") # . . push args 68/push "Ab"/imm32 68/push _test-stream2/imm32 @@ -160,25 +161,26 @@ test-write-stream-single: e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # end + # . end c3/return test-write-stream-appends: - # clear-stream(_test-stream) + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-stream2) + # . clear-stream(_test-stream2) # . . push args 68/push _test-stream2/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(_test-stream2, "C") + # . write(_test-stream2, "C") # . . push args 68/push "C"/imm32 68/push _test-stream2/imm32 @@ -186,7 +188,8 @@ test-write-stream-appends: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream(_test-stream, _test-stream2) + # first write + # . write-stream(_test-stream, _test-stream2) # . . push args 68/push _test-stream2/imm32 68/push _test-stream/imm32 @@ -194,7 +197,8 @@ test-write-stream-appends: e8/call write-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(_test-stream2, "D") + # second write + # . write(_test-stream2, "D") # . . push args 68/push "D"/imm32 68/push _test-stream2/imm32 @@ -202,7 +206,7 @@ test-write-stream-appends: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream(_test-stream, _test-stream2) + # . write-stream(_test-stream, _test-stream2) # . . push args 68/push _test-stream2/imm32 68/push _test-stream/imm32 @@ -221,7 +225,7 @@ test-write-stream-appends: e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # end + # . end c3/return == data diff --git a/subx/apps/crenshaw2-1.subx b/subx/apps/crenshaw2-1.subx index 08f679fc..42c5b119 100644 --- a/subx/apps/crenshaw2-1.subx +++ b/subx/apps/crenshaw2-1.subx @@ -33,10 +33,11 @@ # main: run tests if necessary, call 'compile' if not # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # if (argc > 1) + # - if argc > 1 and argv[1] == "test" then return run_tests() + # . argc > 1 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 - # and if (argv[1] == "test") + # . argv[1] == "test" # . . push args 68/push "test"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) @@ -47,19 +48,20 @@ # . check result 3d/compare-EAX 1/imm32 75/jump-if-not-equal $run-main/disp8 - # then return run-tests() + # . run-tests() e8/call run-tests/disp32 #? e8/call test-get-num-reads-multiple-digits/disp32 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX eb/jump $main:end/disp8 $run-main: - # allocate space for an exit-descriptor - # . var ed/EAX : (address exit-descriptor) + # - otherwise read a program from stdin and emit its translation to stdout + # var ed/EAX : exit-descriptor 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # . clear ed->target (so we really exit) + # configure ed to really exit() + # . ed->target = 0 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # compile(Stdin, 1/stdout, 2/stderr, ed) + # return compile(Stdin, 1/stdout, 2/stderr, ed) # . . push args 50/push-EAX/ed 68/push 2/imm32/stderr @@ -69,7 +71,7 @@ $run-main: e8/call compile/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # syscall(exit, 0) + # . syscall(exit, 0) bb/copy-to-EBX 0/imm32 $main:end: b8/copy-to-EAX 1/imm32/exit @@ -83,7 +85,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd # . save registers 50/push-EAX 51/push-ECX - # Look = get-char(in) + # . Look = get-char(in) # . . push args ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call @@ -98,14 +100,15 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX # num->length = 7 c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) - # clear-stream(num) + # read a digit from 'in' into 'num' + # . clear-stream(num) # . . 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 - # get-num(in, num, err, ed) + # . get-num(in, num, err, ed) # . . push args ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) @@ -115,15 +118,12 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call get-num/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # EAX = write(_test-stream, "Ab") - # . . push args - 68/push "Ab"/imm32 - 68/push _test-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 = write(out, "bb/copy-to-EBX ") + # render 'num' into the following template on 'out': + # bb/copy-to-EBX _num_ + # b8/copy-to-EAX 1/imm32/exit + # cd/syscall 0x80/imm8 + # + # . EAX = write(out, "bb/copy-to-EBX ") # . . push args 68/push "bb/copy-to-EBX "/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -131,7 +131,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream(out, num) + # . write-stream(out, num) # . . push args 51/push-ECX/num ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -139,7 +139,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(out, Newline) + # . write(out, Newline) # . . push args 68/push Newline/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -147,7 +147,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, "b8/copy-to-EAX 1/imm32/exit") + # . write(out, "b8/copy-to-EAX 1/imm32/exit") # . . push args 68/push "b8/copy-to-EAX 1/imm32/exit"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -155,7 +155,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, Newline) + # . write(out, Newline) # . . push args 68/push Newline/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -163,7 +163,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, "cd/syscall 0x80/imm8") + # . write(out, "cd/syscall 0x80/imm8") # . . push args 68/push "cd/syscall 0x80/imm8"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -171,7 +171,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, Newline) + # . write(out, Newline) # . . push args 68/push Newline/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -179,7 +179,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore registers + # . restore registers 59/pop-to-ECX 58/pop-to-EAX # . epilog @@ -200,7 +200,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a # ++out.write # Look = get-char(in) # - # within the loop we'll try to keep things in registers: + # registers: # ESI : in # EDI : out # EAX : temp @@ -214,14 +214,15 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # EAX = is-digit?(Look) + # - if is-digit?(Look) expected(ed, err, "integer") + # . EAX = is-digit?(Look) # . . push args ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look # . . call e8/call is-digit?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # if EAX == 0 error + # . if EAX == 0 3d/compare-EAX 0/imm32 75/jump-if-not-equal $get-num:main/disp8 # . expected(ed, err, "integer") @@ -234,6 +235,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP $get-num:main: + # - otherwise read a digit # . save registers 50/push-EAX 51/push-ECX @@ -253,7 +255,7 @@ $get-num:main: # if out->write >= out->length error 3b/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare EDX with ECX 7d/jump-if-lesser $get-num:stage2/disp8 - # error(ed, err, "get-num: too many digits in number") # TODO: show full number + # . error(ed, err, msg) # TODO: show full number # . . push args 68/push "get-num: too many digits in number"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) @@ -296,15 +298,15 @@ test-get-num-reads-single-digit: # This test uses exit-descriptors. Use EBP for setting up local variables. 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - clear all streams - # clear-stream(_test-stream) + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -313,22 +315,22 @@ test-get-num-reads-single-digit: 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) + # . 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-error-stream) + # . clear-stream(_test-error-stream) # . . push args 68/push _test-error-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 'in' - # write(_test-stream, "3") + # initialize 'in' + # . write(_test-stream, "3") # . . push args 68/push "3"/imm32 68/push _test-stream/imm32 @@ -336,13 +338,11 @@ test-get-num-reads-single-digit: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # - initialize exit-descriptor 'ed' - # allocate on stack - # var ed/EAX : (address exit-descriptor) + # initialize exit-descriptor 'ed' for the call to 'get-num' below + # . var ed/EAX : exit-descriptor 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # size the exit-descriptor for the call to get-num below - # tailor-exit-descriptor(ed, 16) + # . tailor-exit-descriptor(ed, 16) # . . push args 68/push 0x10/imm32/nbytes-of-args-for-get-num 50/push-EAX/ed @@ -350,15 +350,15 @@ test-get-num-reads-single-digit: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # - prime the pump - # get-char(_test-buffered-file) + # prime the pump + # . get-char(_test-buffered-file) # . . push args 68/push _test-buffered-file/imm32 # . . call e8/call get-char/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - ## get-num(in, out, err, ed) + # get-num(in, out, err, ed) # . . push args 50/push-EAX/ed 68/push _test-error-stream/imm32 @@ -366,7 +366,7 @@ test-get-num-reads-single-digit: 68/push _test-buffered-file/imm32 # . . call e8/call get-num/disp32 - ## registers except ESP may be clobbered at this point + # registers except ESP may be clobbered at this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP # check-ints-equal(*_test-output-stream.data, '3') @@ -379,7 +379,7 @@ test-get-num-reads-single-digit: 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 + # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5d/pop-to-EBP c3/return @@ -389,15 +389,15 @@ test-get-num-aborts-on-non-digit-in-Look: # This test uses exit-descriptors. Use EBP for setting up local variables. 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - clear all streams - # clear-stream(_test-stream) + # setup + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -406,22 +406,22 @@ test-get-num-aborts-on-non-digit-in-Look: 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) + # . 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-error-stream) + # . clear-stream(_test-error-stream) # . . push args 68/push _test-error-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 'in' - # write(_test-stream, "3") + # initialize 'in' + # . write(_test-stream, "3") # . . push args 68/push "3"/imm32 68/push _test-stream/imm32 @@ -429,13 +429,11 @@ test-get-num-aborts-on-non-digit-in-Look: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # - initialize exit-descriptor 'ed' - # allocate on stack - # var ed/EAX : (address exit-descriptor) + # initialize exit-descriptor 'ed' for the call to 'get-num' below + # . var ed/EAX : (address exit-descriptor) 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # size the exit-descriptor for the call to get-num below - # tailor-exit-descriptor(ed, 16) + # . tailor-exit-descriptor(ed, 16) # . . push args 68/push 0x10/imm32/nbytes-of-args-for-get-num 50/push-EAX/ed @@ -443,8 +441,8 @@ test-get-num-aborts-on-non-digit-in-Look: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # - don't initialize Look - # - get-num(in, out, err, ed) + # *don't* prime the pump + # get-num(in, out, err, ed) # . . push args 50/push-EAX/ed 68/push _test-error-stream/imm32 @@ -455,18 +453,18 @@ test-get-num-aborts-on-non-digit-in-Look: # registers except ESP may be clobbered at this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # - check that get-num tried to call exit(1) - # check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 + # check that get-num tried to call exit(1) + # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 # . . push args 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 68/push 2/imm32 - # . push ed->value + # . . push ed->value ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) # . . 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 + # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5d/pop-to-EBP c3/return @@ -516,7 +514,7 @@ expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (ad ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call e8/call stop/disp32 - ## should never get past this point + # should never get past this point # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP @@ -557,13 +555,13 @@ error: # ed : (address exit-descriptor), f : fd or (address stream), s : (addre ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call e8/call stop/disp32 - ## should never get past this point + # should never get past this point # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return -# read a byte from 'f', and store it in 'Look' +# read a byte from 'f', and save it in 'Look' get-char: # f : (address buffered-file) -> <void> # . prolog 55/push-EBP diff --git a/subx/apps/crenshaw2-1b.subx b/subx/apps/crenshaw2-1b.subx index 49436370..54264d56 100644 --- a/subx/apps/crenshaw2-1b.subx +++ b/subx/apps/crenshaw2-1b.subx @@ -33,10 +33,11 @@ # main: run tests if necessary, call 'compile' if not # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # if (argc > 1) + # - if argc > 1 and argv[1] == "test" then return run_tests() + # . argc > 1 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 - # and if (argv[1] == "test") + # . argv[1] == "test" # . . push args 68/push "test"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) @@ -44,22 +45,23 @@ e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check result + # . check result 3d/compare-EAX 1/imm32 75/jump-if-not-equal $run-main/disp8 - # then return run-tests() + # . run-tests() e8/call run-tests/disp32 #? e8/call test-get-num-reads-multiple-digits/disp32 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX eb/jump $main:end/disp8 $run-main: - # allocate space for an exit-descriptor - # var ed/EAX : (address exit-descriptor) + # - otherwise read a program from stdin and emit its translation to stdout + # var ed/EAX : exit-descriptor 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # clear ed->target (so we really exit) + # configure ed to really exit() + # . ed->target = 0 c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # compile(Stdin, 1/stdout, 2/stderr, ed) + # return compile(Stdin, 1/stdout, 2/stderr, ed) # . . push args 50/push-EAX/ed 68/push 2/imm32/stderr @@ -69,7 +71,7 @@ $run-main: e8/call compile/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # syscall(exit, 0) + # . syscall(exit, 0) bb/copy-to-EBX 0/imm32 $main:end: b8/copy-to-EAX 1/imm32/exit @@ -83,7 +85,8 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd # . save registers 50/push-EAX 51/push-ECX - # Look = get-char(in) + # prime the pump + # . Look = get-char(in) # . . push args ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call @@ -98,14 +101,15 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX . . # copy ESP to ECX # num->length = 7 c7/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) - # clear-stream(num) + # read a digit from 'in' into 'num' + # . clear-stream(num) # . . 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 - # get-num(in, num, err, ed) + # . get-num(in, num, err, ed) # . . push args ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x14/disp8 . # push *(EBP+20) ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) @@ -115,15 +119,12 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call get-num/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # EAX = write(_test-stream, "Ab") - # . . push args - 68/push "Ab"/imm32 - 68/push _test-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 = write(out, "bb/copy-to-EBX ") + # render 'num' into the following template on 'out': + # bb/copy-to-EBX _num_ + # b8/copy-to-EAX 1/imm32/exit + # cd/syscall 0x80/imm8 + # + # . EAX = write(out, "bb/copy-to-EBX ") # . . push args 68/push "bb/copy-to-EBX "/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -131,7 +132,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream(out, num) + # . write-stream(out, num) # . . push args 51/push-ECX/num ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -139,7 +140,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write-stream/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(out, Newline) + # . write(out, Newline) # . . push args 68/push Newline/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -147,7 +148,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, "b8/copy-to-EAX 1/imm32/exit") + # . write(out, "b8/copy-to-EAX 1/imm32/exit") # . . push args 68/push "b8/copy-to-EAX 1/imm32/exit"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -155,7 +156,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, Newline) + # . write(out, Newline) # . . push args 68/push Newline/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -163,7 +164,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, "cd/syscall 0x80/imm8") + # . write(out, "cd/syscall 0x80/imm8") # . . push args 68/push "cd/syscall 0x80/imm8"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -171,7 +172,7 @@ compile: # in : fd or (address stream), out : fd or (address stream), err : fd e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = write(out, Newline) + # . write(out, Newline) # . . push args 68/push Newline/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) @@ -219,17 +220,18 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # EAX = is-digit?(Look) + # - if is-digit?(Look) expected(ed, err, "integer") + # . EAX = is-digit?(Look) # . . push args ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look # . . call e8/call is-digit?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # if EAX == 0 error + # . if EAX == 0 3d/compare-EAX 0/imm32 75/jump-if-not-equal $get-num:main/disp8 - # expected(ed, err, "integer") + # . expected(ed, err, "integer") # . . push args 68/push "integer"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) @@ -239,6 +241,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP $get-num:main: + # - otherwise read a digit # . save registers 50/push-EAX 51/push-ECX @@ -259,7 +262,7 @@ $get-num:loop: # if out->write >= out->length error 3b/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare EDX with ECX 7d/jump-if-lesser $get-num:loop-stage2/disp8 - # error(ed, err, "get-num: too many digits in number") # TODO: show full number + # . error(ed, err, msg) # TODO: show full number # . . push args 68/push "get-num: too many digits in number"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x10/disp8 . # push *(EBP+16) @@ -282,14 +285,15 @@ $get-num:loop-stage2: e8/call get-char/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # EAX = is-digit?(Look) + # if is-digit?(Look) loop + # . EAX = is-digit?(Look) # . . push args ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Look/disp32 . # push *Look # . . call e8/call is-digit?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # if EAX loop + # . if EAX loop 3d/compare-EAX 0/imm32 0f 85/jump-if-not-equal $get-num:loop/disp32 $get-num:loop-end: @@ -308,19 +312,19 @@ $get-num:loop-end: c3/return test-get-num-reads-single-digit: - ## check that get-num returns first character if it's a digit + # - check that get-num returns first character if it's a digit # This test uses exit-descriptors. Use EBP for setting up local variables. 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - ## clear all streams - # clear-stream(_test-stream) + # clear all streams + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -329,22 +333,22 @@ test-get-num-reads-single-digit: 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) + # . 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-error-stream) + # . clear-stream(_test-error-stream) # . . push args 68/push _test-error-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 'in' - # write(_test-stream, "3") + # initialize 'in' + # . write(_test-stream, "3") # . . push args 68/push "3"/imm32 68/push _test-stream/imm32 @@ -352,13 +356,11 @@ test-get-num-reads-single-digit: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## initialize exit-descriptor 'ed' - # allocate on stack - # var ed/EAX : (address exit-descriptor) + # initialize exit-descriptor 'ed' for the call to 'get-num' below + # . var ed/EAX : exit-descriptor 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # size the exit-descriptor for the call to get-num below - # tailor-exit-descriptor(ed, 16) + # . tailor-exit-descriptor(ed, 16) # . . push args 68/push 0x10/imm32/nbytes-of-args-for-get-num 50/push-EAX/ed @@ -366,15 +368,15 @@ test-get-num-reads-single-digit: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## prime the pump - # get-char(_test-buffered-file) + # prime the pump + # . get-char(_test-buffered-file) # . . push args 68/push _test-buffered-file/imm32 # . . call e8/call get-char/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - ## get-num(in, out, err, ed) + # get-num(in, out, err, ed) # . . push args 50/push-EAX/ed 68/push _test-error-stream/imm32 @@ -382,7 +384,7 @@ test-get-num-reads-single-digit: 68/push _test-buffered-file/imm32 # . . call e8/call get-num/disp32 - ## registers except ESP may be clobbered at this point + # registers except ESP may be clobbered at this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP # check-ints-equal(*_test-output-stream.data, '3') @@ -395,25 +397,25 @@ test-get-num-reads-single-digit: 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 + # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5d/pop-to-EBP c3/return test-get-num-aborts-on-non-digit-in-Look: - ## check that get-num returns first character if it's a digit + # - check that get-num returns first character if it's a digit # This test uses exit-descriptors. Use EBP for setting up local variables. 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - ## clear all streams - # clear-stream(_test-stream) + # clear all streams + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -422,22 +424,22 @@ test-get-num-aborts-on-non-digit-in-Look: 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) + # . 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-error-stream) + # . clear-stream(_test-error-stream) # . . push args 68/push _test-error-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 'in' - # write(_test-stream, "3") + # initialize 'in' + # . write(_test-stream, "3") # . . push args 68/push "3"/imm32 68/push _test-stream/imm32 @@ -445,13 +447,11 @@ test-get-num-aborts-on-non-digit-in-Look: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## initialize exit-descriptor 'ed' - # allocate on stack - # var ed/EAX : (address exit-descriptor) + # initialize exit-descriptor 'ed' for the call to 'get-num' below + # . var ed/EAX : (address exit-descriptor) 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # size the exit-descriptor for the call to get-num below - # tailor-exit-descriptor(ed, 16) + # . tailor-exit-descriptor(ed, 16) # . . push args 68/push 0x10/imm32/nbytes-of-args-for-get-num 50/push-EAX/ed @@ -459,8 +459,8 @@ test-get-num-aborts-on-non-digit-in-Look: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## don't initialize Look - ## get-num(in, out, err, ed) + # *don't* prime the pump + # get-num(in, out, err, ed) # . . push args 50/push-EAX/ed 68/push _test-error-stream/imm32 @@ -468,39 +468,39 @@ test-get-num-aborts-on-non-digit-in-Look: 68/push _test-buffered-file/imm32 # . . call e8/call get-num/disp32 - ## registers except ESP may be clobbered at this point + # registers except ESP may be clobbered at this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - ## check that get-num tried to call exit(1) - # check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 + # check that get-num tried to call exit(1) + # . check-ints-equal(ed->value, 2, msg) # i.e. stop was called with value 1 # . . push args 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 68/push 2/imm32 - # push ed->value + # . . push ed->value ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # push *(EAX+4) # . . 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 + # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5d/pop-to-EBP c3/return test-get-num-reads-multiple-digits: - ## check that get-num returns all initial digits until it encounters a non-digit + # - check that get-num returns all initial digits until it encounters a non-digit # This test uses exit-descriptors. Use EBP for setting up local variables. 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - ## clear all streams - # clear-stream(_test-stream) + # clear all streams + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -509,22 +509,22 @@ test-get-num-reads-multiple-digits: 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) + # . 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-error-stream) + # . clear-stream(_test-error-stream) # . . push args 68/push _test-error-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 'in' - # write(_test-stream, "3456 x") + # initialize 'in' + # . write(_test-stream, "3456 x") # . . push args 68/push "3456"/imm32 68/push _test-stream/imm32 @@ -532,13 +532,11 @@ test-get-num-reads-multiple-digits: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## initialize exit-descriptor 'ed' - # allocate on stack - # var ed/EAX : (address exit-descriptor) + # initialize exit-descriptor 'ed' for the call to 'get-num' below + # . var ed/EAX : (address exit-descriptor) 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # size the exit-descriptor for the call to get-num below - # tailor-exit-descriptor(ed, 16) + # . tailor-exit-descriptor(ed, 16) # . . push args 68/push 0x10/imm32/nbytes-of-args-for-get-num 50/push-EAX/ed @@ -546,15 +544,15 @@ test-get-num-reads-multiple-digits: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## prime the pump - # get-char(_test-buffered-file) + # prime the pump + # . get-char(_test-buffered-file) # . . push args 68/push _test-buffered-file/imm32 # . . call e8/call get-char/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - ## get-num(in, out, err, ed) + # get-num(in, out, err, ed) # . . push args 50/push-EAX/ed 68/push _test-error-stream/imm32 @@ -562,7 +560,7 @@ test-get-num-reads-multiple-digits: 68/push _test-buffered-file/imm32 # . . call e8/call get-num/disp32 - ## registers except ESP may be clobbered at this point + # registers except ESP may be clobbered at this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP # check-ints-equal(*_test-output-stream.data, '3456') @@ -575,25 +573,25 @@ test-get-num-reads-multiple-digits: 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 + # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5d/pop-to-EBP c3/return test-get-num-reads-multiple-digits-followed-by-nondigit: - ## check that get-num returns all initial digits until it encounters a non-digit + # - check that get-num returns all initial digits until it encounters a non-digit # This test uses exit-descriptors. Use EBP for setting up local variables. 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - ## clear all streams - # clear-stream(_test-stream) + # clear all streams + # . clear-stream(_test-stream) # . . push args 68/push _test-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-buffered-file+4) + # . clear-stream(_test-buffered-file+4) # . . push args b8/copy-to-EAX _test-buffered-file/imm32 05/add-to-EAX 4/imm32 @@ -602,22 +600,22 @@ test-get-num-reads-multiple-digits-followed-by-nondigit: 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) + # . 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-error-stream) + # . clear-stream(_test-error-stream) # . . push args 68/push _test-error-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 'in' - # write(_test-stream, "3456 x") + # initialize 'in' + # . write(_test-stream, "3456 x") # . . push args 68/push "3456 x"/imm32 68/push _test-stream/imm32 @@ -625,13 +623,11 @@ test-get-num-reads-multiple-digits-followed-by-nondigit: e8/call write/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## initialize exit-descriptor 'ed' - # allocate on stack - # var ed/EAX : (address exit-descriptor) + # initialize exit-descriptor 'ed' for the call to 'get-num' below + # . var ed/EAX : (address exit-descriptor) 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP 8d/copy-address 0/mod/indirect 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX . . # copy ESP to EAX - # size the exit-descriptor for the call to get-num below - # tailor-exit-descriptor(ed, 16) + # . tailor-exit-descriptor(ed, 16) # . . push args 68/push 0x10/imm32/nbytes-of-args-for-get-num 50/push-EAX/ed @@ -639,15 +635,15 @@ test-get-num-reads-multiple-digits-followed-by-nondigit: e8/call tailor-exit-descriptor/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - ## prime the pump - # get-char(_test-buffered-file) + # prime the pump + # . get-char(_test-buffered-file) # . . push args 68/push _test-buffered-file/imm32 # . . call e8/call get-char/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - ## get-num(in, out, err, ed) + # get-num(in, out, err, ed) # . . push args 50/push-EAX/ed 68/push _test-error-stream/imm32 @@ -655,7 +651,7 @@ test-get-num-reads-multiple-digits-followed-by-nondigit: 68/push _test-buffered-file/imm32 # . . call e8/call get-num/disp32 - ## registers except ESP may be clobbered at this point + # registers except ESP may be clobbered at this point # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP # check-ints-equal(*_test-output-stream.data, '3456') @@ -668,7 +664,7 @@ test-get-num-reads-multiple-digits-followed-by-nondigit: 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 + # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP 5d/pop-to-EBP c3/return @@ -718,7 +714,7 @@ expected: # ed : (address exit-descriptor), f : fd or (address stream), s : (ad ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call e8/call stop/disp32 - ## should never get past this point + # should never get past this point # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP @@ -759,13 +755,13 @@ error: # ed : (address exit-descriptor), f : fd or (address stream), s : (addre ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 . # push *(EBP+8) # . . call e8/call stop/disp32 - ## should never get past this point + # should never get past this point # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return -# read a byte from 'f', and store it in 'Look' +# read a byte from 'f', and save it in 'Look' get-char: # f : (address buffered-file) -> <void> # . prolog 55/push-EBP diff --git a/subx/apps/factorial.subx b/subx/apps/factorial.subx index f7675962..1e6d7bfb 100644 --- a/subx/apps/factorial.subx +++ b/subx/apps/factorial.subx @@ -22,10 +22,11 @@ # main: # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # if (argc > 1) + # - if argc > 1 and argv[1] == "test" then return run_tests() + # . argc > 1 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 - # and if (argv[1] == "test") + # . argv[1] == "test" # . . push args 68/push "test"/imm32 ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) @@ -33,14 +34,14 @@ e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check result + # . check result 3d/compare-EAX 1/imm32 75/jump-if-not-equal $run-main/disp8 - # then return run-tests() + # . run-tests() e8/call run-tests/disp32 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Num-test-failures/disp32 # copy *Num-test-failures to EAX eb/jump $main:end/disp8 # where EAX will get copied to EBX - # else EAX = factorial(5) + # - otherwise return factorial(5) $run-main: # . . push args 68/push 5/imm32 @@ -49,20 +50,19 @@ $run-main: # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP $main:end: - # exit(EAX) + # syscall(exit, EAX) 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 -# factorial(n) -factorial: +factorial: # n : int -> int/EAX # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP 53/push-EBX - # initialize EAX to 1 (base case) + # EAX = 1 (base case) b8/copy-to-EAX 1/imm32 - # if (n <= 1) jump exit + # if (n <= 1) return 81 7/subop/compare 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 8/disp8 1/imm32 # compare *(EBP+8) 7e/jump-if-<= $factorial:end/disp8 # EBX = n-1 diff --git a/subx/examples/ex1.subx b/subx/examples/ex1.subx index 3371cd75..89d331ab 100644 --- a/subx/examples/ex1.subx +++ b/subx/examples/ex1.subx @@ -1,4 +1,4 @@ -## first program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html +# First program: same as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html # Just return 42. # # To run (from the subx directory): @@ -10,8 +10,8 @@ == code +# syscall(exit, 42) bb/copy-to-EBX 2a/imm32 # 42 in hex -# exit(EBX) b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 diff --git a/subx/examples/ex10.subx b/subx/examples/ex10.subx index 936edb08..69e7c2ec 100644 --- a/subx/examples/ex10.subx +++ b/subx/examples/ex10.subx @@ -1,4 +1,4 @@ -## String comparison: return 1 iff the two args passed in at the commandline are equal. +# String comparison: return 1 iff the two args passed in at the commandline are equal. # # To run (from the subx directory): # $ subx translate examples/ex10.subx -o examples/ex10 @@ -20,15 +20,14 @@ # ... # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . . call argv-equal(argv[1], argv[2]) - # push argv[2] + # argv-equal(argv[1], argv[2]) + # . . push argv[2] ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - # push argv[1] + # . . push argv[1] ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) # . . call e8/call argv-equal/disp32 - # exit(EAX) -$exit: + # syscall(exit, EAX) 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 diff --git a/subx/examples/ex11.subx b/subx/examples/ex11.subx index 253b91ab..e2628c39 100644 --- a/subx/examples/ex11.subx +++ b/subx/examples/ex11.subx @@ -1,4 +1,4 @@ -## Null-terminated vs length-prefixed ascii strings. +# Null-terminated vs length-prefixed ascii strings. # # By default we create strings with a 4-byte length prefix rather than a null suffix. # However we still need null-prefixed strings when interacting with the Linux @@ -108,7 +108,7 @@ $kernel-string-equal:end: 5d/pop-to-EBP c3/return -## tests +# - tests test-compare-null-kernel-string-with-empty-array: # EAX = kernel-string-equal(Null-kernel-string, "") @@ -119,7 +119,7 @@ test-compare-null-kernel-string-with-empty-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 1, msg) + # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-compare-null-kernel-string-with-empty-array"/imm32 68/push 1/imm32/true @@ -139,7 +139,7 @@ test-compare-null-kernel-string-with-non-empty-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0, msg) + # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-compare-null-kernel-string-with-non-empty-array"/imm32 68/push 0/imm32/false @@ -159,7 +159,7 @@ test-compare-kernel-string-with-equal-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 1, msg) + # check-ints-equal(EAX, 1, msg) # . . push args 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push 1/imm32/true @@ -179,7 +179,7 @@ test-compare-kernel-string-with-inequal-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0, msg) + # check-ints-equal(EAX, 0, msg) # . . push args 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push 0/imm32/false @@ -199,7 +199,7 @@ test-compare-kernel-string-with-empty-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0) + # check-ints-equal(EAX, 0) # . . push args 68/push "F - test-compare-kernel-string-with-equal-array"/imm32 68/push 0/imm32/false @@ -219,7 +219,7 @@ test-compare-kernel-string-with-shorter-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0) + # check-ints-equal(EAX, 0) # . . push args 68/push "F - test-compare-kernel-string-with-shorter-array"/imm32 68/push 0/imm32/false @@ -239,7 +239,7 @@ test-compare-kernel-string-with-longer-array: e8/call kernel-string-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . call check-ints-equal(EAX, 0) + # check-ints-equal(EAX, 0) # . . push args 68/push "F - test-compare-kernel-string-with-longer-array"/imm32 68/push 0/imm32/false @@ -250,7 +250,7 @@ test-compare-kernel-string-with-longer-array: 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP c3/return -## helpers +# - helpers # print msg to stderr if a != b, otherwise print "." check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean @@ -263,19 +263,19 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean # load args into EAX, EBX and ECX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 0/r32/EAX 0x8/disp8 . # copy *(EBP+8) to EAX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # if EAX == b/EBX + # if EAX == b/EBX print('.') and return 39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX and EBX 75/jump-if-unequal $check-ints-equal:else/disp8 - # print('.') + # . write-stderr('.') # . . push args 68/push "."/imm32 # . . call e8/call write-stderr/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # return + # . return eb/jump $check-ints-equal:end/disp8 - # else: + # otherwise print(msg) $check-ints-equal:else: # copy msg into ECX 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX @@ -312,15 +312,15 @@ write-stderr: # s : (address array byte) -> <void> 52/push-EDX 53/push-EBX # syscall(write, 2/stderr, (data) s+4, (size) *s) - # fd = 2 (stderr) + # . . fd = 2 (stderr) bb/copy-to-EBX 2/imm32 - # x = s+4 + # . . x = s+4 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX - # size = *s + # . . size = *s 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 2/r32/EDX 8/disp8 . # copy *(EBP+8) to EDX 8b/copy 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX - # syscall + # . . syscall b8/copy-to-EAX 4/imm32/write cd/syscall 0x80/imm8 # . restore registers @@ -328,7 +328,7 @@ write-stderr: # s : (address array byte) -> <void> 5a/pop-to-EDX 59/pop-to-ECX 58/pop-to-EAX - # end + # . end 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return diff --git a/subx/examples/ex12.subx b/subx/examples/ex12.subx index 565c8d50..3b101379 100644 --- a/subx/examples/ex12.subx +++ b/subx/examples/ex12.subx @@ -1,4 +1,4 @@ -## example showing mmap syscall +# Example showing mmap syscall. # Create a new segment using mmap, save the address, write to it. # # To run (from the subx directory): @@ -16,7 +16,7 @@ b8/copy-to-EAX 0x5a/imm32/mmap cd/syscall 0x80/imm8 - # store to *EAX + # write to *EAX to check that we have access to the newly-allocated segment c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0x34/imm32 # copy to *EAX # syscall(exit, EAX) diff --git a/subx/examples/ex2.subx b/subx/examples/ex2.subx index f7be9b65..80833894 100644 --- a/subx/examples/ex2.subx +++ b/subx/examples/ex2.subx @@ -1,4 +1,4 @@ -## add 1 and 1, and return the result in the exit code +# Add 1 and 1, and return the result in the exit code. # # To run (from the subx directory): # $ subx translate examples/ex2.subx -o examples/ex2 @@ -9,9 +9,11 @@ == code +# EBX = 1 bb/copy-to-EBX 1/imm32 +# increment EBX 43/inc-EBX -# exit(EBX) +# syscall(exit, EBX) b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 diff --git a/subx/examples/ex3.subx b/subx/examples/ex3.subx index b6e21698..a89ec99c 100644 --- a/subx/examples/ex3.subx +++ b/subx/examples/ex3.subx @@ -1,4 +1,4 @@ -## add the first 10 numbers, and return the result in the exit code +# Add the first 10 numbers, and return the result in the exit code. # # To run (from the subx directory): # $ subx translate examples/ex3.subx -o examples/ex3 @@ -29,7 +29,7 @@ $loop: eb/jump $loop/disp8 $exit: - # exit(EBX) + # syscall(exit, EBX) b8/copy-to-EAX 1/imm32 cd/syscall 0x80/imm8 diff --git a/subx/examples/ex4.subx b/subx/examples/ex4.subx index 2fd15cd7..964d4a60 100644 --- a/subx/examples/ex4.subx +++ b/subx/examples/ex4.subx @@ -1,4 +1,4 @@ -## read a character from stdin, save it to a global, write it to stdout +# Read a character from stdin, save it to a global, write it to stdout. # # To run (from the subx directory): # $ subx translate examples/ex4.subx -o examples/ex4 @@ -7,24 +7,24 @@ == code # syscall(read, stdin, X, 1) - # fd = 0 (stdin) +# . fd = 0 (stdin) bb/copy-to-EBX 0/imm32 - # initialize X (location to write result to) +# . data = X (location to write result to) b9/copy-to-ECX X/imm32 - # size = 1 character +# . size = 1 character ba/copy-to-EDX 1/imm32 - # syscall +# . syscall b8/copy-to-EAX 3/imm32/read cd/syscall 0x80/imm8 # syscall(write, stdout, X, 1) - # fd = 1 (stdout) +# . fd = 1 (stdout) bb/copy-to-EBX 1/imm32 - # initialize X (location to read from) +# . initialize X (location to read from) b9/copy-to-ECX X/imm32 - # size = 1 character +# . size = 1 character ba/copy-to-EDX 1/imm32 - # syscall +# . syscall b8/copy-to-EAX 4/imm32/write cd/syscall 0x80/imm8 diff --git a/subx/examples/ex5.subx b/subx/examples/ex5.subx index 136c177b..5028568c 100644 --- a/subx/examples/ex5.subx +++ b/subx/examples/ex5.subx @@ -1,4 +1,4 @@ -## read a character from stdin, save it to a local on the stack, write it to stdout +# Read a character from stdin, save it to a local on the stack, write it to stdout. # # To run (from the subx directory): # $ subx translate examples/ex5.subx -o examples/ex5 @@ -14,24 +14,24 @@ 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # subtract from ESP # syscall(read, stdin, x, 1) - # fd = 0 (stdin) + # . fd = 0 (stdin) bb/copy-to-EBX 0/imm32 - # initialize x (location to write result to) + # . data = x (location to write result to) 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none 1/r32/ECX 4/disp8 . # copy ESP+4 to ECX - # size = 1 character + # . size = 1 character ba/copy-to-EDX 1/imm32 - # syscall + # . syscall b8/copy-to-EAX 3/imm32/read cd/syscall 0x80/imm8 # syscall(write, stdout, x, 1) - # fd = 1 (stdout) + # . fd = 1 (stdout) bb/copy-to-EBX 1/imm32 - # initialize x (location to read from) + # . data = x (location to read from) 8d/copy-address 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none 1/r32/ECX 4/disp8 . # copy ESP+4 to ECX - # size = 1 character + # . size = 1 character ba/copy-to-EDX 1/imm32 - # syscall + # . syscall b8/copy-to-EAX 4/imm32/write cd/syscall 0x80/imm8 diff --git a/subx/examples/ex6.subx b/subx/examples/ex6.subx index fc266a3a..8b3637f6 100644 --- a/subx/examples/ex6.subx +++ b/subx/examples/ex6.subx @@ -1,4 +1,4 @@ -## print out a (global variable) string to stdout +# Print out a (global variable) string to stdout. # # To run (from the subx directory): # $ subx translate examples/ex6.subx -o examples/ex6 @@ -10,14 +10,14 @@ # . 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 - # syscall(write, stdout, X, size) - # fd = 1 (stdout) + # syscall(write, stdout, X, Size) + # . fd = 1 (stdout) bb/copy-to-EBX 1/imm32 - # initialize X (location to write result to) + # . initialize X (location to write result to) b9/copy-to-ECX X/imm32 - # initialize size - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/EDX Size/disp32 . # copy *size to EDX - # syscall + # . initialize Size + 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 2/r32/EDX Size/disp32 . # copy *Size to EDX + # . syscall b8/copy-to-EAX 4/imm32/write cd/syscall 0x80/imm8 diff --git a/subx/examples/ex7.subx b/subx/examples/ex7.subx index 3650817d..e28ff89b 100644 --- a/subx/examples/ex7.subx +++ b/subx/examples/ex7.subx @@ -1,4 +1,5 @@ -## example showing file syscalls +# Example showing file syscalls. +# # Create a file, open it for writing, write a character to it, close it, open # it for reading, read a character from it, close it, delete it, and return # the character read. @@ -32,20 +33,20 @@ 89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX # syscall(write, Stream, "a", 1) - # load stream + # . load stream bb/copy-to-EBX Stream/imm32 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX - # + # . b9/copy-to-ECX A/imm32 ba/copy-to-EDX 1/imm32/size b8/copy-to-EAX 4/imm32/write cd/syscall 0x80/imm8 # syscall(close, Stream) - # load stream + # . load stream bb/copy-to-EBX Stream/imm32 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX - # + # . b8/copy-to-EAX 6/imm32/close cd/syscall 0x80/imm8 @@ -55,22 +56,22 @@ ba/copy-to-EDX 0x180/imm32/fixed-perms b8/copy-to-EAX 5/imm32/open cd/syscall 0x80/imm8 - # save Stream + # . save Stream bb/copy-to-EBX Stream/imm32 89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX # syscall(read, Stream, B, 1) - # load stream + # . load stream bb/copy-to-EBX Stream/imm32 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX - # + # . b9/copy-to-ECX B/imm32 ba/copy-to-EDX 1/imm32/size b8/copy-to-EAX 3/imm32/read cd/syscall 0x80/imm8 # syscall(close, Stream) - # load stream + # . load stream bb/copy-to-EBX Stream/imm32 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX # @@ -83,7 +84,7 @@ cd/syscall 0x80/imm8 # syscall(exit, b) - # load b + # . load b bb/copy-to-EBX B/imm32 8b/copy 0/mod/indirect 3/rm32/EBX . . . 3/r32/EBX . . # copy *EBX to EBX # diff --git a/subx/examples/ex8.subx b/subx/examples/ex8.subx index 410dfe08..6ec9eb3c 100644 --- a/subx/examples/ex8.subx +++ b/subx/examples/ex8.subx @@ -1,4 +1,4 @@ -## Example reading commandline arguments: compute length of first arg. +# Example reading commandline arguments: compute length of first arg. # # To run (from the subx directory): # $ subx translate examples/ex8.subx -o examples/ex8 @@ -21,7 +21,7 @@ # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . . call ascii-length(argv[1]) + # EAX = ascii-length(argv[1]) # . . push args ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) # . . call @@ -34,13 +34,13 @@ b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -ascii-length: # (s) - # initialize s (EDX) +ascii-length: # s : (address array byte) -> n/EAX + # EDX = s 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 2/r32/EDX 4/disp8 . # copy *(ESP+4) to EDX - # var result = 0 (EAX) + # var result/EAX = 0 b8/copy-to-EAX 0/imm32 $ascii-length-loop: - # var c = *s (ECX) + # var c/ECX = *s 8a/copy 0/mod/* 2/rm32/EDX . . . 1/r32/ECX . . # copy byte at *EDX to lower byte of ECX # if c == '\0' break 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX @@ -52,7 +52,7 @@ $ascii-length-loop: # loop eb/jump $ascii-length-loop/disp8 $ascii-length-ret: - # return (result in EAX) + # return EAX c3/return # . . vim:nowrap:textwidth=0 diff --git a/subx/examples/ex9.subx b/subx/examples/ex9.subx index 964151a2..ed4e6761 100644 --- a/subx/examples/ex9.subx +++ b/subx/examples/ex9.subx @@ -1,4 +1,5 @@ -## Example showing arg order on the stack. +# Example showing arg order on the stack. +# # Show difference between ascii codes of first letter of first arg and first # letter of second arg. # @@ -23,16 +24,16 @@ # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . . call ascii-difference(argv[1], argv[2]) - # push argv[2] + # ascii-difference(argv[1], argv[2]) + # . . push argv[2] ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12) - # push argv[1] + # . . push argv[1] ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0x8/disp8 . # push *(EBP+8) # . . call e8/call ascii-difference/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # exit(EAX) + # syscall(exit, EAX) 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 |