diff --git a/subx/051test.subx b/subx/051test.subx index 08d1d6f6..2ae907c1 100644 --- a/subx/051test.subx +++ b/subx/051test.subx @@ -32,7 +32,7 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> # load first 2 args into EAX and EBX 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # if EAX == EBX success + # 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, '.') diff --git a/subx/052kernel-string-equal.subx b/subx/052kernel-string-equal.subx index b61c3303..840b4460 100644 --- a/subx/052kernel-string-equal.subx +++ b/subx/052kernel-string-equal.subx @@ -30,19 +30,26 @@ # reason for the name: the only place we should have null-terminated ascii strings is from commandline args kernel-string-equal?: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean # pseudocode: - # initialize n = b->length - # initialize s1 = s - # initialize s2 = b->data + # n = benchmark->length + # s1 = s + # s2 = benchmark->data # i = 0 - # for (i = 0; i < n; ++n) + # while (i < n) # c1 = *s1 # c2 = *s2 - # if c1 == 0 - # return false - # if c1 != c2 - # return false + # if (c1 == 0) return false + # if (c1 != c2) return false + # ++s1, ++s2, ++i # return *s1 == 0 # + # registers: + # i: ECX + # n: EDX + # s1: EDI + # s2: ESI + # c1: EAX + # c2: EBX + # # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP @@ -52,24 +59,25 @@ kernel-string-equal?: # s : null-terminated ascii string, benchmark : length-pr 53/push-EBX 56/push-ESI 57/push-EDI - # initialize s into EDI + # s1/EDI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI - # initialize benchmark length n into EDX + # n/EDX = benchmark->length 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX 8b/copy 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX - # initialize benchmark data into ESI + # s2/ESI = benchmark->data 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI - # initialize loop counter i into ECX + # i/ECX = c1/EAX = c2/EBX = 0 b9/copy-to-ECX 0/imm32/exit - # while (i/ECX < n/EDX) -$kernel-string-equal?:loop: - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 74/jump-if-equal $kernel-string-equal?:break/disp8 - # c1/EAX, c2/EBX = *s, *benchmark b8/copy-to-EAX 0/imm32 - 8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX bb/copy-to-EBX 0/imm32 +$kernel-string-equal?:loop: + # if (i >= n) break + 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX + 7d/jump-if-greater-or-equal $kernel-string-equal?:break/disp8 + # c1 = *s1 + 8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX + # c2 = *s2 8a/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy byte at *ESI to lower byte of EBX # if (c1 == 0) return false 3d/compare-EAX 0/imm32 @@ -77,22 +85,21 @@ $kernel-string-equal?:loop: # if (c1 != c2) return false 39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX 75/jump-if-not-equal $kernel-string-equal?:false/disp8 - # ++s1, ++s2, ++i + # ++i 41/inc-ECX - 46/inc-ESI + # ++s1 47/inc-EDI - # end while + # ++s2 + 46/inc-ESI eb/jump $kernel-string-equal?:loop/disp8 $kernel-string-equal?:break: - # if (*s/EDI == 0) return true - b8/copy-to-EAX 0/imm32 + # return *s1 == 0 8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX 3d/compare-EAX 0/imm32 75/jump-if-not-equal $kernel-string-equal?:false/disp8 $kernel-string-equal?:true: b8/copy-to-EAX 1/imm32 eb/jump $kernel-string-equal?:end/disp8 - # return false $kernel-string-equal?:false: b8/copy-to-EAX 0/imm32 $kernel-string-equal?:end: @@ -253,6 +260,7 @@ test-compare-kernel-string-with-longer-array: Null-kernel-string: 00/null + _test-Abc-kernel-string: 41/A 62/b 63/c 00/null diff --git a/subx/054string-equal.subx b/subx/054string-equal.subx index fdfca84e..f69c0c0f 100644 --- a/subx/054string-equal.subx +++ b/subx/054string-equal.subx @@ -13,18 +13,27 @@ b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 -string-equal?: # s : string, benchmark : string -> EAX : boolean +string-equal?: # s : (address string), benchmark : (address string) -> EAX : boolean # pseudocode: - # if s->length != b->length return false - # for i = 0; i < s->length; ++i - # if s[i] != b[i] return false + # lens = s->length + # if (lens != benchmark->length) return false + # i = 0 + # currs = s->data + # currb = benchmark->data + # while (i < s->length) + # c1 = *currs + # c2 = *currb + # if (c1 != c2) return false + # ++i, ++currs, ++currb # return true + # # registers: # i: ECX - # s->length: EDX - # b->length: EBX - # b[i]: EBX - # s[i]: EAX + # lens: EDX + # currs: EAX + # currb: EBX + # c1: ESI + # c2: EDI # # . prolog 55/push-EBP @@ -34,17 +43,16 @@ string-equal?: # s : string, benchmark : string -> EAX : boolean 52/push-EDX 53/push-EBX 56/push-ESI - # var s/EAX : (address array byte) + # EAX = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX - # var benchmark/EBX : (address array byte) + # EBX = benchmark 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # if s->length != b->length return false - # EDX = s->length + # lens/EDX = s->length 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - # compare s->length and b->length +$string-equal?:lengths: + # if (lens != benchmark->length) return false 39/compare 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # compare *EBX with EDX 75/jump-if-not-equal $string-equal?:false/disp8 -$string-equal?:lengths: # var i/ECX : int = 0 b9/copy-to-ECX 0/imm32 # EBX = &b[i] @@ -52,7 +60,7 @@ $string-equal?:lengths: # EAX = &s[i] 40/inc-EAX $string-equal?:loop: - # if i >= s->length return true + # if (i >= lens) return true 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX 7d/jump-if-greater-or-equal $string-equal?:true/disp8 # if b[i] != s[i] return false @@ -63,16 +71,15 @@ $string-equal?:loop: 75/jump-if-not-equal $string-equal?:false/disp8 # ++i 41/inc-ECX + # ++c1 40/inc-EAX + # ++c2 43/inc-EBX - # loop eb/jump $string-equal?:loop/disp8 $string-equal?:true: - # return true b8/copy-to-EAX 1/imm32 eb/jump $string-equal?:end/disp8 $string-equal?:false: - # return false b8/copy-to-EAX 0/imm32 $string-equal?:end: # . restore registers diff --git a/subx/055stream.subx b/subx/055stream.subx index 0d196311..f5d24876 100644 --- a/subx/055stream.subx +++ b/subx/055stream.subx @@ -42,7 +42,7 @@ clear-stream: # f : (address stream) -> 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX # while (true) $clear-stream:loop: - # if EAX >= ECX break + # if (EAX >= ECX) break 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX 7d/jump-if-greater-or-equal $clear-stream:end/disp8 # *EAX = 0 @@ -76,3 +76,5 @@ $rewind-stream:end: 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return + +# . . vim:nowrap:textwidth=0 diff --git a/subx/056trace.subx b/subx/056trace.subx index 96e5646b..aa73bbdd 100644 --- a/subx/056trace.subx +++ b/subx/056trace.subx @@ -99,7 +99,7 @@ trace: # t : (address trace-stream), line : string e8/call _append-3/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # if EAX == 0 return + # if (EAX == 0) return 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EDX 74/jump-if-equal $trace:end/disp8 # t->write += EAX @@ -153,9 +153,8 @@ clear-trace-stream: # t : (address trace-stream) c7 0/subop/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4) # EAX = t->data 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX - # while (true) $clear-trace-stream:loop: - # if EAX >= ECX break + # if (EAX >= ECX) break 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX 7d/jump-if-greater-or-equal $clear-trace-stream:end/disp8 # *EAX = 0 @@ -328,18 +327,20 @@ _append-4: # out : address, outend : address, in : address, inend : address -> # ECX = inend 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX $_append-4:loop: - # if ESI/in >= ECX/inend break + # if (in >= inend) break 39/compare 3/mod/direct 6/rm32/ESI . . . 1/r32/ECX . . # compare ESI with ECX 7d/jump-if-greater-or-equal $_append-4:end/disp8 - # if EDI/out >= EDX/outend break (for now silently ignore filled up buffer) + # if (out >= outend) break # for now silently ignore filled up buffer 39/compare 3/mod/direct 7/rm32/EDI . . . 2/r32/EDX . . # compare EDI with EDX 7d/jump-if-greater-or-equal $_append-4:end/disp8 - # copy one byte from ESI/in to EDI/out + # *out = *in 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 3/r32/BL . . # copy byte at *ESI to BL 88/copy-byte 0/mod/indirect 7/rm32/EDI . . . 3/r32/BL . . # copy byte at BL to *EDI - # updates + # ++num_bytes_appended 40/increment-EAX + # ++in 46/increment-ESI + # ++out 47/increment-EDI eb/jump $_append-4:loop/disp8 $_append-4:end: diff --git a/subx/057write.subx b/subx/057write.subx index 3f2f8a11..c1712996 100644 --- a/subx/057write.subx +++ b/subx/057write.subx @@ -32,7 +32,7 @@ write: # f : fd or (address stream), s : (address array byte) -> # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # if (f < 0x08000000) _write(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor + # if (f < 0x08000000) _write(f, s) and return # f can't be a user-mode address, so treat it as a kernel file descriptor 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x08000000/imm32 # compare *(EBP+8) 7d/jump-if-greater-or-equal $write:fake/disp8 # . . push args diff --git a/subx/058stream-equal.subx b/subx/058stream-equal.subx index e4c1962e..203e5415 100644 --- a/subx/058stream-equal.subx +++ b/subx/058stream-equal.subx @@ -32,7 +32,7 @@ stream-data-equal?: # f : (address stream), s : (address string) -> EAX : boole 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 0xc/imm32 # add to ESI # EDI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI - # if (f->write != s->length) return false; + # if (f->write != s->length) return false 39/compare 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # compare *EDI and EAX 75/jump-if-not-equal $stream-data-equal?:false/disp8 # currs/EDI = s->data @@ -235,25 +235,25 @@ next-stream-line-equal?: # f : (address stream), s : (address string) -> EAX : # pseudocode: # currf = f->read # bound: f->write # currs = 0 # bound : s->length - # while true - # if currf >= f->write + # while true: + # if (currf >= f->write) # return currs >= s->length - # if f[currf] == '\n' + # if (f[currf] == '\n') # ++currf # return currs >= s->length - # if currs >= s->length return false # the current line of f still has data to match - # if f[currf] != s[currs] return false + # if (currs >= s->length) return false # the current line of f still has data to match + # if (f[currf] != s[currs]) return false # ++currf # ++currs # # collapsing the two branches that can return true: # currf = f->read # bound: f->write # currs = 0 # bound : s->length - # while true - # if currf >= f->write break - # if f[currf] == '\n' break - # if currs >= s->length return false # the current line of f still has data to match - # if f[currf] != s[currs] return false + # while true: + # if (currf >= f->write) break + # if (f[currf] == '\n') break + # if (currs >= s->length) return false # the current line of f still has data to match + # if (f[currf] != s[currs]) return false # ++currf # ++currs # ++currf # skip '\n' @@ -261,12 +261,12 @@ next-stream-line-equal?: # f : (address stream), s : (address string) -> EAX : # Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream) # # registers: - # f : ESI - # s : EDI - # currf : ECX - # currs : EDX - # f[currf] : EAX - # s[currs] : EBX + # f: ESI + # s: EDI + # currf: ECX + # currs: EDX + # f[currf]: EAX + # s[currs]: EBX # # . prolog 55/push-EBP @@ -312,7 +312,7 @@ $next-stream-line-equal?:loop: $next-stream-line-equal?:break: # ++currf 41/increment-ECX - # if currs >= s->length return true + # if (currs >= s->length) return true 3b/compare 0/mod/indirect 7/rm32/EDI . . . 2/r32/EDX . . # compare EDX with *EDI 7c/jump-if-lesser $next-stream-line-equal?:false/disp8 $next-stream-line-equal?:true: diff --git a/subx/059stop.subx b/subx/059stop.subx index f9e67f9e..4478dab3 100644 --- a/subx/059stop.subx +++ b/subx/059stop.subx @@ -100,19 +100,20 @@ stop: # ed : (address exit-descriptor), value : int # no prolog; one way or another, we're going to clobber registers # EAX = ed 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # copy *(ESP+4) to EAX - # exit(value) if ed->target == 0 + # if (ed->target == 0) really exit 81 7/subop/compare 0/mod/indirect 0/rm32/EAX . . . . . 0/imm32 # compare *EAX 75/jump-if-not-equal $stop:fake/disp8 - # syscall(exit, value) + # . syscall(exit, value) 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 3/r32/EBX 8/disp8 . # copy *(ESP+8) to EBX b8/copy-to-EAX 1/imm32/exit cd/syscall 0x80/imm8 $stop:fake: + # otherwise: # ed->value = value+1 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 8/disp8 . # copy *(ESP+8) to ECX 41/inc-ECX 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4) - # non-local jump to ed->target + # perform a non-local jump to ed->target 8b/copy 0/mod/indirect 0/rm32/EAX . . . 4/r32/ESP . . # copy *EAX to ESP $stop:end: c3/return # doesn't return to caller diff --git a/subx/061read-byte.subx b/subx/061read-byte.subx index c62b035e..a915d436 100644 --- a/subx/061read-byte.subx +++ b/subx/061read-byte.subx @@ -74,7 +74,7 @@ read-byte: # f : (address buffered-file) -> byte-or-eof/EAX e8/call read/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if EAX = 0 return 0xffffffff + # if (EAX == 0) return 0xffffffff 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX 75/jump-if-not-equal $read-byte:from-stream/disp8 b8/copy-to-EAX 0xffffffff/imm32 diff --git a/subx/065hex.subx b/subx/065hex.subx index 6ba2ef7e..9096680b 100644 --- a/subx/065hex.subx +++ b/subx/065hex.subx @@ -71,7 +71,7 @@ $is-hex-int?:loop: e8/call is-hex-digit?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # if EAX == false return false + # if (EAX == false) return false 3d/compare-with-EAX 0/imm32 74/jump-if-equal $is-hex-int?:end/disp8 # ++curr @@ -738,7 +738,7 @@ test-hex-above-f: from-hex-char: # in/EAX : byte -> out/EAX : num # no error checking; accepts argument in EAX - # if EAX <= '9' return EAX - '0' + # if (EAX <= '9') return EAX - '0' 3d/compare-EAX 0x39/imm32/9 7f/jump-if-greater $from-hex-char:else/disp8 2d/subtract-from-EAX 0x30/imm32/0 @@ -750,7 +750,7 @@ $from-hex-char:else: to-hex-char: # in/EAX : nibble -> out/EAX : byte # no error checking; accepts argument in EAX - # if EAX <= 9 return EAX + '0' + # if (EAX <= 9) return EAX + '0' 3d/compare-EAX 0x9/imm32/9 7f/jump-if-greater $to-hex-char:else/disp8 05/add-to-EAX 0x30/imm32/0 diff --git a/subx/067write-buffered.subx b/subx/067write-buffered.subx index 3825a7f3..50ec7988 100644 --- a/subx/067write-buffered.subx +++ b/subx/067write-buffered.subx @@ -18,8 +18,8 @@ write-buffered: # f : (address buffered-file), msg : (address array byte) -> data # inend = &msg->data[msg->length] - # while in < inend - # if f->write >= f->length + # while (in < inend) + # if (f->write >= f->length) # flush(f) # clear-stream(f) # f->data[f->write] = *in diff --git a/subx/069allocate.subx b/subx/069allocate.subx index 37b01d21..1d9e043a 100644 --- a/subx/069allocate.subx +++ b/subx/069allocate.subx @@ -164,7 +164,7 @@ allocate-region: # ad : (address allocation-descriptor), n : int -> new-ad : (a e8/call allocate/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if EAX == 0 abort + # if (EAX == 0) abort 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX 74/jump-if-equal $allocate-region:abort/disp8 # earmark 8 bytes at the start for a new allocation descriptor diff --git a/subx/071read-line.subx b/subx/071read-line.subx index 3efa96e0..61513aa9 100644 --- a/subx/071read-line.subx +++ b/subx/071read-line.subx @@ -23,7 +23,7 @@ read-line: # f : (address buffered-file), s : (address stream byte) -> eof?/EAX # s->data[s->write] = AL # ++f->read # ++s->write - # if AL == '\n' break + # if (AL == '\n') break # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP @@ -65,8 +65,8 @@ $read-line:loop: e8/call read/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if f->write == 0 return true - # . if EAX == 0 return true + # if (f->write == 0) return true + # . if (EAX == 0) return true 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX 75/jump-if-not-equal $read-line:from-stream/disp8 b8/copy-to-EAX 0xffffffff/imm32 @@ -81,7 +81,7 @@ $read-line:from-stream: 41/increment-ECX # ++s->write 42/increment-EDX - # if AL == '\n' return false + # if (AL == '\n') return false 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX 75/jump-if-not-equal $read-line:loop/disp8 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX diff --git a/subx/072slice.subx b/subx/072slice.subx index fa244219..20a39aa4 100644 --- a/subx/072slice.subx +++ b/subx/072slice.subx @@ -21,7 +21,7 @@ slice-empty?: # s : (address slice) -> EAX : boolean 51/push-ECX # ECX = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - # if s->start == s->end return true + # if (s->start == s->end) return true # . EAX = s->start 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX # . compare EAX with s->end @@ -96,6 +96,24 @@ test-slice-empty-false: c3/return slice-equal?: # s : (address slice), p : (address string) -> EAX : boolean + # pseudocode: + # currs = s->start + # maxs = s->end + # if (maxs - currs != p->length) return false + # currp = p->data + # while (currs < maxs) + # if (*currs != *currp) return false + # ++currs + # ++currp + # return true + # + # registers: + # EAX : *currs + # ECX : *currp + # EDX : currs + # EBX : currp + # ESI : maxs + # # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP @@ -106,37 +124,37 @@ slice-equal?: # s : (address slice), p : (address string) -> EAX : boolean 56/push-ESI # ESI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # curr/EDX = s->start + # currs/EDX = s->start 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - # max/ESI = s->end + # maxs/ESI = s->end 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI # EBX = p 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # EAX = s->end - s->start + # EAX = maxs - currs 89/copy 3/mod/direct 0/rm32/EAX . . . 6/r32/ESI . . # copy ESI to EAX 29/subtract 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # subtract EDX from EAX - # if (EAX != p->length) return false; + # if (EAX != p->length) return false 39/compare 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # compare *EBX and EAX 75/jump-if-not-equal $slice-equal?:false/disp8 - # skip p->length + # currp/EBX = p->data 81 0/subop/add 3/mod/direct 3/rm32/EBX . . . . . 4/imm32 # add to EBX # EAX = ECX = 0 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX $slice-equal?:loop: - # if (curr >= max) return true + # if (currs >= maxs) return true 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX and ESI 7d/jump-if-greater-or-equal $slice-equal?:true/disp8 - # AL = *p + # AL = *currp 8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at *EBX to AL - # CL = *curr + # CL = *currs 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL # if (EAX != ECX) return false 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX and ECX 75/jump-if-not-equal $slice-equal?:false/disp8 - # ++p + # ++currp 43/increment-EBX - # ++curr + # ++currs 42/increment-EDX eb/jump $slice-equal?:loop/disp8 $slice-equal?:false: diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index 3391c314..73a34441 100755 Binary files a/subx/apps/crenshaw2-1 and b/subx/apps/crenshaw2-1 differ diff --git a/subx/apps/crenshaw2-1.subx b/subx/apps/crenshaw2-1.subx index 7c279955..3fe51fd7 100644 --- a/subx/apps/crenshaw2-1.subx +++ b/subx/apps/crenshaw2-1.subx @@ -37,7 +37,7 @@ # 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 and argv[1] == "test" then return run_tests() + # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 @@ -199,8 +199,8 @@ $compile:end: # 'in' into it on exit. get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> # pseudocode: - # if !is-digit?(Look) expected(ed, err, "integer") - # if out->write >= out->length + # if (!is-digit?(Look)) expected(ed, err, "integer") + # if (out->write >= out->length) # write(err, "Error: too many digits in number\n") # stop(ed, 1) # out->data[out->write] = LSB(Look) @@ -221,7 +221,7 @@ 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 - # - if is-digit?(Look) expected(ed, err, "integer") + # - 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 @@ -229,7 +229,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a 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 + # . if (EAX == 0) 3d/compare-EAX 0/imm32 75/jump-if-not-equal $get-num:main/disp8 # . expected(ed, err, "integer") @@ -259,7 +259,7 @@ $get-num:main: 8b/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy *EDI to ECX # EDX = out->length 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX - # if out->write >= out->length error + # if (out->write >= out->length) error 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX 7d/jump-if-lesser $get-num:stage2/disp8 # . error(ed, err, msg) # TODO: show full number @@ -559,10 +559,10 @@ is-digit?: # c : int -> EAX : boolean 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # EAX = false b8/copy-to-EAX 0/imm32 - # if c < '0' return false + # if (c < '0') return false 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x30/imm32 # compare *(EBP+8) 7c/jump-if-lesser $is-digit?:end/disp8 - # if c > '9' return false + # if (c > '9') return false 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x39/imm32 # compare *(EBP+8) 7f/jump-if-greater $is-digit?:end/disp8 # otherwise return true diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b index 24c37657..80c9e4f0 100755 Binary files a/subx/apps/crenshaw2-1b and b/subx/apps/crenshaw2-1b differ diff --git a/subx/apps/crenshaw2-1b.subx b/subx/apps/crenshaw2-1b.subx index 0df86a68..4fc2680b 100644 --- a/subx/apps/crenshaw2-1b.subx +++ b/subx/apps/crenshaw2-1b.subx @@ -37,7 +37,7 @@ # 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 and argv[1] == "test" then return run_tests() + # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 @@ -200,15 +200,15 @@ $compile:end: # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit. get-num: # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> # pseudocode: - # if !is-digit?(Look) expected(ed, err, "integer") + # if (!is-digit?(Look)) expected(ed, err, "integer") # do - # if out->write >= out->length + # if (out->write >= out->length) # write(err, "Error: too many digits in number\n") # stop(ed, 1) # out->data[out->write] = LSB(Look) # ++out->write # Look = get-char(in) - # while is-digit?(Look) + # while (is-digit?(Look)) # This is complicated because I don't want to hard-code the error strategy in # a general helper like write-byte. Maybe I should just create a local helper. # @@ -226,7 +226,7 @@ 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 - # - if is-digit?(Look) expected(ed, err, "integer") + # - 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 @@ -234,7 +234,7 @@ get-num: # in : (address buffered-file), out : (address stream), err : fd or (a 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 + # . if (EAX == 0) 3d/compare-EAX 0/imm32 75/jump-if-not-equal $get-num:main/disp8 # . expected(ed, err, "integer") @@ -265,7 +265,7 @@ $get-num:main: # EDX = out->length 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 2/r32/EDX 8/disp8 . # copy *(EDI+8) to EDX $get-num:loop: - # if out->write >= out->length error + # if (out->write >= out->length) error 39/compare 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # compare EDX with ECX 7d/jump-if-lesser $get-num:loop-stage2/disp8 # . error(ed, err, msg) # TODO: show full number @@ -291,7 +291,7 @@ $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 - # if is-digit?(Look) loop + # 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 @@ -299,7 +299,7 @@ $get-num:loop-stage2: 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 != 0) loop 3d/compare-EAX 0/imm32 0f 85/jump-if-not-equal $get-num:loop/disp32 $get-num:loop-end: @@ -756,10 +756,10 @@ is-digit?: # c : int -> EAX : boolean 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP # EAX = false b8/copy-to-EAX 0/imm32 - # if c < '0' return false + # if (c < '0') return false 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x30/imm32 # compare *(EBP+8) 7c/jump-if-lesser $is-digit?:end/disp8 - # if c > '9' return false + # if (c > '9') return false 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 0x39/imm32 # compare *(EBP+8) 7f/jump-if-greater $is-digit?:end/disp8 # otherwise return true diff --git a/subx/apps/factorial b/subx/apps/factorial index 01112b12..83a5e14f 100755 Binary files a/subx/apps/factorial and b/subx/apps/factorial differ diff --git a/subx/apps/factorial.subx b/subx/apps/factorial.subx index a239d419..912285e2 100644 --- a/subx/apps/factorial.subx +++ b/subx/apps/factorial.subx @@ -21,7 +21,7 @@ # main: # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - if argc > 1 and argv[1] == "test" then return run_tests() + # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 diff --git a/subx/apps/handle b/subx/apps/handle index 164fbd1a..d79ed98e 100755 Binary files a/subx/apps/handle and b/subx/apps/handle differ diff --git a/subx/apps/hex b/subx/apps/hex index 5edc02a3..a9500830 100755 Binary files a/subx/apps/hex and b/subx/apps/hex differ diff --git a/subx/apps/hex.subx b/subx/apps/hex.subx index 2c1606ed..d841fd8b 100644 --- a/subx/apps/hex.subx +++ b/subx/apps/hex.subx @@ -25,7 +25,7 @@ # main: run tests if necessary, convert stdin if not # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - if argc > 1 and argv[1] == "test" then return run_tests() + # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 @@ -73,7 +73,7 @@ convert: # in : (address buffered-file), out : (address buffered-file), err : ( # pseudocode: # repeatedly # EAX = convert-next-octet(in, err, ed) - # if EAX == 0xffffffff break # eof + # if (EAX == 0xffffffff) break # eof # write-byte(out, AL) # flush(out) # @@ -92,7 +92,7 @@ $convert:loop: e8/call convert-next-octet/disp32 # . . discard first 2 args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # if EAX == 0xffffffff break + # if (EAX == 0xffffffff) break 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xffffffff/imm32 # compare EAX 74/jump-if-equal $convert:loop-end/disp8 # write-byte(out, AL) @@ -489,10 +489,10 @@ scan-next-byte: # in : (address buffered-file), err : (address buffered-file), # pseudocode: # repeatedly # EAX = read-byte(in) - # if EAX == 0xffffffff return EAX - # if is-hex-digit?(EAX) return EAX - # if EAX == ' ' or '\t' or '\n' continue - # if EAX == '#' skip-until-newline(in) + # if (EAX == 0xffffffff) return EAX + # if (is-hex-digit?(EAX)) return EAX + # if (EAX == ' ' or '\t' or '\n') continue + # if (EAX == '#') skip-until-newline(in) # else error-byte(ed, err, "invalid byte: " EAX) # # . prolog @@ -510,7 +510,7 @@ $scan-next-byte:loop: # if (EAX == 0xffffffff) return EAX 3d/compare-with-EAX 0xffffffff/imm32 74/jump-if-equal $scan-next-byte:end/disp8 - # if is-hex-digit?(EAX) return EAX + # if (is-hex-digit?(EAX)) return EAX # . save EAX for now 50/push-EAX # . is-hex-digit?(EAX) @@ -527,17 +527,17 @@ $scan-next-byte:loop: # . check whether to return 75/jump-if-not-equal $scan-next-byte:end/disp8 $scan-next-byte:check1: - # if EAX == ' ' continue + # if (EAX == ' ') continue 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0x20/imm32 # compare EAX 74/jump-if-equal $scan-next-byte:loop/disp8 - # if EAX == '\t' continue + # if (EAX == '\t') continue 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0x9/imm32 # compare EAX 74/jump-if-equal $scan-next-byte:loop/disp8 - # if EAX == '\n' continue + # if (EAX == '\n') continue 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX 74/jump-if-equal $scan-next-byte:loop/disp8 $scan-next-byte:check2: - # if EAX == '#' skip-until-newline(in) + # if (EAX == '#') skip-until-newline(in) 3d/compare-with-EAX 0x23/imm32 75/jump-if-not-equal $scan-next-byte:check3/disp8 # . skip-until-newline(in) @@ -1413,8 +1413,8 @@ skip-until-newline: # in : (address buffered-file) -> # push EAX # repeatedly: # EAX = read-byte(in) - # if EAX == 0xffffffff break - # if EAX == 0x0a break + # if (EAX == 0xffffffff) break + # if (EAX == 0x0a) break # pop EAX # . prolog 55/push-EBP @@ -1429,10 +1429,10 @@ $skip-until-newline:loop: e8/call read-byte/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if EAX == 0xffffffff break + # . if (EAX == 0xffffffff) break 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xffffffff/imm32 # compare EAX 74/jump-if-equal $skip-until-newline:end/disp8 - # . if EAX != 0xa/newline loop + # . if (EAX != 0xa/newline) loop 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0xa/imm32 # compare EAX 75/jump-if-not-equal $skip-until-newline:loop/disp8 $skip-until-newline:end: diff --git a/subx/apps/pack b/subx/apps/pack index 075dc69b..e55b170a 100755 Binary files a/subx/apps/pack and b/subx/apps/pack differ diff --git a/subx/apps/pack.subx b/subx/apps/pack.subx index 07988399..a27d2613 100644 --- a/subx/apps/pack.subx +++ b/subx/apps/pack.subx @@ -28,7 +28,7 @@ # main: run tests if necessary, convert stdin if not # . prolog 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - if argc > 1 and argv[1] == "test" then return run_tests() + # - if argc > 1 and argv[1] == "test", then return run_tests() # . argc > 1 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP 7e/jump-if-lesser-or-equal $run-main/disp8 @@ -88,7 +88,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> # pseudocode: # word-slice = next-word - # if *word-slice->start == '#' + # if (*word-slice->start == '#') # write-stream-buffered(out, line) # return - # if starts-with(word-slice, '==') + # if (starts-with(word-slice, '==')) # write-stream-buffered(out, line) # return # @@ -599,7 +599,7 @@ next-word: # line : (address stream byte), out : (address slice) 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX 89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI - # if line->data[line->read] == '#': out->end = &line->data[line->write]), skip rest of stream and return + # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return # . EAX = line->data[line->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 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL @@ -770,8 +770,8 @@ has-metadata?: # word : (address slice), s : (address string) -> EAX : boolean # curr = twig->end # while true: # twig = next-token-from-slice(curr, word->end, '/') - # if twig.empty() break - # if slice-equal?(twig, s) return true + # if (twig.empty()) break + # if (slice-equal?(twig, s)) return true # curr = twig->end # return false # . prolog @@ -813,7 +813,7 @@ $has-metadata?:loop: e8/call next-token-from-slice/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # if slice-empty?(twig) return false + # if (slice-empty?(twig)) return false # . EAX = slice-empty?(twig) # . . push args 57/push-EDI @@ -824,7 +824,7 @@ $has-metadata?:loop: # . if (EAX != 0) return false 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX 75/compare-if-not-equal $has-metadata?:false/disp8 - # if slice-equal?(twig, s) return true + # if (slice-equal?(twig, s)) return true # . EAX = slice-equal?(twig, s) # . . push args ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) @@ -1058,7 +1058,7 @@ emit: # out : (address buffered-file), word : (address slice), width : int e8/call next-token-from-slice/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # if !is-hex-int?(name) write-slice(out, word) and return + # if (!is-hex-int?(name)) write-slice(out, word) and return # . is-hex-int?(name) # . . push args 57/push-EDI @@ -1066,7 +1066,7 @@ emit: # out : (address buffered-file), word : (address slice), width : int e8/call is-hex-int?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if EAX == 0 + # . if (EAX == 0) 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX 75/jump-if-not-equal $emit:hex-int/disp8 # . write-slice(out, word) diff --git a/subx/examples/ex10.subx b/subx/examples/ex10.subx index 3ae1eae7..07b5b4bb 100644 --- a/subx/examples/ex10.subx +++ b/subx/examples/ex10.subx @@ -38,7 +38,6 @@ argv-equal: # (s1, s2) : null-terminated ascii strings -> EAX : boolean # initialize s1 (ECX) and s2 (EDX) 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 1/r32/ECX 4/disp8 . # copy *(ESP+4) to ECX 8b/copy 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 2/r32/EDX 8/disp8 . # copy *(ESP+8) to EDX - # while (true) $argv-equal:loop: # c1/EAX, c2/EBX = *s1, *s2 b8/copy-to-EAX 0/imm32 diff --git a/subx/examples/ex11 b/subx/examples/ex11 index cdabbf0a..0ffafb6f 100755 Binary files a/subx/examples/ex11 and b/subx/examples/ex11 differ diff --git a/subx/examples/ex11.subx b/subx/examples/ex11.subx index 7fb83eb6..49e0c753 100644 --- a/subx/examples/ex11.subx +++ b/subx/examples/ex11.subx @@ -28,7 +28,28 @@ # compare a null-terminated ascii string with a more idiomatic length-prefixed byte array # reason for the name: the only place we should have null-terminated ascii strings is from commandline args -kernel-string-equal: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean +kernel-string-equal?: # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean + # pseudocode: + # n = benchmark->length + # s1 = s + # s2 = benchmark->data + # i = 0 + # while (i < n) + # c1 = *s1 + # c2 = *s2 + # if (c1 == 0) return false + # if (c1 != c2) return false + # ++s1, ++s2, ++i + # return *s1 == 0 + # + # registers: + # i: ECX + # n: EDX + # s1: EDI + # s2: ESI + # c1: EAX + # c2: EBX + # # . prolog 55/push-EBP 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP @@ -38,72 +59,57 @@ kernel-string-equal: # s : null-terminated ascii string, benchmark : length-pre 53/push-EBX 56/push-ESI 57/push-EDI - - # pseudocode: - # initialize n = b->length - # initialize s1 = s - # initialize s2 = b->data - # i = 0 - # for (i = 0; i < n; ++n) - # c1 = *s1 - # c2 = *s2 - # if c1 == 0 - # return false - # if c1 != c2 - # return false - # return *s1 == 0 - # initialize s into EDI + # s1/EDI = s 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI - # initialize benchmark length n into EDX + # n/EDX = benchmark->length 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX 8b/copy 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX - # initialize benchmark data into ESI + # s2/ESI = benchmark->data 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 4/imm32 # add to ESI - # initialize loop counter i into ECX + # i/ECX = c1/EAX = c2/EBX = 0 b9/copy-to-ECX 0/imm32/exit - # while (i/ECX < n/EDX) -$kernel-string-equal:loop: - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 74/jump-if-equal $kernel-string-equal:break/disp8 - # c1/EAX, c2/EBX = *s, *benchmark b8/copy-to-EAX 0/imm32 - 8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX bb/copy-to-EBX 0/imm32 +$kernel-string-equal?:loop: + # if (i >= n) break + 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX + 7d/jump-if-greater-or-equal $kernel-string-equal?:break/disp8 + # c1 = *s1 + 8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX + # c2 = *s2 8a/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy byte at *ESI to lower byte of EBX # if (c1 == 0) return false 3d/compare-EAX 0/imm32 - 74/jump-if-equal $kernel-string-equal:false/disp8 + 74/jump-if-equal $kernel-string-equal?:false/disp8 # if (c1 != c2) return false 39/compare 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # compare EAX with EBX - 75/jump-if-not-equal $kernel-string-equal:false/disp8 - # ++s1, ++s2, ++i + 75/jump-if-not-equal $kernel-string-equal?:false/disp8 + # ++i 41/inc-ECX - 46/inc-ESI + # ++s1 47/inc-EDI - # end while - eb/jump $kernel-string-equal:loop/disp8 -$kernel-string-equal:break: - # if (*s/EDI == 0) return true - b8/copy-to-EAX 0/imm32 + # ++s2 + 46/inc-ESI + eb/jump $kernel-string-equal?:loop/disp8 +$kernel-string-equal?:break: + # return *s1 == 0 8a/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy byte at *EDI to lower byte of EAX - 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX - 75/jump-if-not-equal $kernel-string-equal:false/disp8 + 3d/compare-EAX 0/imm32 + 75/jump-if-not-equal $kernel-string-equal?:false/disp8 +$kernel-string-equal?:true: b8/copy-to-EAX 1/imm32 -$kernel-string-equal:true: - eb/jump $kernel-string-equal:end/disp8 - # return false -$kernel-string-equal:false: + eb/jump $kernel-string-equal?:end/disp8 +$kernel-string-equal?:false: b8/copy-to-EAX 0/imm32 - -$kernel-string-equal:end: +$kernel-string-equal?:end: # . restore registers 5f/pop-to-EDI 5e/pop-to-ESI 5b/pop-to-EBX 5a/pop-to-EDX 59/pop-to-ECX - # end + # . epilog 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP 5d/pop-to-EBP c3/return @@ -111,12 +117,12 @@ $kernel-string-equal:end: # - tests test-compare-null-kernel-string-with-empty-array: - # EAX = kernel-string-equal(Null-kernel-string, "") + # EAX = kernel-string-equal?(Null-kernel-string, "") # . . push args 68/push ""/imm32 68/push Null-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 1, msg) @@ -131,12 +137,12 @@ test-compare-null-kernel-string-with-empty-array: c3/return test-compare-null-kernel-string-with-non-empty-array: - # EAX = kernel-string-equal(Null-kernel-string, "Abc") + # EAX = kernel-string-equal?(Null-kernel-string, "Abc") # . . push args 68/push "Abc"/imm32 68/push Null-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 0, msg) @@ -151,12 +157,12 @@ test-compare-null-kernel-string-with-non-empty-array: c3/return test-compare-kernel-string-with-equal-array: - # EAX = kernel-string-equal(Abc-kernel-string, "Abc") + # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Abc") # . . push args 68/push "Abc"/imm32 - 68/push Abc-kernel-string/imm32 + 68/push _test-Abc-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 1, msg) @@ -171,12 +177,12 @@ test-compare-kernel-string-with-equal-array: c3/return test-compare-kernel-string-with-inequal-array: - # EAX = kernel-string-equal(Abc-kernel-string, "Adc") + # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Adc") # . . push args 68/push "Adc"/imm32 - 68/push Abc-kernel-string/imm32 + 68/push _test-Abc-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 0, msg) @@ -191,12 +197,12 @@ test-compare-kernel-string-with-inequal-array: c3/return test-compare-kernel-string-with-empty-array: - # EAX = kernel-string-equal(Abc-kernel-string, "") + # EAX = kernel-string-equal?(_test-Abc-kernel-string, "") # . . push args 68/push ""/imm32 - 68/push Abc-kernel-string/imm32 + 68/push _test-Abc-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 0, msg) @@ -211,12 +217,12 @@ test-compare-kernel-string-with-empty-array: c3/return test-compare-kernel-string-with-shorter-array: - # EAX = kernel-string-equal(Abc-kernel-string, "Ab") + # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Ab") # . . push args 68/push "Ab"/imm32 - 68/push Abc-kernel-string/imm32 + 68/push _test-Abc-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 0, msg) @@ -231,12 +237,12 @@ test-compare-kernel-string-with-shorter-array: c3/return test-compare-kernel-string-with-longer-array: - # EAX = kernel-string-equal(Abc-kernel-string, "Abcd") + # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Abcd") # . . push args 68/push "Abcd"/imm32 - 68/push Abc-kernel-string/imm32 + 68/push _test-Abc-kernel-string/imm32 # . . call - e8/call kernel-string-equal/disp32 + e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # check-ints-equal(EAX, 0, msg) @@ -263,7 +269,7 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> boolean # load args into EAX, EBX and ECX 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # if EAX == b/EBX print('.') and return + # 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 # . write-stderr('.') @@ -344,7 +350,8 @@ Newline: # for kernel-string-equal tests Null-kernel-string: 00/null -Abc-kernel-string: + +_test-Abc-kernel-string: 41/A 62/b 63/c 00/null # . . vim:nowrap:textwidth=0 diff --git a/subx/examples/ex3.subx b/subx/examples/ex3.subx index ceeaef00..6a4f7b01 100644 --- a/subx/examples/ex3.subx +++ b/subx/examples/ex3.subx @@ -18,7 +18,7 @@ b9/copy-to-ECX 1/imm32 $loop: - # while (counter <= 10) + # if (counter > 10) break 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0xa/imm32 # compare ECX 7f/jump-if-greater $exit/disp8 # result += counter diff --git a/subx/examples/ex8.subx b/subx/examples/ex8.subx index 0ae75760..f45813ec 100644 --- a/subx/examples/ex8.subx +++ b/subx/examples/ex8.subx @@ -42,7 +42,7 @@ ascii-length: # s : (address array byte) -> n/EAX $ascii-length-loop: # 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 + # if (c == '\0') break 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX 74/jump-if-equal $ascii-length-ret/disp8 # ++s diff --git a/subx/opcodes b/subx/opcodes index 3437f30a..0eb0792b 100644 --- a/subx/opcodes +++ b/subx/opcodes @@ -74,6 +74,7 @@ Opcodes currently supported by SubX: bf: copy imm32 to EDI (mov) c1: shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr) c3: return from most recent unfinished call (ret) + c6: copy imm8 to r8/m8-at-r32 (mov) c7: copy imm32 to rm32 (mov) cd: software interrupt (int) d3: shift rm32 by CL bits depending on subop (sal/sar/shl/shr)