This commit is contained in:
Kartik Agaram 2019-02-14 16:24:20 -08:00
parent 1ab48a69cc
commit 1639687ba0
31 changed files with 254 additions and 210 deletions

View File

@ -32,7 +32,7 @@ check-ints-equal: # (a : int, b : int, msg : (address array byte)) -> <void>
# 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, '.')

View File

@ -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

View File

@ -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

View File

@ -42,7 +42,7 @@ clear-stream: # f : (address stream) -> <void>
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

View File

@ -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:

View File

@ -32,7 +32,7 @@ write: # f : fd or (address stream), s : (address array byte) -> <void>
# . 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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -18,8 +18,8 @@ write-buffered: # f : (address buffered-file), msg : (address array byte) -> <v
# pseudocode:
# in = msg->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

View File

@ -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

View File

@ -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

View File

@ -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:

Binary file not shown.

View File

@ -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) -> <void>
# 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

Binary file not shown.

View File

@ -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) -> <void>
# 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

Binary file not shown.

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -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) -> <void>
# 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:

Binary file not shown.

View File

@ -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) -> <void
# repeatedly
# clear-stream(line)
# EAX = read-line(in, line)
# if EAX == EOF break
# if (EAX == EOF) break
# convert-instruction(line, out)
# flush(out)
#
@ -119,7 +119,7 @@ $convert:loop:
e8/call convert-instruction/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
# if EAX == 0xffffffff break
# if (EAX == 0xffffffff) break
3d/compare-with-EAX 0xffffffff/imm32
74/jump-if-equal $convert:break/disp8
# convert-instruction(line, out)
@ -200,10 +200,10 @@ $convert:end:
convert-instruction: # line : (address stream byte), out : (address buffered-file) -> <void>
# 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)

View File

@ -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

Binary file not shown.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)