diff options
Diffstat (limited to 'subx/apps')
-rw-r--r-- | subx/apps/Readme.md | 2 | ||||
-rwxr-xr-x | subx/apps/assort | bin | 34384 -> 0 bytes | |||
-rw-r--r-- | subx/apps/assort.subx | 911 | ||||
-rwxr-xr-x | subx/apps/crenshaw2-1 | bin | 24788 -> 0 bytes | |||
-rw-r--r-- | subx/apps/crenshaw2-1.subx | 585 | ||||
-rwxr-xr-x | subx/apps/crenshaw2-1b | bin | 25347 -> 0 bytes | |||
-rw-r--r-- | subx/apps/crenshaw2-1b.subx | 785 | ||||
-rwxr-xr-x | subx/apps/dquotes | bin | 40940 -> 0 bytes | |||
-rw-r--r-- | subx/apps/dquotes.subx | 2757 | ||||
-rwxr-xr-x | subx/apps/factorial | bin | 23704 -> 0 bytes | |||
-rw-r--r-- | subx/apps/factorial.subx | 117 | ||||
-rwxr-xr-x | subx/apps/handle | bin | 24558 -> 0 bytes | |||
-rw-r--r-- | subx/apps/handle.subx | 412 | ||||
-rwxr-xr-x | subx/apps/hex | bin | 36939 -> 0 bytes | |||
-rw-r--r-- | subx/apps/hex.subx | 1515 | ||||
-rwxr-xr-x | subx/apps/pack | bin | 47070 -> 0 bytes | |||
-rw-r--r-- | subx/apps/pack.subx | 5986 | ||||
-rw-r--r-- | subx/apps/subx-common.subx | 3118 | ||||
-rwxr-xr-x | subx/apps/survey | bin | 43605 -> 0 bytes | |||
-rw-r--r-- | subx/apps/survey.subx | 4787 | ||||
-rwxr-xr-x | subx/apps/tests | bin | 33196 -> 0 bytes | |||
-rw-r--r-- | subx/apps/tests.subx | 279 |
22 files changed, 0 insertions, 21254 deletions
diff --git a/subx/apps/Readme.md b/subx/apps/Readme.md deleted file mode 100644 index b76c5a8b..00000000 --- a/subx/apps/Readme.md +++ /dev/null @@ -1,2 +0,0 @@ -Larger programs than in the subx/examples/ subdirectory, combining the -techniques demonstrated there. diff --git a/subx/apps/assort b/subx/apps/assort deleted file mode 100755 index 70d7aaf3..00000000 --- a/subx/apps/assort +++ /dev/null Binary files differdiff --git a/subx/apps/assort.subx b/subx/apps/assort.subx deleted file mode 100644 index 801e52d0..00000000 --- a/subx/apps/assort.subx +++ /dev/null @@ -1,911 +0,0 @@ -# Read a series of segments from stdin and concatenate segments with the same -# name on stdout. -# -# Segments are emitted in order of first encounter. -# -# Drop lines that are all comments. They could get misleading after assortment -# because we don't know if they refer to the line above or the line below. -# -# To run (from the subx/ directory): -# $ ./subx translate *.subx apps/assort.subx -o apps/assort -# $ cat x -# == code -# abc -# == code -# def -# $ cat x |./subx run apps/assort -# == code -# abc -# def - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: - # initialize heap - # . Heap = new-segment(Heap-size) - # . . push args - 68/push Heap/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - otherwise convert stdin - # var ed/EAX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # configure ed to really exit() - # . ed->target = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # return convert(Stdin, 1/stdout, 2/stderr, ed) - # . . push args - 50/push-EAX/ed - 68/push Stderr/imm32 - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# data structure: -# table: (address stream {string, (address stream byte)}) (8 bytes per row) -# inefficient; uses sequential search for looking up segments by name - -convert: # in : (address buffered-file), out : (address buffered-file) -> <void> - # pseudocode: - # var table : (address stream) = new-stream(10 rows, 8 bytes each) - # read-segments(in, table) - # write-segments(out, table) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - # var table/ECX : (address stream byte) = stream(10 * 8) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x50/imm32 # subtract from ESP - 68/push 0x50/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # clear-stream(table) - # . . 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 -$convert:read: -#? # print("read\n") {{{ -#? # . . push args -#? 68/push "read\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # read-segments(in, table) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-segments/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:write: -#? # print("write\n") {{{ -#? # . . push args -#? 68/push "write\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # write-segments(out, table) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-segments/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x5c/imm32 # add to ESP - # . restore registers - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input (meta comments in parens) - # # comment 1 - # # comment 2 indented - # == code 0x09000000 (new segment) - # # comment 3 inside a segment - # 1 - # (empty line) - # 2 3 # comment 4 inline with other contents - # == data 0x0a000000 (new segment) - # 4 5/imm32 - # == code (existing segment but non-contiguous with previous iteration) - # 6 7 - # 8 9 (multiple lines) - # == code (existing segment contiguous with previous iteration) - # 10 11 - # . write(_test-input-stream, "# comment 1\n") - # . . push args - 68/push "# comment 1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, " # comment 2 indented\n") - # . . push args - 68/push " # comment 2 indented\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== code 0x09000000\n") - # . . push args - 68/push "== code 0x09000000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "# comment 3 inside a segment\n") - # . . push args - 68/push "# comment 3 inside a segment\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "1\n") - # . . push args - 68/push "1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "\n") # empty line - # . . push args - 68/push "\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") - # . . push args - 68/push "2 3 # comment 4 inline with other contents\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x0a000000\n") - # . . push args - 68/push "== data 0x0a000000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "4 5/imm32\n") - # . . push args - 68/push "4 5/imm32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== code\n") - # . . push args - 68/push "== code\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "6 7\n") - # . . push args - 68/push "6 7\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "8 9\n") - # . . push args - 68/push "8 9\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== code\n") - # . . push args - 68/push "== code\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "10 11\n") - # . . push args - 68/push "10 11\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check output - # == code 0x09000000 - # 1 - # 2 3 # comment 4 inline with other contents - # 6 7 - # 8 9 - # 10 11 - # == data 0x0a000000 - # 4 5/imm32 -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(_test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} - # . check-next-stream-line-equal(_test-output-stream, "== code 0x09000000", msg) - # . . push args - 68/push "F - test-convert/0"/imm32 - 68/push "== code 0x09000000"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "1", msg) - # . . push args - 68/push "F - test-convert/1"/imm32 - 68/push "1"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "2 3 # comment 4 inline with other contents", msg) - # . . push args - 68/push "F - test-convert/2"/imm32 - 68/push "2 3 # comment 4 inline with other contents"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "6 7", msg) - # . . push args - 68/push "F - test-convert/3"/imm32 - 68/push "6 7"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "8 9", msg) - # . . push args - 68/push "F - test-convert/4"/imm32 - 68/push "8 9"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "10 11", msg) - # . . push args - 68/push "F - test-convert/5"/imm32 - 68/push "10 11"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== data 0x0a000000", msg) - # . . push args - 68/push "F - test-convert/6"/imm32 - 68/push "== data 0x0a000000"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32", msg) - # . . push args - 68/push "F - test-convert/7"/imm32 - 68/push "4 5/imm32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# beware: leaks memory (one name per segment read) -read-segments: # in : (address buffered-file), table : (address stream {string, (address stream byte)}) - # pseudocode: - # var curr-segment = null - # var line = new-stream(512, 1) - # while true - # clear-stream(line) - # read-line-buffered(in, line) - # if (line->write == 0) break # end of file - # var word-slice = next-word(line) - # if slice-empty?(word-slice) # whitespace - # continue - # if slice-starts-with?(word-slice, "#") # comment - # continue - # if slice-equal?(word-slice, "==") - # var segment-name = next-word(line) - # segment-slot = leaky-get-or-insert-slice(table, segment-name, row-size=8) - # curr-segment = *segment-slot - # if curr-segment != 0 - # continue - # curr-segment = new-stream(Segment-size) - # *segment-slot = curr-segment - # rewind-stream(line) - # write-stream(curr-segment, line) # abort if curr-segment overflows - # - # word-slice and segment-name are both slices with disjoint lifetimes, so - # we'll use the same address for them. - # - # registers: - # line: ECX - # word-slice and segment-name: EDX - # segment-name and curr-segment: EBX - # word-slice->start: ESI - # temporary: EAX - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - # var line/ECX : (address stream byte) = stream(512) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP - 68/push 0x200/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var word-slice/EDX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -$read-segments:loop: - # clear-stream(line) - # . . 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 - # read-line-buffered(in, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-line-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$read-segments:check0: - # if (line->write == 0) break - 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX - 0f 84/jump-if-equal $read-segments:break/disp32 -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? 51/push-ECX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(line) -#? # . . push args -#? 51/push-ECX -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # next-word(line, word-slice) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$read-segments:check1: -#? # print("check1\n") {{{ -#? # . . push args -#? 68/push "check1\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # if (slice-empty?(word-slice)) continue - # . EAX = slice-empty?(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) continue - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $read-segments:loop/disp32 -$read-segments:check-for-comment: -#? # print("check for comment\n") {{{ -#? # . . push args -#? 68/push "check for comment\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # if (slice-starts-with?(word-slice, "#")) continue - # . start/ESI = word-slice->start - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *ECX to ESI - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL - # . if (EAX == '#') continue - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $read-segments:loop/disp32 -$read-segments:check-for-segment-header: -#? # print("check for segment header\n") {{{ -#? # . . push args -#? 68/push "check for segment header\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 52/push-EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # if !slice-equal?(word-slice, "==") goto next check - # . EAX = slice-equal?(word-slice, "==") - # . . push args - 68/push "=="/imm32 - 52/push-EDX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto check3 - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $read-segments:regular-line/disp32 - # segment-name = next-word(line) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump segment name {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 52/push-EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # segment-slot/EAX = leaky-get-or-insert-slice(table, segment-name, row-size=8) - # . . push args - 68/push 8/imm32/row-size - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call leaky-get-or-insert-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # curr-segment = *segment-slot - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 3/r32/EBX . . # copy *EAX to EBX - # if (curr-segment != 0) continue - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX - 0f 85/jump-if-not-equal $read-segments:loop/disp32 - # curr-segment = new-stream(Heap, Segment-size, 1) - # . save segment-slot - 50/push-EAX - # . EAX = new-stream(Heap, Segment-size, 1) - # . . push args - 68/push 1/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size - 68/push Heap/imm32 - # . . call - e8/call new-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . curr-segment = EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX - # . restore segment-slot - 58/pop-to-EAX - # *segment-slot = curr-segment - 89/copy 0/mod/indirect 0/rm32/EAX . . . 3/r32/EBX . . # copy EBX to *EAX - # fall through -$read-segments:regular-line: -#? # print("regular line\n") {{{ -#? # . . push args -#? 68/push "regular line\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # dump line {{{ -#? # . write(2/stderr, "regular line: ") -#? # . . push args -#? 68/push "regular line: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(line) -#? # . . push args -#? 51/push-ECX -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? 51/push-ECX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # rewind-stream(line) - # . . push args - 51/push-ECX - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # print("write stream\n") {{{ -#? # . . push args -#? 68/push "write stream\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # write-stream(curr-segment, line) - # . . push args - 51/push-ECX - 53/push-EBX - # . . call - e8/call write-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # loop -#? # print("loop\n") {{{ -#? # . . push args -#? 68/push "loop\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - e9/jump $read-segments:loop/disp32 -$read-segments:break: -$read-segments:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP - # . restore registers - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -write-segments: # out : (address buffered-file), table : (address stream {string, (address stream byte)}) - # pseudocode: - # var curr = table->data - # var max = table->data + table->write - # while curr < max - # stream = table[i].stream - # write-stream-data(out, stream) - # curr += 8 - # flush(out) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 52/push-EDX - 56/push-ESI - # ESI = table - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # write/EDX = table->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - # curr/ESI = table->data - 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 0xc/imm32 # add to EAX - # max/EDX = curr + write - 01/add 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # add ESI to EDX -$write-segments:loop: - # if (curr >= max) break - 39/compare 3/mod/direct 6/rm32/ESI . . . 2/r32/EDX . . # compare ESI with EDX - 73/jump-if-greater-or-equal-unsigned $write-segments:break/disp8 - # stream/EAX = table[i].stream - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - # write-stream-data(out, stream) - # . . push args - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$write-segments:continue: - # curr += 8 - 81 0/subop/add 3/mod/direct 6/rm32/ESI . . . . . 8/imm32 # add to ESI - eb/jump $write-segments:loop/disp8 -$write-segments:break: - # flush(out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$write-segments:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 deleted file mode 100755 index 47ee601e..00000000 --- a/subx/apps/crenshaw2-1 +++ /dev/null Binary files differdiff --git a/subx/apps/crenshaw2-1.subx b/subx/apps/crenshaw2-1.subx deleted file mode 100644 index 0c3f180b..00000000 --- a/subx/apps/crenshaw2-1.subx +++ /dev/null @@ -1,585 +0,0 @@ -# Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas -# which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt -# except that we support hex digits. -# -# To run (from the subx/ directory): -# $ ./subx translate *.subx apps/crenshaw2-1.subx -o apps/crenshaw2-1 -# $ echo '3' |./subx run apps/crenshaw2-1 -# Expected output: -# # syscall(exit, 3) -# bb/copy-to-EBX 3/imm32 -# b8/copy-to-EAX 1/imm32/exit -# cd/syscall 0x80/imm8 -# -# To run the generated output: -# $ echo '3' |./subx run apps/crenshaw2-1 > z1.subx -# $ ./subx translate z1.subx -o z1 -# $ ./subx run z1 -# $ echo $? -# 3 -# -# Stdin must contain just a single hex digit. Other input will print an error: -# $ echo 'xyz' |./subx run apps/crenshaw2-1 -# Error: integer expected -# -# Names in this file sometimes follow Crenshaw's original rather than my usual -# naming conventions. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: # run tests if necessary, call 'compile' if not - # initialize heap - # . Heap = new-segment(64KB) - # . . push args - 68/push Heap/imm32 - 68/push 0x10000/imm32/64KB - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # . 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # configure ed to really exit() - # . ed->target = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # return compile(Stdin, 1/stdout, 2/stderr, ed) - # . . push args - 50/push-EAX/ed - 68/push 2/imm32/stderr - 68/push 1/imm32/stdout - 68/push Stdin/imm32 - # . . call - e8/call compile/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# the main entry point -compile: # in : (address buffered-file), out : fd or (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - # prime the pump - # . Look = get-char(in) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call get-char/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # var num/ECX : (address stream) on the stack - # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes. - # Sizing the stream just right buys us overflow-handling for free inside 'get-num'. - # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex. - # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point. - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x13/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # initialize the stream - # . num->length = 7 - c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) - # . 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 - # read a digit from 'in' into 'num' - # . get-num(in, num, err, ed) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 51/push-ECX/num - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call get-num/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # render 'num' into the following template on 'out': - # bb/copy-to-EBX _num_ - # b8/copy-to-EAX 1/imm32/exit - # cd/syscall 0x80/imm8 - # - # . write(out, "bb/copy-to-EBX ") - # . . push args - 68/push "bb/copy-to-EBX "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - 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) - # . . push args - 51/push-ECX/num - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - 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) - # . . push args - 68/push Newline/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(out, "b8/copy-to-EAX 1/imm32/exit\n") - # . . push args - 68/push "b8/copy-to-EAX 1/imm32/exit\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(out, "cd/syscall 0x80/imm8\n") - # . . push args - 68/push "cd/syscall 0x80/imm8\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$compile:end: - # . restore registers - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# Read a single digit into 'out'. Abort if there are none, or if there is no space in 'out'. -# Input comes from the global variable 'Look', and we leave the next byte from -# '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 - # write(err, "Error: too many digits in number\n") - # stop(ed, 1) - # out->data[out->write] = LSB(Look) - # ++out->write - # Look = get-char(in) - # - # registers: - # in: ESI - # out: EDI - # out->write: ECX (cached copy; need to keep in sync) - # out->length: EDX - # temporaries: EAX, EBX - # We can't allocate Look to a register because it gets written implicitly in - # get-char in each iteration of the loop. (Thereby demonstrating that it's - # not the right interface for us. But we'll keep it just to follow Crenshaw.) - # - # . 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") - # . 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) - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $get-num:main/disp8 - # . expected(ed, err, "integer") - # . . push args - 68/push "integer"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - # . . call - e8/call expected/disp32 # never returns - # . . 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 - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # read necessary variables to registers - # ESI = in - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # EDI = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI - # ECX = out->write - 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 - 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 - # . . push args - 68/push "get-num: too many digits in number"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - # . . call - e8/call error/disp32 # never returns - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$get-num:stage2: - # out->data[out->write] = LSB(Look) - 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 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX - 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX - # ++out->write - 41/increment-ECX - # Look = get-char(in) - # . . push args - 56/push-ESI - # . . 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:loop-end: - # persist necessary variables from registers - 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI -$get-num:end: - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-get-num-reads-single-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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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) - # . . 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") - # . . push args - 68/push "3"/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 - # 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . tailor-exit-descriptor(ed, 16) - # . . push args - 68/push 0x10/imm32/nbytes-of-args-for-get-num - 50/push-EAX/ed - # . . call - 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) - # . . 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) - # . . push args - 50/push-EAX/ed - 68/push _test-error-stream/imm32 - 68/push _test-output-stream/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call get-num/disp32 - # 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', msg) - # . . push args - 68/push "F - test-get-num-reads-single-digit"/imm32 - 68/push 0x33/imm32 - b8/copy-to-EAX _test-output-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) - # . . 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 - 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 - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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) - # . . 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") - # . . push args - 68/push "3"/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 - # 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . tailor-exit-descriptor(ed, 16) - # . . push args - 68/push 0x10/imm32/nbytes-of-args-for-get-num - 50/push-EAX/ed - # . . call - 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* prime the pump - # get-num(in, out, err, ed) - # . . push args - 50/push-EAX/ed - 68/push _test-error-stream/imm32 - 68/push _test-output-stream/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call get-num/disp32 - # 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 - # . . push args - 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 - 68/push 2/imm32 - # . . 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 - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -## helpers - -# write(f, "Error: "+s+" expected\n") then stop(ed, 1) -expected: # ed : (address exit-descriptor), 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 - # write(f, "Error: ") - # . . push args - 68/push "Error: "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(f, s) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(f, " expected") - # . . push args - 68/push " expected\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # stop(ed, 1) - # . . push args - 68/push 1/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call stop/disp32 - # should never get past this point -$expected:dead-end: - # . 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 save it in 'Look' -get-char: # f : (address buffered-file) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - # EAX = read-byte-buffered(f) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # save EAX to Look - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look -$get-char:end: - # . restore registers - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -is-digit?: # c : int -> EAX : boolean - # . prolog - 55/push-EBP - 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 - 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 - 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 - b8/copy-to-EAX 1/imm32 -$is-digit?:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -Look: # (char with some extra padding) - 0/imm32 - -_test-output-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 8/imm32 - # data - 00 00 00 00 00 00 00 00 # 8 bytes - -_test-error-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 0x40/imm32 - # data (4 lines x 16 bytes/line) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b deleted file mode 100755 index fba81a7d..00000000 --- a/subx/apps/crenshaw2-1b +++ /dev/null Binary files differdiff --git a/subx/apps/crenshaw2-1b.subx b/subx/apps/crenshaw2-1b.subx deleted file mode 100644 index e1bb6448..00000000 --- a/subx/apps/crenshaw2-1b.subx +++ /dev/null @@ -1,785 +0,0 @@ -# Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas -# which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt -# except that we support hex numbers of multiple digits. -# -# To run (from the subx/ directory): -# $ ./subx translate *.subx apps/crenshaw2-1b.subx -o apps/crenshaw2-1b -# $ echo '1a' |./subx run apps/crenshaw2-1b -# Expected output: -# # syscall(exit, 1a) -# bb/copy-to-EBX 3/imm32 -# b8/copy-to-EAX 1/imm32/exit -# cd/syscall 0x80/imm8 -# -# To run the generated output: -# $ echo '1a' |./subx run apps/crenshaw2-1b > z1.subx -# $ ./subx translate z1.subx -o z1 -# $ ./subx run z1 -# $ echo $? -# 26 # 0x1a in decimal -# -# Stdin must contain just a single hex digit. Other input will print an error: -# $ echo 'xyz' |./subx run apps/crenshaw2-1b -# Error: integer expected -# -# Names in this file sometimes follow Crenshaw's original rather than my usual -# naming conventions. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: # run tests if necessary, call 'compile' if not - # initialize heap - # . Heap = new-segment(64KB) - # . . push args - 68/push Heap/imm32 - 68/push 0x10000/imm32/64KB - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # . 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # configure ed to really exit() - # . ed->target = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # return compile(Stdin, 1/stdout, 2/stderr, ed) - # . . push args - 50/push-EAX/ed - 68/push 2/imm32/stderr - 68/push 1/imm32/stdout - 68/push Stdin/imm32 - # . . call - e8/call compile/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# the main entry point -compile: # in : (address buffered-file), out : fd or (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - # prime the pump - # . Look = get-char(in) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call get-char/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # var num/ECX : (address stream) on the stack - # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes. - # Sizing the stream just right buys us overflow-handling for free inside 'get-num'. - # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex. - # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point. - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x13/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # initialize the stream - # . num->length = 7 - c7 0/subop/copy 1/mod/*+disp8 1/rm32/ECX . . . . 8/disp8 7/imm32 # copy to *(ECX+8) - # . 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 - # read a digit from 'in' into 'num' - # . get-num(in, num, err, ed) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 51/push-ECX/num - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call get-num/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # render 'num' into the following template on 'out': - # bb/copy-to-EBX _num_ - # b8/copy-to-EAX 1/imm32/exit - # cd/syscall 0x80/imm8 - # - # . write(out, "bb/copy-to-EBX ") - # . . push args - 68/push "bb/copy-to-EBX "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - 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) - # . . push args - 51/push-ECX/num - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - 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) - # . . push args - 68/push Newline/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(out, "b8/copy-to-EAX 1/imm32/exit\n") - # . . push args - 68/push "b8/copy-to-EAX 1/imm32/exit\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(out, "cd/syscall 0x80/imm8\n") - # . . push args - 68/push "cd/syscall 0x80/imm8\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$compile:end: - # . restore registers - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# Read a sequence of digits into 'out'. Abort if there are none, or if there is -# no space in 'out'. -# Input comes from the global variable 'Look' (first byte) and the argument -# '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") - # do - # 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) - # This is complicated because I don't want to hard-code the error strategy in - # a general helper like write-byte-buffered. Maybe I should just create a - # local helper. - # - # within the loop we'll try to keep things in registers: - # in: ESI - # out: EDI - # out->write: ECX (cached copy; need to keep in sync) - # out->length: EDX - # temporaries: EAX, EBX - # We can't allocate Look to a register because it gets written implicitly in - # get-char in each iteration of the loop. (Thereby demonstrating that it's - # not the right interface for us. But we'll keep it just to follow Crenshaw.) - # - # . 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") - # . 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) - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $get-num:main/disp8 - # . expected(ed, err, "integer") - # . . push args - 68/push "integer"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - # . . call - e8/call expected/disp32 # never returns - # . . 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 - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # read necessary variables to registers - # ESI = in - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # EDI = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI - # ECX = out->write - 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 -$get-num:loop: - # 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 - # . . push args - 68/push "get-num: too many digits in number"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - # . . call - e8/call error/disp32 # never returns - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$get-num:loop-stage2: - # out->data[out->write] = LSB(Look) - 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 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy *Look to EAX - 88/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at AL to *EBX - # ++out->write - 41/increment-ECX - # Look = get-char(in) - # . . push args - 56/push-ESI - # . . call - 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 - # . 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) loop - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $get-num:loop/disp32 -$get-num:loop-end: - # persist necessary variables from registers - 89/copy 0/mod/indirect 7/rm32/EDI . . . 1/r32/ECX . . # copy ECX to *EDI -$get-num:end: - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-get-num-reads-single-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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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) - # . . 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") - # . . push args - 68/push "3"/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 - # 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . tailor-exit-descriptor(ed, 16) - # . . push args - 68/push 0x10/imm32/nbytes-of-args-for-get-num - 50/push-EAX/ed - # . . call - 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) - # . . 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) - # . . push args - 50/push-EAX/ed - 68/push _test-error-stream/imm32 - 68/push _test-output-stream/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call get-num/disp32 - # 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', msg) - # . . push args - 68/push "F - test-get-num-reads-single-digit"/imm32 - 68/push 0x33/imm32 - b8/copy-to-EAX _test-output-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) - # . . 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 - 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 - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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) - # . . 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") - # . . push args - 68/push "3"/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 - # 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . tailor-exit-descriptor(ed, 16) - # . . push args - 68/push 0x10/imm32/nbytes-of-args-for-get-num - 50/push-EAX/ed - # . . call - 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* prime the pump - # get-num(in, out, err, ed) - # . . push args - 50/push-EAX/ed - 68/push _test-error-stream/imm32 - 68/push _test-output-stream/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call get-num/disp32 - # 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 - # . . push args - 68/push "F - test-get-num-aborts-on-non-digit-in-Look"/imm32 - 68/push 2/imm32 - # . . 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 - 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 - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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) - # . . 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") - # . . push args - 68/push "3456"/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 - # 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . tailor-exit-descriptor(ed, 16) - # . . push args - 68/push 0x10/imm32/nbytes-of-args-for-get-num - 50/push-EAX/ed - # . . call - 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) - # . . 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) - # . . push args - 50/push-EAX/ed - 68/push _test-error-stream/imm32 - 68/push _test-output-stream/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call get-num/disp32 - # 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', msg) - # . . push args - 68/push "F - test-get-num-reads-multiple-digits"/imm32 - 68/push 0x36353433/imm32 - b8/copy-to-EAX _test-output-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) - # . . 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 - 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 - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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) - # . . 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") - # . . push args - 68/push "3456 x"/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 - # 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 - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . tailor-exit-descriptor(ed, 16) - # . . push args - 68/push 0x10/imm32/nbytes-of-args-for-get-num - 50/push-EAX/ed - # . . call - 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) - # . . 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) - # . . push args - 50/push-EAX/ed - 68/push _test-error-stream/imm32 - 68/push _test-output-stream/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call get-num/disp32 - # 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', msg) - # . . push args - 68/push "F - test-get-num-reads-multiple-digits-followed-by-nondigit"/imm32 - 68/push 0x36353433/imm32 - b8/copy-to-EAX _test-output-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) - # . . 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 - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -## helpers - -# write(f, "Error: "+s+" expected\n") then stop(ed, 1) -expected: # ed : (address exit-descriptor), 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 - # write(f, "Error: ") - # . . push args - 68/push "Error: "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(f, s) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(f, " expected\n") - # . . push args - 68/push " expected\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # stop(ed, 1) - # . . push args - 68/push 1/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call stop/disp32 - # should never get past this point -$expected:dead-end: - # . 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 save it in 'Look' -get-char: # f : (address buffered-file) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - # EAX = read-byte-buffered(f) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # save EAX to Look - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Look/disp32 . # copy EAX to *Look -$get-char:end: - # . restore registers - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -is-digit?: # c : int -> EAX : boolean - # . prolog - 55/push-EBP - 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 - 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 - 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 - b8/copy-to-EAX 1/imm32 -$is-digit?:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -Look: # (char with some extra padding) - 0/imm32 - -_test-output-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 8/imm32 - # data - 00 00 00 00 00 00 00 00 # 8 bytes - -_test-error-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 0x40/imm32 - # data (4 lines x 16 bytes/line) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/dquotes b/subx/apps/dquotes deleted file mode 100755 index b7a4adfe..00000000 --- a/subx/apps/dquotes +++ /dev/null Binary files differdiff --git a/subx/apps/dquotes.subx b/subx/apps/dquotes.subx deleted file mode 100644 index 6848ad19..00000000 --- a/subx/apps/dquotes.subx +++ /dev/null @@ -1,2757 +0,0 @@ -# Translate literal strings within double quotes. -# Replace them with references to new variables in the data segment. -# -# To run (from the subx/ directory): -# $ ./subx translate *.subx apps/dquotes.subx -o apps/dquotes -# $ cat x -# == code -# ab "cd ef"/imm32 -# $ cat x |./subx run apps/dquotes -# == code -# ab __string1/imm32 -# == data -# __string1: -# 5/imm32 -# 0x63/c 0x64/d 0x20/ 0x65/e 0x66/f - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: - # initialize heap - # . Heap = new-segment(Heap-size) - # . . push args - 68/push Heap/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - otherwise convert stdin - # var ed/EAX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # configure ed to really exit() - # . ed->target = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # return convert(Stdin, 1/stdout, 2/stderr, ed) - # . . push args - 50/push-EAX/ed - 68/push Stderr/imm32 - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# conceptual hierarchy within a line: -# line = words separated by ' ', maybe followed by comment starting with '#' -# word = datum until '/', then 0 or more metadata separated by '/' - -convert: # in : (address buffered-file), out : (address buffered-file) -> <void> - # pseudocode: - # var line = new-stream(512, 1) - # var new-data-segment = new-stream(Heap, Segment-size, 1) - # write(new-data-segment, "== data\n") - # while true - # clear-stream(line) - # read-line-buffered(in, line) - # if (line->write == 0) break # end of file - # while true - # var word-slice = next-word-or-string(line) - # if slice-empty?(word-slice) # end of line - # break - # if slice-starts-with?(word-slice, "#") # comment - # continue - # if slice-starts-with?(word-slice, '"') # string literal <== what we're here for - # process-string-literal(word-slice, out, new-data-segment) - # else - # write-slice-buffered(out, word-slice) - # write(out, " ") - # write(out, "\n\n") - # write-stream-data(out, new-data-segment) - # flush(out) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # var line/ECX : (address stream byte) = stream(512) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP - 68/push 0x200/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var word-slice/EDX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # new-data-segment/EDI = new-stream(Heap, Segment-size, 1) - # . EAX = new-stream(Heap, Segment-size, 1) - # . . push args - 68/push 1/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size - 68/push Heap/imm32 - # . . call - e8/call new-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . EDI = EAX - 89/copy 3/mod/direct 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to EDI - # write(new-data-segment, "== data\n") - # . . push args - 68/push "== data\n"/imm32 - 57/push-EDI - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:line-loop: - # clear-stream(line) - # . . 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 - # read-line-buffered(in, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-line-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:check0: - # if (line->write == 0) break - 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX - 0f 84/jump-if-equal $convert:break/disp32 -$convert:word-loop: - # next-word-or-string(line, word-slice) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word-or-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:check1: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $convert:next-line/disp32 -$convert:check-for-comment: - # if (slice-starts-with?(word-slice, "#")) continue - # . start/ESI = word-slice->start - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *EDX to ESI - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL - # . if (EAX == '#') continue - 3d/compare-EAX-and 0x23/imm32/hash - 74/jump-if-equal $convert:word-loop/disp8 -$convert:check-for-string-literal: - 3d/compare-EAX-and 0x22/imm32/dquote - 75/jump-if-not-equal $convert:regular-word/disp8 -$convert:string-literal: - # process-string-literal(word-slice, out, new-data-segment) - # . . push args - 57/push-EDI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 52/push-EDX - # . . call - e8/call process-string-literal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # continue - eb/jump $convert:next-word/disp8 -$convert:regular-word: - # write-slice-buffered(out, word-slice) - # . . push args - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # fall through -$convert:next-word: - # write-buffered(out, " ") - # . . push args - 68/push " "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # loop - eb/jump $convert:word-loop/disp8 -$convert:next-line: - # write-buffered(out, "\n") - # . . push args - 68/push Newline/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # loop - e9/jump $convert:line-loop/disp32 -$convert:break: - # write-stream-data(out, new-data-segment) - # . . push args - 57/push-EDI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # flush(out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$convert:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# Write out 'string-literal' in a new format to 'out-segment', assign it a new -# label, and write the new label out to 'out'. -process-string-literal: # string-literal : (address slice), out : (address buffered-file), out-segment : (address stream) - # pseudocode: - # print(out-segment, "_string#{Next-string-literal}:\n") - # emit-string-literal-data(out-segment, string-literal) - # print(out, "_string#{Next-string-literal}") - # emit-metadata(out, string-literal) - # ++ *Next-string-literal - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - # var int32-stream/ECX = stream(10) # number of decimal digits a 32-bit number can have - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa/imm32 # subtract from ESP - 68/push 0xa/imm32/decimal-digits-in-32bit-number - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # print(out-segment, "_string#{Next-string-literal}:\n") - # . write(out-segment, "_string") - # . . push args - 68/push "_string"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . print-int32-decimal(out-segment, *Next-string-literal) - # . . push args - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call print-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(out-segment, ":\n") - # . . push args - 68/push ":\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-string-literal-data(out-segment, string-literal) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x8/disp8 . # push *(EBP+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call emit-string-literal-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(out-segment, "\n") - # . . push args - 68/push Newline/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # print(out, "_string#{Next-string-literal}") - # . write-buffered(out, "_string") - # . . push args - 68/push "_string"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . print-int32-decimal(int32-stream, *Next-string-literal) - # . . push args - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal - 51/push-ECX - # . . call - e8/call print-int32-decimal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write-stream-data(out, int32-stream) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-metadata(out, string-literal) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-metadata/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # ++ *Next-string-literal - ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # increment *Num-test-failures -$process-string-literal:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x16/imm32 # add to ESP - # . restore registers - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-is-idempotent-by-default: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input (meta comments in parens) - # # comment 1 - # # comment 2 indented - # == code 0x1 (new segment) - # # comment 3 inside a segment - # 1 - # (empty line) - # 2 3 # comment 4 inline with other contents - # == data 0x2 (new segment) - # 4 5/imm32 - # . write(_test-input-stream, "# comment 1\n") - # . . push args - 68/push "# comment 1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, " # comment 2 indented\n") - # . . push args - 68/push " # comment 2 indented\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== code 0x1\n") - # . . push args - 68/push "== code 0x1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "# comment 3 inside a segment\n") - # . . push args - 68/push "# comment 3 inside a segment\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "1\n") - # . . push args - 68/push "1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "\n") # empty line - # . . push args - 68/push "\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n") - # . . push args - 68/push "2 3 # comment 4 inline with other contents\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x2\n") - # . . push args - 68/push "== data 0x2\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "4 5/imm32\n") - # . . push args - 68/push "4 5/imm32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check output - # (comment dropped for now) - # (comment dropped for now) - # == code 0x1 - # (comment dropped for now) - # 1 - # (comment dropped for now) - # 2 3 - # == data 0x2 - # 4 5/imm32 - # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-next-stream-line-equal(_test-output-stream, "", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/0"/imm32 - 68/push ""/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/1"/imm32 - 68/push ""/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/2"/imm32 - 68/push "== code 0x1 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/3"/imm32 - 68/push ""/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "1 ", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/4"/imm32 - 68/push "1 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/5"/imm32 - 68/push ""/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "2 3 ", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/6"/imm32 - 68/push "2 3 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== data 0x2 ", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/7"/imm32 - 68/push "== data 0x2 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "4 5/imm32 ", msg) - # . . push args - 68/push "F - test-convert-is-idempotent-by-default/8"/imm32 - 68/push "4 5/imm32 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-processes-string-literals: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input (meta comments in parens) - # == code (new segment) - # 1 "a"/x - # 2 "bc"/y - 68/push "== code 0x1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "1 \"a\"/x\n") - # . . push args - 68/push "1 \"a\"/x\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "2 \"bc\"/y\n") - # . . push args - 68/push "2 \"bc\"/y\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check output - # == code 0x1 - # 1 _string1/x - # 2 _string2/y - # == data - # _string1: - # 1/imm32 61/a - # _string2: - # 2/imm32 62/b 63/c - # We don't care right now what exactly happens to comments. Trailing spaces are also minor details. - # - # Open question: how to make this check more robust. - # We don't actually care what the auto-generated string variables are - # called. We just want to make sure instructions using string literals - # switch to a string variable with the right value. - # (Modifying string literals completely off the radar for now.) -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(_test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} - # . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/0"/imm32 - 68/push "== code 0x1 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "1 _string1/x ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/1"/imm32 - 68/push "1 _string1/x "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/2"/imm32 - 68/push "2 _string2/y "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== data", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/3"/imm32 - 68/push "== data"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/4"/imm32 - 68/push "_string1:"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/5"/imm32 - 68/push "0x00000001/imm32 61/a "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/6"/imm32 - 68/push "_string2:"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg) - # . . push args - 68/push "F - test-convert-processes-string-literals/7"/imm32 - 68/push "0x00000002/imm32 62/b 63/c "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# generate the data segment contents byte by byte for a given slice -emit-string-literal-data: # out : (address stream), word : (address slice) - # pseudocode - # len = string-length-at-start-of-slice(word->start, word->end) - # print(out, "#{len}/imm32 ") - # curr = word->start - # ++curr # skip '"' - # while true - # if (curr >= word->end) break - # c = *curr - # if (c == '"') break - # if (c == '\') { - # ++curr - # c = *curr - # if (c == 'n') - # c = newline - # } - # append-byte-hex(out, c) - # if c is alphanumeric: - # write(out, "/") - # append-byte(out, c) - # write(out, " ") - # ++curr - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 56/push-ESI - # ESI = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # curr/EDX = word->start - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - # max/ESI = word->end - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI -$emit-string-literal-data:emit-length: - # len/EAX = string-length-at-start-of-slice(word->start, word->end) - # . . push args - 56/push-ESI - 52/push-EDX - # . . call - e8/call string-length-at-start-of-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # print(out, "#{len}/imm32 ") - # . print-int32(out, len) - # . . push args - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call print-int32/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(out, "/imm32 ") - # . . push args - 68/push "/imm32 "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$emit-string-literal-data:loop-init: - # ++curr # skip initial '"' - 42/increment-EDX - # c/ECX = 0 - 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX -$emit-string-literal-data:loop: - # if (curr >= max) break - 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI - 0f 83/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp32 - # CL = *curr - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL - # if (c == '"') break - 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x22/imm32/dquote # compare ECX - 74/jump-if-equal $emit-string-literal-data:end/disp8 - # if (c != '\') goto emit - 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x5c/imm32/backslash # compare ECX - 75/jump-if-not-equal $emit-string-literal-data:emit/disp8 - # ++curr - 42/increment-EDX - # if (curr >= max) break - 39/compare 3/mod/direct 2/rm32/EDX . . . 6/r32/ESI . . # compare EDX with ESI - 73/jump-if-greater-or-equal-unsigned $emit-string-literal-data:end/disp8 - # c = *curr - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL - # if (c == 'n') c = newline - 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x6e/imm32/n # compare ECX - 75/jump-if-not-equal $emit-string-literal-data:emit/disp8 - b9/copy-to-ECX 0x0a/imm32/newline -$emit-string-literal-data:emit: - # append-byte-hex(out, CL) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call append-byte-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (is-alphanumeric?(*curr)) print(out, "/#{*curr}") - # . EAX = is-alphanumeric?(CL) - # . . push args - 51/push-ECX - # . . call - e8/call is-alphanumeric?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX == 0) goto char-done - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-string-literal-data:char-done/disp8 - # . write(out, "/") - # . . push args - 68/push Slash/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . append-byte(out, *curr) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call append-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$emit-string-literal-data:char-done: - # write(out, " ") - # . . push args - 68/push Space/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # ++curr - 42/increment-EDX - e9/jump $emit-string-literal-data:loop/disp32 -$emit-string-literal-data:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -is-alphanumeric?: # c : int -> EAX : boolean - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # EAX = c - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX - # if (EAX < '0') return false - 3d/compare-EAX-with 0x30/imm32/0 - 7c/jump-if-lesser $is-alphanumeric?:false/disp8 - # if (EAX <= '9') return true - 3d/compare-EAX-with 0x39/imm32/9 - 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 - # if (EAX < 'A') return false - 3d/compare-EAX-with 0x41/imm32/A - 7c/jump-if-lesser $is-alphanumeric?:false/disp8 - # if (EAX <= 'Z') return true - 3d/compare-EAX-with 0x5a/imm32/Z - 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 - # if (EAX < 'a') return false - 3d/compare-EAX-with 0x61/imm32/a - 7c/jump-if-lesser $is-alphanumeric?:false/disp8 - # if (EAX <= 'z') return true - 3d/compare-EAX-with 0x7a/imm32/z - 7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8 - # return false -$is-alphanumeric?:false: - b8/copy-to-EAX 0/imm32/false - eb/jump $is-alphanumeric?:end/disp8 -$is-alphanumeric?:true: - b8/copy-to-EAX 1/imm32/true -$is-alphanumeric?:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-string-literal-data: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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 - # var slice/ECX = '"abc"/d' - 68/push _test-slice-abc-limit/imm32 - 68/push _test-slice-abc/imm32 - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-string-literal-data(_test-output-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-output-stream/imm32 - # . . call - e8/call emit-string-literal-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg) - # . . push args - 68/push "F - test-emit-string-literal-data"/imm32 - 68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-string-literal-data-empty: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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 - # var slice/ECX = '""' - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-string-literal-data(_test-output-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-output-stream/imm32 - # . . call - e8/call emit-string-literal-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "0/imm32 ", msg) - # . . push args - 68/push "F - test-emit-string-literal-data-empty"/imm32 - 68/push "0x00000000/imm32 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# just to keep things simple -test-emit-string-literal-data-no-metadata-for-non-alphanumerics: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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 - # var slice/ECX = '"a b"' - 68/push _test-slice-a-space-b-limit/imm32 - 68/push _test-slice-a-space-b/imm32 - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-string-literal-data(_test-output-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-output-stream/imm32 - # . . call - e8/call emit-string-literal-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints - # . . push args - 68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32 - 68/push "0x00000003/imm32 61/a 20 62/b "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-string-literal-data-handles-escape-sequences: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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 - # var slice/ECX = '"a\"b"' - 68/push _test-slice-a-dquote-b-limit/imm32 - 68/push _test-slice-a-dquote-b/imm32 - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-string-literal-data(_test-output-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-output-stream/imm32 - # . . call - e8/call emit-string-literal-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg) - # . . push args - 68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32 - 68/push "0x00000003/imm32 61/a 22 62/b "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-string-literal-data-handles-newline-escape: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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 - # var slice/ECX = '"a\nb"' - 68/push _test-slice-a-newline-b-limit/imm32 - 68/push _test-slice-a-newline-b/imm32 - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-string-literal-data(_test-output-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-output-stream/imm32 - # . . call - e8/call emit-string-literal-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "3/imm32 61/a 0a 62/b ", msg) - # . . push args - 68/push "F - test-emit-string-literal-data-handles-newline-escape"/imm32 - 68/push "0x00000003/imm32 61/a 0a 62/b "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# emit everything from a word except the initial datum -emit-metadata: # out : (address buffered-file), word : (address slice) - # pseudocode - # var slice = {0, word->end} - # curr = word->start - # if *curr == '"' - # curr = skip-string-in-slice(curr, word->end) - # else - # while true - # if curr == word->end - # return - # if *curr == '/' - # break - # ++curr - # slice->start = curr - # write-slice-buffered(out, slice) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - # ESI = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # curr/ECX = word->start - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - # end/EDX = word->end - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 4/disp8 . # copy *(ESI+4) to EDX - # var slice/EBX = {0, end} - 52/push-EDX - 68/push 0/imm32 - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX - # EAX = 0 - b8/copy-to-EAX 0/imm32 -$emit-metadata:check-for-string-literal: - # - if (*curr == '"') curr = skip-string-in-slice(curr, end) - 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL - 3d/compare-EAX-and 0x22/imm32/dquote - 75/jump-if-not-equal $emit-metadata:skip-datum-loop/disp8 -$emit-metadata:skip-string-literal: - # . EAX = skip-string-in-slice(curr, end) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . curr = EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX - eb/jump $emit-metadata:emit/disp8 -$emit-metadata:skip-datum-loop: - # - otherwise scan for '/' - # if (curr == end) return - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX and EDX - 74/jump-if-equal $emit-metadata:end/disp8 - # if (*curr == '/') break - 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL - 3d/compare-EAX-and 0x2f/imm32/slash - 74/jump-if-equal $emit-metadata:emit/disp8 - # ++curr - 41/increment-ECX - eb/jump $emit-metadata:skip-datum-loop/disp8 -$emit-metadata:emit: - # slice->start = ECX - 89/copy 0/mod/indirect 3/rm32/EBX . . . 1/r32/ECX . . # copy ECX to *EBX - # write-slice-buffered(out, slice) - # . . push args - 53/push-EBX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 8/imm32 . # add to ESP -$emit-metadata:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 8/imm32 . # add to ESP - # . restore registers - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-metadata: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "abc/def" - b8/copy-to-EAX "abc/def"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-metadata(_test-output-buffered-file, slice) - # . . push args - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-metadata/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "/def", msg) # important that there's no leading space - # . . push args - 68/push "F - test-emit-metadata"/imm32 - 68/push "/def"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-metadata-none: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "abc" - b8/copy-to-EAX "abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-metadata(_test-output-buffered-file, slice) - # . . push args - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-metadata/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "", msg) - # . . push args - 68/push "F - test-emit-metadata-none"/imm32 - 68/push ""/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-metadata-multiple: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "abc/def/ghi" - b8/copy-to-EAX "abc/def/ghi"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-metadata(_test-output-buffered-file, slice) - # . . push args - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-metadata/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "/def/ghi", msg) # important that there's no leading space - # . . push args - 68/push "F - test-emit-metadata-multiple"/imm32 - 68/push "/def/ghi"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-metadata-when-no-datum: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # var slice/ECX = "/abc" - b8/copy-to-EAX "/abc"/imm32 - # . push end/ECX - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 curr/EAX - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . save stack pointer - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-metadata(_test-output-buffered-file, slice) - # . . push args - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-metadata/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "/abc", msg) # nothing skipped - # . . push args - 68/push "F - test-emit-metadata-when-no-datum"/imm32 - 68/push "/abc"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-metadata-in-string-literal: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # var slice/ECX = "\"abc/def\"/ghi" - 68/push _test-slice-literal-string-with-limit/imm32 - 68/push _test-slice-literal-string/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-metadata(_test-output-buffered-file, slice) - # . . push args - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-metadata/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-stream-equal(_test-output-stream, "/ghi", msg) # important that there's no leading space - # . . push args - 68/push "F - test-emit-metadata-in-string-literal"/imm32 - 68/push "/ghi"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# (re)compute the bounds of the next word in the line -# return empty string on reaching end of file -next-word-or-string: # line : (address stream byte), out : (address slice) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 56/push-ESI - 57/push-EDI - # ESI = line - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # EDI = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI - # skip-chars-matching(line, ' ') - # . . push args - 68/push 0x20/imm32/space - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call skip-chars-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$next-word-or-string:check0: - # if (line->read >= line->write) clear out and return - # . EAX = line->read - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - # . if (EAX < line->write) goto next check - 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI - 7c/jump-if-lesser $next-word-or-string:check-for-comment/disp8 - # . return out = {0, 0} - c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI - c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) - eb/jump $next-word-or-string:end/disp8 -$next-word-or-string:check-for-comment: - # out->start = &line->data[line->read] - 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] == '#' - # . 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 - # . compare - 3d/compare-EAX-and 0x23/imm32/pound - 75/jump-if-not-equal $next-word-or-string:check-for-string-literal/disp8 -$next-word-or-string:comment: - # out->end = &line->data[line->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 - 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) - # line->read = line->write # skip rest of line - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX - 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) - # return - eb/jump $next-word-or-string:end/disp8 -$next-word-or-string:check-for-string-literal: - # if line->data[line->read] == '"' - # . 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 - # . compare - 3d/compare-EAX-and 0x22/imm32/dquote - 75/jump-if-not-equal $next-word-or-string:regular-word/disp8 -$next-word-or-string:string-literal: - # skip-string(line) - # . . push args - 56/push-ESI - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # fall through -$next-word-or-string:regular-word: - # skip-chars-not-matching-whitespace(line) # including trailing newline - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call skip-chars-not-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # out->end = &line->data[line->read] - 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 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -$next-word-or-string:end: - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-or-string: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write(_test-input-stream, " ab") - # . . push args - 68/push " ab"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # next-word-or-string(_test-input-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-input-stream/imm32 - # . . call - e8/call next-word-or-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(_test-input-stream->read, 4, msg) - # . . push args - 68/push "F - test-next-word-or-string/updates-stream-read-correctly"/imm32 - 68/push 4/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) - # . check-ints-equal(slice->start - _test-input-stream, 14, msg) - # . . push args - 68/push "F - test-next-word-or-string: start"/imm32 - 68/push 0xe/imm32 - # . . push slice->start - _test-input-stream - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) - # . check-ints-equal(slice->end - _test-input-stream, 16, msg) - # . . push args - 68/push "F - test-next-word-or-string: end"/imm32 - 68/push 0x10/imm32 - # . . push slice->end - _test-input-stream - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-or-string-returns-whole-comment: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write(_test-input-stream, " # a") - # . . push args - 68/push " # a"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # next-word-or-string(_test-input-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-input-stream/imm32 - # . . call - e8/call next-word-or-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(_test-input-stream->read, 5, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32 - 68/push 5/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) - # . check-ints-equal(slice->start - _test-input-stream, 14, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-whole-comment: start"/imm32 - 68/push 0xe/imm32 - # . . push slice->start - _test-input-stream - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) - # . check-ints-equal(slice->end - _test-input-stream, 17, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-whole-comment: end"/imm32 - 68/push 0x11/imm32 - # . . push slice->end - _test-input-stream - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-or-string-returns-empty-string-on-eof: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write nothing to _test-input-stream - # next-word-or-string(_test-input-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-input-stream/imm32 - # . . call - e8/call next-word-or-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(slice->end - slice->start, 0, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-empty-string-on-eof"/imm32 - 68/push 0/imm32 - # . . push slice->end - slice->start - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-or-string-returns-whole-string: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write(_test-input-stream, " \"a b\"/imm32 ") - # . . push args - 68/push " \"a b\"/imm32 "/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # next-word-or-string(_test-input-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-input-stream/imm32 - # . . call - e8/call next-word-or-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) - # . check-ints-equal(slice->start - _test-input-stream, 13, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-whole-string: start"/imm32 - 68/push 0xd/imm32 - # . . push slice->start - _test-input-stream - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(slice->end - _test-input-stream->data, 12, msg) - # . check-ints-equal(slice->end - _test-input-stream, 24, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-whole-string: end"/imm32 - 68/push 0x18/imm32 - # . . push slice->end - _test-input-stream - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-or-string-returns-string-with-escapes: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write(_test-input-stream, " \"a\\\"b\"/x") - # . . push args - 68/push " \"a\\\"b\"/x"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # next-word-or-string(_test-input-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-input-stream/imm32 - # . . call - e8/call next-word-or-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) - # . check-ints-equal(slice->start - _test-input-stream, 13, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32 - 68/push 0xd/imm32 - # . . push slice->start - _test-input-stream - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(slice->end - _test-input-stream->data, 9, msg) - # . check-ints-equal(slice->end - _test-input-stream, 21, msg) - # . . push args - 68/push "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32 - 68/push 0x15/imm32 - # . . push slice->end - _test-input-stream - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# update line->read to end of string literal surrounded by double quotes -# line->read must start out at a double-quote -skip-string: # line : (address stream) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # ECX = line - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - # EAX = skip-string-in-slice(&line->data[line->read], &line->data[line->write]) - # . . push &line->data[line->write] - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . 2/r32/EDX 8/disp8 . # copy *(ECX+8) to EDX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ECX+EDX+12 to EDX - 52/push-EDX - # . . push &line->data[line->read] - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ECX+EDX+12 to EDX - 52/push-EDX - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # line->read = EAX - line->data - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 2d/subtract-from-EAX 0xc/imm32 - 89/copy 1/mod/*+disp8 1/rm32/ECX . . 0/r32/EAX 4/disp8 . # copy EAX to *(ECX+4) -$skip-string:end: - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # . write(_test-input-stream, "\"abc\" def") - # . indices: 0123 45 - # . . push args - 68/push "\"abc\" def"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-string/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # skip-string(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(line->read, 5, msg) - # . . push args - 68/push "F - test-skip-string"/imm32 - 68/push 5/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-ignores-spaces: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # . write(_test-input-stream, "\"a b\"/yz") - # . indices: 0123 45 - # . . push args - 68/push "\"a b\"/yz"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-string-ignores-spaces/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # skip-string(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(line->read, 5, msg) - # . . push args - 68/push "F - test-skip-string-ignores-spaces"/imm32 - 68/push 5/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-ignores-escapes: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # . write(_test-input-stream, "\"a\\\"b\"/yz") - # . indices: 01 2 34 56 - # . . push args - 68/push "\"a\\\"b\"/yz"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # precondition: line->read == 0 - # . . push args - 68/push "F - test-skip-string-ignores-escapes/precondition"/imm32 - 68/push 0/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # skip-string(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(line->read, 6, msg) - # . . push args - 68/push "F - test-skip-string-ignores-escapes"/imm32 - 68/push 6/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-works-from-mid-stream: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # . write(_test-input-stream, "0 \"a\\\"b\"/yz") - # . indices: 01 2 34 56 - # . . push args - 68/push "0 \"a\\\"b\"/yz"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # precondition: line->read == 2 - c7 0/subop/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 2/imm32 # copy to *(EAX+4) - # skip-string(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call skip-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(line->read, 8, msg) - # . . push args - 68/push "F - test-skip-string-works-from-mid-stream"/imm32 - 68/push 8/imm32 - b8/copy-to-EAX _test-input-stream/imm32 - 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 - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -skip-string-in-slice: # curr : (address byte), end : (address byte) -> new_curr/EAX - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 53/push-EBX - # ECX = curr - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - # EDX = end - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX - # EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - # skip initial dquote - 41/increment-ECX -$skip-string-in-slice:loop: - # if (curr >= end) return curr - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-unsigned-or-equal $skip-string-in-slice:return-curr/disp8 - # AL = *curr - 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL -$skip-string-in-slice:dquote: - # if (EAX == '"') break - 3d/compare-EAX-and 0x22/imm32/double-quote - 74/jump-if-equal $skip-string-in-slice:break/disp8 -$skip-string-in-slice:check-for-escape: - # if (EAX == '\') escape next char - 3d/compare-EAX-and 0x5c/imm32/backslash - 75/jump-if-not-equal $skip-string-in-slice:continue/disp8 -$skip-string-in-slice:escape: - 41/increment-ECX -$skip-string-in-slice:continue: - # ++curr - 41/increment-ECX - eb/jump $skip-string-in-slice:loop/disp8 -$skip-string-in-slice:break: - # skip final dquote - 41/increment-ECX -$skip-string-in-slice:return-curr: - # return curr - 89/copy 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to EAX -$skip-string-in-slice:end: - # . restore registers - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-in-slice: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup: (EAX..ECX) = "\"abc\" def" - b8/copy-to-EAX "\"abc\" def"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # EAX = skip-string-in-slice(EAX, ECX) - # . . push args - 51/push-ECX - 50/push-EAX - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(ECX-EAX, 4, msg) # number of chars remaining after the string literal - # . . push args - 68/push "F - test-skip-string-in-slice"/imm32 - 68/push 4/imm32 - # . . push ECX-EAX - 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX - 51/push-ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-in-slice-ignores-spaces: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup: (EAX..ECX) = "\"a b\"/yz" - b8/copy-to-EAX "\"a b\"/yz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # EAX = skip-string-in-slice(EAX, ECX) - # . . push args - 51/push-ECX - 50/push-EAX - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(ECX-EAX, 3, msg) # number of chars remaining after the string literal - # . . push args - 68/push "F - test-skip-string-in-slice-ignores-spaces"/imm32 - 68/push 3/imm32 - # . . push ECX-EAX - 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX - 51/push-ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-in-slice-ignores-escapes: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup: (EAX..ECX) = "\"a\\\"b\"/yz" - b8/copy-to-EAX "\"a\\\"b\"/yz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # EAX = skip-string-in-slice(EAX, ECX) - # . . push args - 51/push-ECX - 50/push-EAX - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(ECX-EAX, 3, msg) # number of chars remaining after the string literal - # . . push args - 68/push "F - test-skip-string-in-slice-ignores-escapes"/imm32 - 68/push 3/imm32 - # . . push ECX-EAX - 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX - 51/push-ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-string-in-slice-stops-at-end: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup: (EAX..ECX) = "\"abc" # unbalanced dquote - b8/copy-to-EAX "\"abc"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # EAX = skip-string-in-slice(EAX, ECX) - # . . push args - 51/push-ECX - 50/push-EAX - # . . call - e8/call skip-string-in-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(ECX-EAX, 0, msg) # skipped to end of slice - # . . push args - 68/push "F - test-skip-string-in-slice-stops-at-end"/imm32 - 68/push 0/imm32 - # . . push ECX-EAX - 29/subtract 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # subtract EAX from ECX - 51/push-ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -string-length-at-start-of-slice: # curr : (address byte), end : (address byte) -> length/EAX - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 53/push-EBX - # ECX = curr - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - # EDX = end - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX - # length/EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - # EBX = 0 - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX - # skip initial dquote - 41/increment-ECX -$string-length-at-start-of-slice:loop: - # if (curr >= end) return length - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-unsigned-or-equal $string-length-at-start-of-slice:end/disp8 - # BL = *curr - 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 3/r32/BL . . # copy byte at *ECX to BL -$string-length-at-start-of-slice:dquote: - # if (EBX == '"') break - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x22/imm32/dquote # compare EBX - 74/jump-if-equal $string-length-at-start-of-slice:end/disp8 -$string-length-at-start-of-slice:check-for-escape: - # if (EBX == '\') escape next char - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x5c/imm32/backslash # compare EBX - 75/jump-if-not-equal $string-length-at-start-of-slice:continue/disp8 -$string-length-at-start-of-slice:escape: - # increment curr but not result - 41/increment-ECX -$string-length-at-start-of-slice:continue: - # ++result - 40/increment-EAX - # ++curr - 41/increment-ECX - eb/jump $string-length-at-start-of-slice:loop/disp8 -$string-length-at-start-of-slice:end: - # . restore registers - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-string-length-at-start-of-slice: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup: (EAX..ECX) = "\"abc\" def" - b8/copy-to-EAX "\"abc\" def"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # EAX = string-length-at-start-of-slice(EAX, ECX) - # . . push args - 51/push-ECX - 50/push-EAX - # . . call - e8/call string-length-at-start-of-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 3, msg) - # . . push args - 68/push "F - test-string-length-at-start-of-slice"/imm32 - 68/push 3/imm32 - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-string-length-at-start-of-slice-escaped: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup: (EAX..ECX) = "\"ab\\c\" def" - b8/copy-to-EAX "\"ab\\c\" def"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # EAX = string-length-at-start-of-slice(EAX, ECX) - # . . push args - 51/push-ECX - 50/push-EAX - # . . call - e8/call string-length-at-start-of-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 3, msg) - # . . push args - 68/push "F - test-string-length-at-start-of-slice-escaped"/imm32 - 68/push 3/imm32 - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -Next-string-literal: # tracks the next auto-generated variable name - 1/imm32 - -# length-prefixed string containing just a single space -Space: - # size - 1/imm32 - # data - 20/space - -# length-prefixed string containing just a single slash -Slash: - # size - 1/imm32 - # data - 2f/slash - -_test-slice-abc: - 22/dquote 61/a 62/b 63/c 22/dquote # "abc" - 2f/slash 64/d -_test-slice-abc-limit: - -_test-slice-a-space-b: - 22/dquote 61/a 20/space 62/b 22/dquote # "a b" -_test-slice-a-space-b-limit: - -_test-slice-a-dquote-b: - 22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b" -_test-slice-a-dquote-b-limit: - -_test-slice-a-newline-b: - 22/dquote 61/a 5c/backslash 6e/n 62/b 22/dquote # "a\nb" -_test-slice-a-newline-b-limit: - -# "abc/def"/ghi -_test-slice-literal-string: - 22/dquote - 61/a 62/b 63/c # abc - 2f/slash 64/d 65/e 66/f # /def - 22/dquote - 2f/slash 67/g 68/h 69/i # /ghi -_test-slice-literal-string-with-limit: - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/factorial b/subx/apps/factorial deleted file mode 100755 index b82be120..00000000 --- a/subx/apps/factorial +++ /dev/null Binary files differdiff --git a/subx/apps/factorial.subx b/subx/apps/factorial.subx deleted file mode 100644 index e4b7a057..00000000 --- a/subx/apps/factorial.subx +++ /dev/null @@ -1,117 +0,0 @@ -## compute the factorial of 5, and return the result in the exit code -# -# To run (from the subx directory): -# $ ./subx translate apps/factorial.subx -o apps/factorial -# $ ./subx run apps/factorial -# Expected result: -# $ echo $? -# 120 -# -# You can also run the automated test suite: -# $ ./subx run apps/factorial test -# Expected output: -# ........ -# Every '.' indicates a passing test. Failing tests get a 'F'. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: # run tests if necessary, compute `factorial(5)` if not - # initialize heap - # . Heap = new-segment(64KB) - # . . push args - 68/push Heap/imm32 - 68/push 0x10000/imm32/64KB - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # . 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . 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 -$run-main: - # - otherwise return factorial(5) - # . . push args - 68/push 5/imm32 - # . . call - e8/call factorial/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$main:end: - # 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 - -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 - # EAX = 1 (base case) - b8/copy-to-EAX 1/imm32 - # if (n <= 1) return - 81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 1/imm32 # compare *(EBP+8) - 7e/jump-if-<= $factorial:end/disp8 - # EBX = n-1 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 3/r32/EBX 8/disp8 . # copy *(EBP+8) to EBX - 81 5/subop/subtract 3/mod/direct 3/rm32/EBX . . . . . 1/imm32 # subtract from EBX - # EAX = factorial(n-1) - # . . push args - 53/push-EBX - # . . call - e8/call factorial/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # return n * factorial(n-1) - f7 4/subop/multiply 1/mod/*+disp8 5/rm32/EBP . . 8/disp8 . # multiply *(EBP+8) into EAX - # TODO: check for overflow -$factorial:end: - # . epilog - 5b/pop-to-EBX - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-factorial: - # factorial(5) - # . . push args - 68/push 5/imm32 - # . . call - e8/call factorial/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 120, msg) - # . . push args - 68/push "F - test-factorial"/imm32 - 68/push 0x78/imm32/expected-120 - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # end - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/handle b/subx/apps/handle deleted file mode 100755 index b6794474..00000000 --- a/subx/apps/handle +++ /dev/null Binary files differdiff --git a/subx/apps/handle.subx b/subx/apps/handle.subx deleted file mode 100644 index ba824f85..00000000 --- a/subx/apps/handle.subx +++ /dev/null @@ -1,412 +0,0 @@ -# A sketch of Mu-style handles or kinda-safe pointers, that add a modicum of -# checking to dynamically allocated memory. -# -# This approach avoids using 'allocate' directly in favor of two primitives: -# - 'new', which allocates some space (the 'payload'), stores the address -# along with an opaque 'alloc id' in a 'handle', and prepends the same -# alloc id to the payload. -# - 'lookup', which checks that the alloc id at the start of a handle matches -# the alloc id at the start of the payload before returning the address. -# -# Layout of a handle: -# offset 0: alloc id -# offset 4: address -# -# To run (from the subx directory): -# $ ./subx translate *.subx apps/handle.subx -o apps/handle -# $ ./subx run apps/handle -# Expected result is a successful lookup followed by a hard abort: -# lookup succeeded -# lookup failed -# (This file is a prototype. The 'tests' in it aren't real; failures are -# expected.) - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -# no Entry; the standard library runs all tests by default - -new: # ad : (address allocation-descriptor), n : int, out : (address handle) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # ECX = n+4 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX - 81 0/subop/add 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # add to ECX - # EAX = allocate(ad, ECX) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call allocate/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EDX = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX - # out->address = EAX - 89/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDX+4) - # if (EAX == 0) out->alloc_id = 0, return - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $new:continue/disp8 - c7 0/subop/copy 0/mod/indirect 2/rm32/EDX . . . . . 0/imm32 # copy to *EDX - eb/jump $new:end/disp8 -$new:continue: - # otherwise: - # ECX = *Next-alloc-id - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 1/r32/ECX Next-alloc-id/disp32 # copy *Next-alloc-id to ECX - # *EAX = *Next-alloc-id/ECX - 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX - # out->alloc_id = *Next-alloc-id - 89/copy 0/mod/indirect 2/rm32/EDX . . . 1/r32/ECX . . # copy ECX to *EDX - # increment *Next-alloc-id - ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # increment *Next-alloc-id -$new:end: - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-new: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var heap/EDX : (address allocation-descriptor) = {0, 0} - 68/push 0/imm32/limit - 68/push 0/imm32/curr - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # heap = new-segment(512) - # . . push args - 52/push-EDX - 68/push 0x200/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # var handle/ECX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # new(heap, 2, handle/ECX) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 52/push-EDX - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(handle->alloc_id, 0x34, msg) - # . . push args - 68/push "F - test-new: alloc id of handle"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(*handle->address, 0x34, msg) - # . . push args - 68/push "F - test-new: alloc id of payload"/imm32 - 68/push 0x34/imm32 - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(*Next-alloc-id, 0x35) - # . . push args - 68/push "F - test-new: next alloc id"/imm32 - 68/push 0x35/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # copy to *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -_pending-test-new-failure: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . *Next-alloc-id = 0x34 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 0x34/imm32 # copy to *Next-alloc-id - # define an allocation-descriptor with no space left - # . var ad/EAX : (address allocation-descriptor) = {0x10, 0x10} - 68/push 0x10/imm32/limit - 68/push 0x10/imm32/curr - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # . var handle/ECX = {random, random} - 68/push 1234/imm32/address - 68/push 5678/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # try to allocate - # . new(ad, 2, handle/ECX) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 50/push-EAX - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # handle should be cleared - # . check-ints-equal(handle->alloc_id, 0, msg) - # . . push args - 68/push "F - test-new-failure: alloc id of handle"/imm32 - 68/push 0/imm32 - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-ints-equal(handle->address, 0, msg) - # . . push args - 68/push "F - test-new-failure: address of handle"/imm32 - 68/push 0/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # Next-alloc-id should be unmodified - # . check-ints-equal(*Next-alloc-id, 0x34) - # . . push args - 68/push "F - test-new-failure: next alloc id"/imm32 - 68/push 0x34/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 # copy to *Next-alloc-id - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -lookup: # h : (handle T) -> EAX : (address T) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - as a proof of concept for future inlining, uses no general-purpose registers besides the output (EAX) - # EAX = handle - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX - # - inline { - # push handle->alloc_id - ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX - # EAX = handle->address (payload) - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 . # copy *(EAX+4) to EAX - # push handle->address - 50/push-EAX - # EAX = payload->alloc_id - 8b/copy 0/mod/indirect 0/rm32/EAX . . . . . . # copy *EAX to EAX - # if (EAX != handle->alloc_id) abort - 39/compare 1/mod/*+disp8 4/rm32/sib 4/base/ESP 4/index/none . 0/r32/EAX 4/disp8 . # compare *(ESP+4) and EAX - 75/jump-if-not-equal $lookup:abort/disp8 - # EAX = pop handle->address - 58/pop-to-EAX - # discard handle->alloc_id - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # add 4 - 05/add-to-EAX 4/imm32 - # - } - # - alternative consuming a second register { -#? # ECX = handle->alloc_id -#? 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX -#? # EAX = handle->address (payload) -#? 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 4/disp8 . # copy *(EAX+4) to EAX -#? # if (ECX != *EAX) abort -#? 39/compare 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # compare *EAX and ECX -#? 75/jump-if-not-equal $lookup:abort/disp8 -#? # add 4 to EAX -#? 05/add-to-EAX 4/imm32 - # - } - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$lookup:abort: - # . _write(2/stderr, msg) - # . . push args - 68/push "lookup failed\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32/exit-status - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -test-lookup-success: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - # var heap/EBX : (address allocation-descriptor) = {0, 0} - 68/push 0/imm32/limit - 68/push 0/imm32/curr - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX - # heap = new-segment(512) - # . . push args - 53/push-EBX - 68/push 0x200/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # var handle/ECX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var old_top/EDX = heap->curr - 8b/copy 0/mod/indirect 3/rm32/EBX . . . 2/r32/EDX . . # copy *EBX to EDX - # new(heap, 2, handle) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 53/push-EBX - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # EAX = lookup(handle) - # . . push args - 51/push-ECX - # . . call - e8/call lookup/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # EAX contains old top of heap, except skipping the alloc id in the payload - # . check-ints-equal(EAX, old_top+4, msg) - # . . push args - 68/push "F - test-lookup-success"/imm32 - 81 0/subop/add 3/mod/direct 2/rm32/EDX . . . . . 4/imm32 # add to EDX - 52/push-EDX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # write(2/stderr, "lookup succeeded\n") - # . . push args - 68/push "lookup succeeded\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-lookup-failure: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var heap/ESI : (address allocation-descriptor) = {0, 0} - 68/push 0/imm32/limit - 68/push 0/imm32/curr - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # heap = new-segment(512) - # . . push args - 56/push-ESI - 68/push 0x200/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # var h1/ECX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var old_top/EBX = heap->curr - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy *ESI to EBX - # first allocation, to h1 - # . new(heap, 2, h1) - # . . push args - 51/push-ECX - 68/push 2/imm32/size - 56/push-ESI - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # reset heap->curr to mimic reclamation - 89/copy 0/mod/indirect 6/rm32/ESI . . . 3/r32/EBX . . # copy EBX to *ESI - # second allocation that returns the same address as the first - # var h2/EDX = {0, 0} - 68/push 0/imm32/address - 68/push 0/imm32/alloc-id - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # . new(heap, 2, h2) - # . . push args - 52/push-EDX - 68/push 2/imm32/size - 56/push-ESI - # . . call - e8/call new/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(h1->address, h2->address, msg) - # . . push args - 68/push "F - test-lookup-failure"/imm32 - ff 6/subop/push 1/mod/*+disp8 2/rm32/ECX . . . . 4/disp8 . # push *(EDX+4) - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # lookup(h1) should crash - # . . push args - 51/push-ECX - # . . call - e8/call lookup/disp32 - # should never get past this point - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # clean up - # . *Next-alloc-id = 1 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Next-alloc-id/disp32 1/imm32 # copy to *Next-alloc-id - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -# Monotonically increasing counter for calls to 'new' -Next-alloc-id: - 1/imm32 - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/hex b/subx/apps/hex deleted file mode 100755 index 84575cfd..00000000 --- a/subx/apps/hex +++ /dev/null Binary files differdiff --git a/subx/apps/hex.subx b/subx/apps/hex.subx deleted file mode 100644 index a24c5a2e..00000000 --- a/subx/apps/hex.subx +++ /dev/null @@ -1,1515 +0,0 @@ -# Read a text file containing whitespace-separated pairs of ascii hex bytes -# from stdin, and convert them into binary bytes (octets) on stdout. Ignore -# comments between '#' and newline. -# -# To run (from the subx/ directory): -# $ ./subx translate *.subx apps/hex.subx -o apps/hex -# $ echo '80 81 82 # comment' |./subx run apps/hex |xxd - -# Expected output: -# 00000000: 8081 82 -# -# Only hex bytes and comments are permitted. Outside of comments all words -# must be exactly 2 characters long and contain only characters [0-9a-f]. No -# uppercase hex. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: # run tests if necessary, convert stdin if not - # initialize heap - # . Heap = new-segment(64KB) - # . . push args - 68/push Heap/imm32 - 68/push 0x10000/imm32/64KB - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # . 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - otherwise convert stdin - # var ed/EAX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # configure ed to really exit() - # . ed->target = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # return convert(Stdin, 1/stdout, 2/stderr, ed) - # . . push args - 50/push-EAX/ed - 68/push Stderr/imm32 - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# the main entry point -convert: # in : (address buffered-file), out : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> <void> - # pseudocode: - # while true - # EAX = convert-next-octet(in, err, ed) - # if (EAX == Eof) break - # write-byte-buffered(out, AL) - # flush(out) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX -$convert:loop: - # EAX = convert-next-octet(in, err, ed) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 == Eof) break - 3d/compare-EAX-and 0xffffffff/imm32/Eof - 74/jump-if-equal $convert:loop-end/disp8 - # write-byte-buffered(out, AL) - # . . push args - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # loop - eb/jump $convert:loop/disp8 -$convert:loop-end: - # flush(out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$convert:end: - # . restore registers - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# read bytes from 'in' until a sequence of two lowercase hex (0-9, a-f) bytes -# skip spaces and newlines -# on '#' skip bytes until newline -# raise an error and abort on all other unexpected bytes -# return in EAX an _octet_ containing the binary value of the two hex characters -# return Eof on reaching end of file -convert-next-octet: # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-Eof/EAX - # pseudocode: - # EAX = scan-next-byte(in, err, ed) - # if (EAX == Eof) return - # ECX = from-hex-char(EAX) - # EAX = scan-next-byte(in, err, ed) - # if (EAX == Eof) error("partial byte found.") - # EAX = from-hex-char(EAX) - # EAX = (ECX << 4) | EAX - # return - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - # EAX = scan-next-byte(in, err, ed) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call scan-next-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # if (EAX == Eof) return - 3d/compare-EAX-and 0xffffffff/imm32/Eof - 74/jump-if-equal $convert-next-octet:end/disp8 - # EAX = from-hex-char(EAX) - e8/call from-hex-char/disp32 - # ECX = EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX - # EAX = scan-next-byte(in, err, ed) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call scan-next-byte/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # if (EAX == Eof) error(ed, err, "partial byte found.") - 3d/compare-EAX-and 0xffffffff/imm32/Eof - 75/jump-if-not-equal $convert-next-octet:convert/disp8 - # . error-byte(ed, err, msg, '.') # reusing error-byte to avoid creating _yet_ another helper - # . . push args - 68/push 0x2e/imm32/period/dummy - 68/push "convert-next-octet: partial byte found"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call error-byte/disp32 # never returns -$convert-next-octet:convert: - # EAX = from-hex-char(EAX) - e8/call from-hex-char/disp32 - # EAX = (ECX << 4) | EAX - # . ECX <<= 4 - c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX . . . . . 4/imm8 # shift ECX left by 4 bits - # . EAX |= ECX - 09/or 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # EAX = bitwise OR with ECX -$convert-next-octet:end: - # . restore registers - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-next-octet: - # - check that the first two bytes of the input are assembled into the resulting octet - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to "abc" - # . write(_test-stream, "abc") - # . . push args - 68/push "abc"/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 - # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-convert-next-octet - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call convert-next-octet/disp32 - # registers except ESP may be clobbered at this point - # pop args to convert-next-octet - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that convert-next-octet didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-convert-next-octet: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-convert-next-octet:end/disp8 - # check-ints-equal(EAX, 0xab, msg) - # . . push args - 68/push "F - test-convert-next-octet"/imm32 - 68/push 0xab/imm32/ab - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-convert-next-octet:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-convert-next-octet-handles-Eof: - # - check that reaching end of file returns Eof - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # don't initialize '_test-stream' - # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-convert-next-octet - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call convert-next-octet/disp32 - # registers except ESP may be clobbered at this point - # pop args to convert-next-octet - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that convert-next-octet didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-convert-next-octet: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-convert-next-octet-handles-Eof:end/disp8 - # check-ints-equal(EAX, Eof, msg) - # . . push args - 68/push "F - test-convert-next-octet-handles-Eof"/imm32 - 68/push 0xffffffff/imm32/Eof - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-convert-next-octet-handles-Eof:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-convert-next-octet-aborts-on-single-hex-byte: - # - check that a single unaccompanied hex byte aborts - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to "a" - # . write(_test-stream, "a") - # . . push args - 68/push "a"/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 - # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-convert-next-octet - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call convert-next-octet/disp32 - # registers except ESP may be clobbered at this point - # pop args to convert-next-octet - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that convert-next-octet aborted - # . check-ints-equal(ed->value, 2, msg) - # . . push args - 68/push "F - test-convert-next-octet-aborts-on-single-hex-byte: unexpected abort"/imm32 - 68/push 2/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 -$test-convert-next-octet-aborts-on-single-hex-byte:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -# read whitespace until a hex byte, and return it -# return Eof if file ends without finding a hex byte -# on '#' skip all bytes until newline -# abort on any other byte -scan-next-byte: # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-Eof/EAX - # pseudocode: - # while true - # EAX = read-byte-buffered(in) - # if (EAX == Eof) 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 - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers -$scan-next-byte:loop: - # EAX = read-byte-buffered(in) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # if (EAX == Eof) return EAX - 3d/compare-with-EAX 0xffffffff/imm32/Eof - 74/jump-if-equal $scan-next-byte:end/disp8 - # if (is-hex-digit?(EAX)) return EAX - # . save EAX for now - 50/push-EAX - # . is-hex-digit?(EAX) - # . . push args - 50/push-EAX - # . . call - e8/call is-hex-digit?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . compare with 'false' - 3d/compare-with-EAX 0/imm32 - # . restore EAX (does not affect flags) - 58/pop-to-EAX - # . check whether to return - 75/jump-if-not-equal $scan-next-byte:end/disp8 -$scan-next-byte:check1: - # if (EAX == ' ') continue - 3d/compare-EAX-and 0x20/imm32/space - 74/jump-if-equal $scan-next-byte:loop/disp8 - # if (EAX == '\t') continue - 3d/compare-EAX-and 9/imm32/tab - 74/jump-if-equal $scan-next-byte:loop/disp8 - # if (EAX == '\n') continue - 3d/compare-EAX-and 0xa/imm32/newline - 74/jump-if-equal $scan-next-byte:loop/disp8 -$scan-next-byte:check2: - # 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) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call skip-until-newline/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - eb/jump $scan-next-byte:loop/disp8 -$scan-next-byte:check3: - # otherwise error-byte(ed, err, msg, EAX) - # . . push args - 50/push-EAX - 68/push "scan-next-byte: invalid byte"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call error-byte/disp32 # never returns -$scan-next-byte:end: - # . restore registers - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte: - # - check that the first byte of the input is returned - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to "abc" - # . write(_test-stream, "abc") - # . . push args - 68/push "abc"/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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte:end/disp8 - # check-ints-equal(EAX, 0x61/a, msg) - # . . push args - 68/push "F - test-scan-next-byte"/imm32 - 68/push 0x61/imm32/a - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-skips-whitespace: - # - check that the first byte after whitespace is returned - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to input with leading whitespace - # . write(_test-stream, text) - # . . push args - 68/push " abc"/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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-whitespace: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte-skips-whitespace:end/disp8 - # check-ints-equal(EAX, 0x61/a, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-whitespace"/imm32 - 68/push 0x61/imm32/a - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte-skips-whitespace:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-skips-comment: - # - check that the first byte after a comment (and newline) is returned - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to input with leading comment - # . write(_test-stream, comment) - # . . push args - 68/push "#x\n"/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 - # . write(_test-stream, real text) - # . . 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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-comment: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte-skips-comment:end/disp8 - # check-ints-equal(EAX, 0x61/a, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-comment"/imm32 - 68/push 0x61/imm32/a - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte-skips-comment:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-skips-comment-and-whitespace: - # - check that the first byte after a comment and any further whitespace is returned - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to input with leading comment and more whitespace after newline - # . write(_test-stream, comment) - # . . push args - 68/push "#x\n"/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 - # . write(_test-stream, real text) - # . . 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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-comment-and-whitespace: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte-skips-comment-and-whitespace:end/disp8 - # check-ints-equal(EAX, 0x61/a, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-comment-and-whitespace"/imm32 - 68/push 0x61/imm32/a - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte-skips-comment-and-whitespace:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-skips-whitespace-and-comment: - # - check that the first byte after any whitespace and comments is returned - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to input with leading whitespace and comment - # . write(_test-stream, comment) - # . . push args - 68/push " #x\n"/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 - # . write(_test-stream, real text) - # . . 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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-whitespace-and-comment: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte-skips-whitespace-and-comment:end/disp8 - # check-ints-equal(EAX, 0x61/a, msg) - # . . push args - 68/push "F - test-scan-next-byte-skips-whitespace-and-comment"/imm32 - 68/push 0x61/imm32/a - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte-skips-whitespace-and-comment:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-reads-final-byte: - # - check that the final byte in input is returned - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to input with single character - # . write(_test-stream, character) - # . . push args - 68/push "a"/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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte-reads-final-byte: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte-reads-final-byte:end/disp8 - # check-ints-equal(EAX, 0x61/a, msg) - # . . push args - 68/push "F - test-scan-next-byte-reads-final-byte"/imm32 - 68/push 0x61/imm32/a - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte-reads-final-byte:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-handles-Eof: - # - check that the right sentinel value is returned when there's no data remaining to be read - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # leave '_test-stream' empty - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte didn't abort - # . check-ints-equal(ed->value, 0, msg) - # . . push args - 68/push "F - test-scan-next-byte-handles-Eof: unexpected abort"/imm32 - 68/push 0/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 - # return if abort - 81 7/subop/compare 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 0/imm32 # compare *(ECX+4) - 75/jump-if-not-equal $test-scan-next-byte-handles-Eof:end/disp8 - # check-ints-equal(EAX, Eof, msg) - # . . push args - 68/push "F - test-scan-next-byte-handles-Eof"/imm32 - 68/push 0xffffffff/imm32/Eof - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-scan-next-byte-handles-Eof:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -test-scan-next-byte-aborts-on-invalid-byte: - # - check that the a bad byte immediately aborts - # 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) - # . . 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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) - # . . 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 - # . clear-stream(_test-error-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-error-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to "x" - # . write(_test-stream, "x") - # . . push args - 68/push "x"/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 - # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below - # . var ed/ECX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . tailor-exit-descriptor(ed, 12) - # . . push args - 68/push 0xc/imm32/nbytes-of-args-for-scan-next-byte - 51/push-ECX/ed - # . . call - e8/call tailor-exit-descriptor/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EAX = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed) - # . . push args - 51/push-ECX/ed - 68/push _test-error-buffered-file/imm32 - 68/push _test-buffered-file/imm32 - # . . call - e8/call scan-next-byte/disp32 - # registers except ESP may be clobbered at this point - # pop args to scan-next-byte - # . . discard first 2 args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . restore ed - 59/pop-to-ECX - # check that scan-next-byte aborted - # . check-ints-equal(ed->value, 2, msg) - # . . push args - 68/push "F - test-scan-next-byte-aborts-on-invalid-byte"/imm32 - 68/push 2/imm32 - # . . push ed->value - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+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 -$test-scan-next-byte-aborts-on-invalid-byte:end: - # . epilog - # don't restore ESP from EBP; manually reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 5d/pop-to-EBP - c3/return - -skip-until-newline: # in : (address buffered-file) -> <void> - # pseudocode: - # push EAX - # while true - # EAX = read-byte-buffered(in) - # if (EAX == Eof) break - # if (EAX == 0x0a) break - # pop EAX - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX -$skip-until-newline:loop: - # . EAX = read-byte-buffered(in) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX == Eof) break - 3d/compare-EAX-and 0xffffffff/imm32/Eof - 74/jump-if-equal $skip-until-newline:end/disp8 - # . if (EAX != 0xa/newline) loop - 3d/compare-EAX-and 0xa/imm32/newline - 75/jump-if-not-equal $skip-until-newline:loop/disp8 -$skip-until-newline:end: - # . restore registers - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-skip-until-newline: - # - check that the read pointer points after the newline - # 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) - # . . push args - b8/copy-to-EAX _test-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize '_test-stream' to "abc\nde" - # . write(_test-stream, "abc") - # . . push args - 68/push "abc\n"/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 - # . write(_test-stream, "de") - # . . push args - 68/push "de"/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 - # skip-until-newline(_test-buffered-file) - # . . push args - 68/push _test-buffered-file/imm32 - # . . call - e8/call skip-until-newline/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(_test-buffered-file->read, 4, msg) - # . . push args - 68/push "F - test-skip-until-newline"/imm32 - 68/push 4/imm32 - b8/copy-to-EAX _test-buffered-file/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . end - c3/return - -== data - -_test-error-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # line - 0x80/imm32 # 128 bytes - # data (8 lines x 16 bytes/line) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# a test buffered file for _test-error-stream -_test-error-buffered-file: - # file descriptor or (address stream) - _test-error-stream/imm32 - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 6/imm32 - # data - 00 00 00 00 00 00 # 6 bytes - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/pack b/subx/apps/pack deleted file mode 100755 index 720ba3ea..00000000 --- a/subx/apps/pack +++ /dev/null Binary files differdiff --git a/subx/apps/pack.subx b/subx/apps/pack.subx deleted file mode 100644 index 61a837ba..00000000 --- a/subx/apps/pack.subx +++ /dev/null @@ -1,5986 +0,0 @@ -# Read a text file of SubX instructions from stdin, and convert it into a list -# of whitespace-separated ascii hex bytes on stdout. Label definitions and -# uses are left untouched. -# -# To run (from the subx/ directory): -# $ ./subx translate *.subx apps/pack.subx -o apps/pack -# $ echo '05/add-to-EAX 0x20/imm32' |./subx run apps/pack -# Expected output: -# 05 20 00 00 00 # 05/add-to-EAX 0x20/imm32 -# The original instruction gets included as a comment at the end of each -# converted line. -# -# There's zero error-checking. For now we assume the input program is valid. -# We'll continue to rely on the C++ version for error messages. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: # run tests if necessary, convert stdin if not - # initialize heap - # . Heap = new-segment(64KB) - # . . push args - 68/push Heap/imm32 - 68/push 0x10000/imm32/64KB - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - - # . 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() - # . 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - otherwise convert stdin - # var ed/EAX : exit-descriptor - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # subtract from ESP - 89/copy 3/mod/direct 0/rm32/EAX . . . 4/r32/ESP . . # copy ESP to EAX - # configure ed to really exit() - # . ed->target = 0 - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX - # return convert(Stdin, 1/stdout, 2/stderr, ed) - # . . push args - 50/push-EAX/ed - 68/push Stderr/imm32 - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# - big picture -# We'll operate on each line/instruction in isolation. That way we only need to -# allocate memory for converting a single instruction. -# -# To pack an entire file, convert every segment in it -# To convert a code segment, convert every instruction (line) until the next segment header -# To convert a non-data segment, convert every word until the next segment header -# -# primary state: line -# stream of 512 bytes; abort if it ever overflows - -# conceptual hierarchy within a line: -# line = words separated by ' ', maybe followed by comment starting with '#' -# word = datum until '/', then 0 or more metadata separated by '/' -# -# we won't bother saving the internal structure of lines; reparsing should be cheap using three primitives: -# next-token(stream, delim char) -> slice (start, end pointers) -# next-token-from-slice(start, end, delim char) -> slice -# slice-equal?(slice, string) - -convert: # in : (address buffered-file), out : (address buffered-file) -> <void> - # pseudocode: - # var line = new-stream(512, 1) - # var in-code? = false - # while true - # clear-stream(line) - # read-line-buffered(in, line) - # if (line->write == 0) break # end of file - # var word-slice = next-word(line) - # if slice-empty?(word-slice) # whitespace - # write-stream-data(out, line) - # else if (slice-equal?(word-slice, "==")) - # word-slice = next-word(line) - # in-code? = slice-equal?(word-slice, "code") - # write-stream-data(out, line) - # else if (in-code?) - # rewind-stream(line) - # convert-instruction(line, out) - # else - # rewind-stream(line) - # convert-data(line, out) - # flush(out) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - # var line/ECX : (address stream byte) = stream(512) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP - 68/push 0x200/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var word-slice/EDX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # var in-code?/EBX = false - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX -$convert:loop: - # clear-stream(line) - # . . 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 - # read-line-buffered(in, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-line-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:check0: - # if (line->write == 0) break - 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX - 0f 84/jump-if-equal $convert:break/disp32 -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? 51/push-ECX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # next-word(line, word-slice) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:check1: - # if (slice-empty?(word-slice)) write-stream-data(out, line) - # . EAX = slice-empty?(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) write-stream-data(out, line) - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $convert:pass-through/disp32 -$convert:check2: -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 52/push-EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # if (!slice-equal?(word-slice, "==")) goto next check - # . EAX = slice-equal?(word-slice, "==") - # . . push args - 68/push "=="/imm32 - 52/push-EDX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto check3 - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $convert:check3/disp32 - # word-slice = next-word(line) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump segment name {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 52/push-EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # in-code? = slice-equal?(word-slice, "code") - # . . push args - 68/push "code"/imm32 - 52/push-EDX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . . in-code? = EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX - # write-stream-data(out, line) - eb/jump $convert:pass-through/disp8 -$convert:check3: - # else rewind-stream(line) - # . rewind-stream(line) - # . . push args - 51/push-ECX - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # if (in-code? != 0) convert-instruction(line, out) - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX - 74/jump-if-equal $convert:data/disp8 -$convert:code: - # . convert-instruction(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 51/push-ECX - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . loop - e9/jump $convert:loop/disp32 -$convert:data: - # else convert-data(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 51/push-ECX - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . loop - e9/jump $convert:loop/disp32 -$convert:pass-through: - # write-stream-data(out, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . loop - e9/jump $convert:loop/disp32 -$convert:break: - # flush(out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$convert:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP - # . restore registers - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-passes-empty-lines-through: - # if a line is empty, pass it along unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # write nothing to input - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "", msg) - # . . push args - 68/push "F - test-convert-passes-empty-lines-through"/imm32 - 68/push ""/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-passes-lines-with-just-whitespace-through: - # if a line is empty, pass it along unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, " ") - # . . push args - 68/push " "/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, " ", msg) - # . . push args - 68/push "F - test-convert-passes-with-just-whitespace-through"/imm32 - 68/push " "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-passes-segment-headers-through: - # if a line starts with '==', pass it along unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "== abcd 0x1") - # . . push args - 68/push "== abcd 0x1"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "== abcd 0x1", msg) - # . . push args - 68/push "F - test-convert-passes-segment-headers-through"/imm32 - 68/push "== abcd 0x1"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-in-data-segment: - # correctly process lines in the data segment - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # == code 0x1 - # == data 0x2 - # 3 4/imm32 - # . write(_test-input-stream, "== code 0x1") - # . . push args - 68/push "== code 0x1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x2\n") - # . . push args - 68/push "== data 0x2\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "3 4/imm32\n") - # . . push args - 68/push "3 4/imm32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output -#? # debug print {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== code 0x1", msg) - # . . push args - 68/push "F - test-convert-in-data-segment/0"/imm32 - 68/push "== code 0x1"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== data 0x2", msg) - # . . push args - 68/push "F - test-convert-in-data-segment/1"/imm32 - 68/push "== data 0x2"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "03 04 00 00 00 ", msg) - # . . push args - 68/push "F - test-convert-in-data-segment/2"/imm32 - 68/push "03 04 00 00 00 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-code-and-data-segments: - # correctly process lines in both code and data segments - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # == code 0x1 - # e8/call 20/disp32 - # 68/push 0x20/imm8 - # == data 0x2 - # 3 4/imm32 - # . write(_test-input-stream, "== code 0x1\n") - # . . push args - 68/push "== code 0x1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "e8/call 20/disp32\n") - # . . push args - 68/push "e8/call 20/disp32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "68/push 0x20/imm8\n") - # . . push args - 68/push "68/push 0x20/imm8\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x2\n") - # . . push args - 68/push "== data 0x2\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "3 4/imm32\n") - # . . push args - 68/push "3 4/imm32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # == code 0x1 - # e8 20 00 00 00 # e8/call 20/disp32 - # 68 20 # 68/push 0x20/imm8 - # == data 0x2 - # 03 04 00 00 00 -#? # debug print {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== code 0x1", msg) - # . . push args - 68/push "F - test-convert-code-and-data-segments/0"/imm32 - 68/push "== code 0x1"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "e8 20 00 00 00 # e8/call 20/disp32", msg) - # . . push args - 68/push "F - test-convert-code-and-data-segments/1"/imm32 - 68/push "e8 20 00 00 00 # e8/call 20/disp32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "68 20 # 68/push 0x20/imm8", msg) - # . . push args - 68/push "F - test-convert-code-and-data-segments/2"/imm32 - 68/push "68 20 # 68/push 0x20/imm8"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== data 0x2", msg) - # . . push args - 68/push "F - test-convert-code-and-data-segments/3"/imm32 - 68/push "== data 0x2"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "03 04 00 00 00 ", msg) - # . . push args - 68/push "F - test-convert-code-and-data-segments/4"/imm32 - 68/push "03 04 00 00 00 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -convert-data: # line : (address stream byte), out : (address buffered-file) -> <void> - # pseudocode: - # var word-slice = {0, 0} - # while true - # word-slice = next-word(line) - # if slice-empty?(word-slice) # end of file (maybe including trailing whitespace) - # break # skip emitting some whitespace - # if slice-starts-with?(word-slice, "#") # comment - # write-slice-buffered(out, word-slice) - # return - # if slice-ends-with?(word-slice, ":") # label - # write-stream-data(out, line) - # return - # if has-metadata?(word-slice, "imm32") - # emit(out, word-slice, 4) - # # disp32 is not permitted in data segments, and anything else is only a byte long - # else - # emit(out, word-slice, 1) - # write-buffered(out, "\n") - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # write-stream(2/stderr, line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$convert-data:loop: - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 51/push-ECX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$convert-data:check0: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $convert-data:break/disp32 -$convert-data:check-for-comment: - # if (slice-starts-with?(word-slice, "#")) - # . start/EDX = word-slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 0/r32/AL . . # copy byte at *EDX to AL - # . if (EAX != '#') goto next check - 3d/compare-EAX-and 0x23/imm32/hash - 75/jump-if-not-equal $convert-data:check-for-label/disp8 -$convert-data:comment: - # write-slice-buffered(out, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # return - 0f 85/jump-if-not-equal $convert-data:end/disp32 -$convert-data:check-for-label: - # if (slice-ends-with?(word-slice, ":")) - # . end/EDX = word-slice->end - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX - # . c/EAX = *(end-1) - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/AL -1/disp8 . # copy byte at *ECX to AL - # . if (EAX != ':') goto next check - 3d/compare-EAX-and 0x3a/imm32/colon - 75/jump-if-not-equal $convert-data:check-for-imm32/disp8 -$convert-data:label: - # write-stream-data(out, line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # return - 75/jump-if-not-equal $convert-data:end/disp8 -$convert-data:check-for-imm32: - # if (has-metadata?(word-slice, "imm32")) - # . EAX = has-metadata?(ECX, "imm32") - # . . push args - 68/push "imm32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) process as a single byte - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $convert-data:single-byte/disp8 -$convert-data:imm32: - # emit(out, word-slice, 4) - # . . push args - 68/push 4/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - e9/jump $convert-data:loop/disp32 -$convert-data:single-byte: - # emit(out, word-slice, 1) - # . . push args - 68/push 1/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - e9/jump $convert-data:loop/disp32 -$convert-data:break: - # write-buffered(out, "\n") - # . . push args - 68/push "\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert-data:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-passes-comments-through: - # if a line starts with '#', pass it along unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "# abcd") - # . . push args - 68/push "# abcd"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "# abcd", msg) - # . . push args - 68/push "F - test-convert-data-passes-comments-through"/imm32 - 68/push "# abcd"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-passes-labels-through: - # if the first word ends with ':', pass along the entire line unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "ab: # cd") - # . . push args - 68/push "ab: # cd"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "ab: # cd", msg) - # . . push args - 68/push "F - test-convert-data-passes-labels-through"/imm32 - 68/push "ab: # cd"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-passes-names-through: - # If a word is a valid name, just emit it unchanged. - # Later phases will deal with it. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "abcd/imm32") - # . . push args - 68/push "abcd/imm32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "abcd/imm32 \n", msg) - # . . push args - 68/push "F - test-convert-data-passes-names-through"/imm32 - 68/push "abcd/imm32 \n"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-handles-imm32: - # If a word has the /imm32 metadata, emit it in 4 bytes. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "30/imm32") - # . . push args - 68/push "30/imm32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that 4 bytes were written - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "30 00 00 00 \n", msg) - # . . push args - 68/push "F - test-convert-data-handles-imm32"/imm32 - 68/push "30 00 00 00 \n"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-handles-single-byte: - # Any metadata but /imm32 will emit a single byte. - # Data segments can't have /disp32, and SubX doesn't support 16-bit operands. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "30/imm16") - # . . push args - 68/push "30/imm16"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that a single byte was written (imm16 is not a valid operand type) - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "30 \n", msg) - # . . push args - 68/push "F - test-convert-data-handles-single-byte"/imm32 - 68/push "30 \n"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-multiple-bytes: - # Multiple single-byte words in input stream get processed one by one. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "1 2") - # . . push args - 68/push "1 2"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "01 02 \n", msg) - # . . push args - 68/push "F - test-convert-data-multiple-bytes"/imm32 - 68/push "01 02 \n"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-byte-then-name: - # Single-byte word followed by valid name get processed one by one. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "30 abcd/o") - # . . push args - 68/push "30 abcd/o"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "30 abcd/o \n", msg) - # . . push args - 68/push "F - test-convert-data-byte-then-name"/imm32 - 68/push "30 abcd/o \n"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-multiple-words: - # Multiple words in input stream get processed one by one. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "30 abcd/o 42e1/imm32") - # . . push args - 68/push "30 abcd/o 42e1/imm32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "30 abcd/o 42 e1 00 00 \n", msg) - # . . push args - 68/push "F - test-convert-data-multiple-words"/imm32 - 68/push "30 abcd/o e1 42 00 00 \n"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-data-trailing-comment: - # Trailing comments in data segment get appropriately ignored. - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "30/imm32 # comment") - # . . push args - 68/push "30/imm32 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-data(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "30 00 00 00 # comment", msg) - # . . push args - 68/push "F - test-convert-data-trailing-comment"/imm32 - 68/push "30 00 00 00 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# pack an instruction, following the C++ version -# -# zero error handling at the moment (continuing to rely on the C++ version for that): -# missing fields are always 0-filled -# bytes never mentioned are silently dropped; if you don't provide /mod, /rm32 or /r32 you don't get a 0 ModR/M byte. You get *no* ModR/M byte. -# may pick up any of duplicate operands in an instruction -# silently drop extraneous operands -# unceremoniously abort on non-numeric operands except disp or imm -# opcodes must be lowercase and zero padded -# opcodes with misleading operand metadata may get duplicated as operands as well. don't rely on this. -convert-instruction: # line : (address stream byte), out : (address buffered-file) -> <void> - # pseudocode: - # # some early exits - # var word-slice = next-word(line) - # if slice-empty?(word-slice) - # write-stream-data(out, line) - # return - # if slice-starts-with?(word-slice, "#") - # write-stream-data(out, line) - # return - # if slice-ends-with?(word-slice, ":") - # write-stream-data(out, line) - # return - # # really convert - # emit-opcodes(line, out) - # emit-modrm(line, out) - # emit-sib(line, out) - # emit-disp(line, out) - # emit-imm(line, out) - # emit-line-in-comment(line, out) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert-instruction:check0: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) pass through - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $convert-instruction:pass-through/disp8 -$convert-instruction:check1: - # if (slice-starts-with?(word-slice, "#")) write-stream-data(out, line) - # . start/EDX = word-slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 0/r32/AL . . # copy byte at *EDX to AL - # . if (EAX == '#') pass through - 3d/compare-EAX-and 0x23/imm32/hash - 74/jump-if-equal $convert-instruction:pass-through/disp8 -$convert-instruction:check2: - # if (slice-ends-with?(word-slice, ":")) write-stream-data(out, line) - # . end/EDX = word-slice->end - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX - # . c/EAX = *(end-1) - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/AL -1/disp8 . # copy byte at *ECX to AL - # . if (EAX == ':') pass through - 3d/compare-EAX-and 0x3a/imm32/colon - 75/jump-if-not-equal $convert-instruction:really-convert/disp8 -$convert-instruction:pass-through: - # write-stream-data(out, line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # return - eb/jump $convert-instruction:end/disp8 -$convert-instruction:really-convert: - # emit-opcodes(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-opcodes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-modrm(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-modrm/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-sib(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-sib/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-disp(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-disp/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-imm(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-imm/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # emit-line-in-comment(line, out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-line-in-comment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert-instruction:end: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-opcodes: # line : (address stream byte), out : (address buffered-file) -> <void> - # opcodes occupy 1-3 bytes: - # xx - # 0f xx - # f2 xx - # f3 xx - # f2 0f xx - # f3 0f xx - # - # pseudocode: - # rewind-stream(line) - # - # var op1 = next-word(line) - # if (slice-empty?(op1) || slice-starts-with?(op1, "#")) return - # op1 = next-token-from-slice(op1->start, op1->end, "/") - # write-slice-buffered(out, op1) - # if !slice-equal?(op1, "0f") && !slice-equal?(op1, "f2") && !slice-equal?(op1, "f3") - # return - # - # var op2 = next-word(line) - # if (slice-empty?(op2) || slice-starts-with?(op2, "#")) return - # op2 = next-token-from-slice(op2->start, op2->end, "/") - # write-slice-buffered(out, op2) - # if slice-equal?(op1, "0f") - # return - # if !slice-equal?(op2, "0f") - # return - # - # var op3 = next-word(line) - # if (slice-empty?(op3) || slice-starts-with?(op3, "#")) return - # op3 = next-token-from-slice(op3->start, op3->end, "/") - # write-slice-buffered(out, op3) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - # var op1/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var op2/EDX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$emit-opcodes:op1: - # next-word(line, op1) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (slice-empty?(op1)) return - # . EAX = slice-empty?(op1) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) return - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-opcodes:end/disp32 - # if (slice-starts-with?(op1, "#")) return - # . start/EBX = op1->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 3/r32/EBX . . # copy *ECX to EBX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at *EBX to AL - # . if (EAX == '#') return - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-opcodes:end/disp32 - # op1 = next-token-from-slice(op1->start, op1->end, '/') - # . . push args - 51/push-ECX - 68/push 0x2f/imm32/slash - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 4/disp8 . # push *(ECX+4) - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # write-slice-buffered(out, op1) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-buffered(out, " ") - # . . push args - 68/push " "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (slice-equal?(op1, "0f")) goto op2 - # . EAX = slice-equal?(op1, "0f") - # . . push args - 68/push "0f"/imm32 - 51/push-ECX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) goto op2 - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $emit-opcodes:op2/disp8 - # if (slice-equal?(op1, "f2")) goto op2 - # . EAX = slice-equal?(op1, "f2") - # . . push args - 68/push "f2"/imm32 - 51/push-ECX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) goto op2 - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $emit-opcodes:op2/disp8 - # if (slice-equal?(op1, "f3")) goto op2 - # . EAX = slice-equal?(op1, "f3") - # . . push args - 68/push "f3"/imm32 - 51/push-ECX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) goto op2 - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $emit-opcodes:op2/disp8 - # otherwise return - e9/jump $emit-opcodes:end/disp32 -$emit-opcodes:op2: - # next-word(line, op2) - # . . push args - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (slice-empty?(op2)) return - # . EAX = slice-empty?(op2) - # . . push args - 52/push-EDX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) return - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-opcodes:end/disp32 - # if (slice-starts-with?(op2, "#")) return - # . start/EBX = op2->start - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy *EDX to EBX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at *EBX to AL - # . if (EAX == '#') return - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-opcodes:end/disp32 - # op2 = next-token-from-slice(op2->start, op2->end, '/') - # . . push args - 52/push-EDX - 68/push 0x2f/imm32/slash - ff 6/subop/push 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # push *(EDX+4) - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # write-slice-buffered(out, op2) - # . . push args - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-buffered(out, " ") - # . . push args - 68/push " "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (slice-equal?(op1, "0f")) return - # . EAX = slice-equal?(op1, "0f") - # . . push args - 68/push "0f"/imm32 - 51/push-ECX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-opcodes:end/disp32 - # if (!slice-equal?(op2, "0f")) return - # . EAX = slice-equal?(op2, "0f") - # . . push args - 68/push "0f"/imm32 - 52/push-EDX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) return - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $emit-opcodes:end/disp32 -$emit-opcodes:op3: - # next-word(line, op3) # reuse op2/EDX - # . . push args - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (slice-empty?(op3)) return - # . EAX = slice-empty?(op3) - # . . push args - 52/push-EDX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) return - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-opcodes:end/disp32 - # if (slice-starts-with?(op3, "#")) return - # . start/EBX = op2->start - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy *EDX to EBX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 3/rm32/EBX . . . 0/r32/AL . . # copy byte at *EBX to AL - # . if (EAX == '#') return - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-opcodes:end/disp32 - # op3 = next-token-from-slice(op3->start, op3->end, '/') - # . . push args - 52/push-EDX - 68/push 0x2f/imm32/slash - ff 6/subop/push 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # push *(EDX+4) - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # write-slice-buffered(out, op3) - # . . push args - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-buffered(out, " ") - # . . push args - 68/push " "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$emit-opcodes:end: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # . restore registers - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-modrm: # line : (address stream byte), out : (address buffered-file) -> <void> - # pseudocode: - # rewind-stream(line) - # var has-modrm? = false, mod = 0, rm32 = 0, r32 = 0 - # var word-slice = {0, 0} - # while true - # word-slice = next-word(line) - # if (slice-empty?(word-slice)) break - # if (slice-starts-with?(word-slice, "#")) break - # if (has-metadata?(word-slice, "mod")) - # mod = parse-hex-int(next-token-from-slice(word-slice, "/")) - # has-modrm? = true - # else if (has-metadata?(word-slice, "rm32")) - # rm32 = parse-hex-int(next-token-from-slice(word-slice, "/")) - # has-modrm? = true - # else if (has-metadata?(word-slice, "r32") or has-metadata?(word-slice, "subop")) - # r32 = parse-hex-int(next-token-from-slice(word-slice, "/")) - # has-modrm? = true - # if has-modrm? - # var modrm = mod & 0b11 - # modrm <<= 3 - # modrm |= r32 & 0b111 - # modrm <<= 3 - # modrm |= rm32 & 0b111 - # emit-hex(out, modrm, 1) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var has-modrm?/EDX = false - 31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX - # var mod/EBX = 0 - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX - # var rm32/ESI = 0 - 31/xor 3/mod/direct 6/rm32/ESI . . . 6/r32/ESI . . # clear ESI - # var r32/EDI = 0 - 31/xor 3/mod/direct 7/rm32/EDI . . . 7/r32/EDI . . # clear EDI - # rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} -$emit-modrm:loop: - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 51/push-ECX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-modrm:check0: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) pass through - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-modrm:break/disp32 -$emit-modrm:check1: - # if (slice-starts-with?(word-slice, "#")) break - # . spill EDX - 52/push-EDX - # . start/EDX = word-slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 0/r32/AL . . # copy byte at *EDX to AL - # . restore EDX - 5a/pop-to-EDX - # . if (EAX == '#') pass through - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-modrm:break/disp32 -$emit-modrm:check-for-mod: - # if (has-metadata?(word-slice, "mod")) - # . EAX = has-metadata?(ECX, "mod") - # . . push args - 68/push "mod"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-modrm:check-for-rm32/disp8 -$emit-modrm:mod: - # mod = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . mod = EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX - # has-modrm? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-modrm:loop/disp32 -$emit-modrm:check-for-rm32: - # if (has-metadata?(word-slice, "rm32")) - # . EAX = has-metadata?(ECX, "rm32") - # . . push args - 68/push "rm32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-modrm:check-for-r32/disp8 -$emit-modrm:rm32: - # rm32 = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . rm32 = EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI - # has-modrm? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-modrm:loop/disp32 -$emit-modrm:check-for-r32: - # if (has-metadata?(word-slice, "r32")) - # . EAX = has-metadata?(ECX, "r32") - # . . push args - 68/push "r32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-modrm:check-for-subop/disp8 -$emit-modrm:r32: - # r32 = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . r32 = EAX - 89/copy 3/mod/direct 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to EDI - # has-modrm? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-modrm:loop/disp32 -$emit-modrm:check-for-subop: - # if (has-metadata?(word-slice, "subop")) - # . EAX = has-metadata?(ECX, "subop") - # . . push args - 68/push "subop"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) loop - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $emit-modrm:loop/disp32 -$emit-modrm:subop: - # r32 = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . r32 = EAX - 89/copy 3/mod/direct 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to EDI - # has-modrm? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-modrm:loop/disp32 -$emit-modrm:break: - # if (!has-modrm?) return - 81 7/subop/compare 3/mod/direct 2/rm32/EDX . . . . . 0/imm32 # compare EDX - 74/jump-if-equal $emit-modrm:end/disp8 -$emit-modrm:calculate: - # modrm/EBX = mod & 0b11 - 81 4/subop/and 3/mod/direct 3/rm32/EBX . . . . . 3/imm32/0b11 # bitwise and of EBX - # modrm <<= 3 - c1/shift 4/subop/left 3/mod/direct 3/rm32/EBX . . . . . 3/imm8 # shift EBX left by 3 bits - # modrm |= r32 & 0b111 - 81 4/subop/and 3/mod/direct 7/rm32/EDI . . . . . 7/imm32/0b111 # bitwise and of EDI - 09/or 3/mod/direct 3/rm32/EBX . . . 7/r32/EDI . . # EBX = bitwise OR with EDI - # modrm <<= 3 - c1/shift 4/subop/left 3/mod/direct 3/rm32/EBX . . . . . 3/imm8 # shift EBX left by 3 bits - # modrm |= rm32 & 0b111 - 81 4/subop/and 3/mod/direct 6/rm32/ESI . . . . . 7/imm32/0b111 # bitwise and of ESI - 09/or 3/mod/direct 3/rm32/EBX . . . 6/r32/ESI . . # EBX = bitwise OR with ESI -$emit-modrm:emit: - # emit-hex(out, modrm, 1) - # . . push args - 68/push 1/imm32 - 53/push-EBX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$emit-modrm:end: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-sib: # line : (address stream byte), out : (address buffered-file) -> <void> - # pseudocode: - # var has-sib? = false, base = 0, index = 0, scale = 0 - # var word-slice = {0, 0} - # while true - # word-slice = next-word(line) - # if (slice-empty?(word-slice)) break - # if (slice-starts-with?(word-slice, "#")) break - # if (has-metadata?(word-slice, "base") - # base = parse-hex-int(next-token-from-slice(word-slice, "/")) - # has-sib? = true - # else if (has-metadata?(word-slice, "index") - # index = parse-hex-int(next-token-from-slice(word-slice, "/")) - # has-sib? = true - # else if (has-metadata?(word-slice, "scale") - # scale = parse-hex-int(next-token-from-slice(word-slice, "/")) - # has-sib? = true - # if has-sib? - # var sib = scale & 0b11 - # sib <<= 2 - # sib |= index & 0b111 - # sib <<= 3 - # sib |= base & 0b111 - # emit-hex(out, sib, 1) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var has-sib?/EDX = false - 31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX - # var scale/EBX = 0 - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX - # var base/ESI = 0 - 31/xor 3/mod/direct 6/rm32/ESI . . . 6/r32/ESI . . # clear ESI - # var index/EDI = 0 - 31/xor 3/mod/direct 7/rm32/EDI . . . 7/r32/EDI . . # clear EDI - # rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$emit-sib:loop: -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 51/push-ECX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-sib:check0: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) pass through - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-sib:break/disp32 -$emit-sib:check1: - # if (slice-starts-with?(word-slice, "#")) break - # . spill EDX - 52/push-EDX - # . start/EDX = word-slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 0/r32/AL . . # copy byte at *EDX to AL - # . restore EDX - 5a/pop-to-EDX - # . if (EAX == '#') pass through - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-sib:break/disp32 -$emit-sib:check-for-scale: - # if (has-metadata?(word-slice, "scale")) - # . EAX = has-metadata?(ECX, "scale") - # . . push args - 68/push "scale"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-sib:check-for-base/disp8 -$emit-sib:scale: - # scale = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . scale = EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX - # has-sib? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-sib:loop/disp32 -$emit-sib:check-for-base: - # if (has-metadata?(word-slice, "base")) - # . EAX = has-metadata?(ECX, "base") - # . . push args - 68/push "base"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-sib:check-for-index/disp8 -$emit-sib:base: - # base = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . base = EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI - # has-sib? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-sib:loop/disp32 -$emit-sib:check-for-index: - # if (has-metadata?(word-slice, "index")) - # . EAX = has-metadata?(ECX, "index") - # . . push args - 68/push "index"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) loop - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $emit-sib:loop/disp32 -$emit-sib:index: - # index = parse-hex-int(next-token-from-slice(word-slice->start, word-slice->end, '/')) - # . EAX = parse-datum-of-word(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-datum-of-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . index = EAX - 89/copy 3/mod/direct 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to EDI - # has-sib? = true - ba/copy-to-EDX 1/imm32/true - # continue - e9/jump $emit-sib:loop/disp32 -$emit-sib:break: - # if (!has-sib?) return - 81 7/subop/compare 3/mod/direct 2/rm32/EDX . . . . . 0/imm32 # compare EDX - 74/jump-if-equal $emit-sib:end/disp8 -$emit-sib:calculate: - # sib/EBX = scale & 0b11 - 81 4/subop/and 3/mod/direct 3/rm32/EBX . . . . . 3/imm32/0b11 # bitwise and of EBX - # sib <<= 2 - c1/shift 4/subop/left 3/mod/direct 3/rm32/EBX . . . . . 2/imm8 # shift EBX left by 2 bits - # sib |= index & 0b111 - 81 4/subop/and 3/mod/direct 7/rm32/EDI . . . . . 7/imm32/0b111 # bitwise and of EDI - 09/or 3/mod/direct 3/rm32/EBX . . . 7/r32/EDI . . # EBX = bitwise OR with EDI - # sib <<= 3 - c1/shift 4/subop/left 3/mod/direct 3/rm32/EBX . . . . . 3/imm8 # shift EBX left by 3 bits - # sib |= base & 0b111 - 81 4/subop/and 3/mod/direct 6/rm32/ESI . . . . . 7/imm32/0b111 # bitwise and of ESI - 09/or 3/mod/direct 3/rm32/EBX . . . 6/r32/ESI . . # EBX = bitwise OR with ESI -$emit-sib:emit: - # emit-hex(out, sib, 1) - # . . push args - 68/push 1/imm32 - 53/push-EBX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$emit-sib:end: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-disp: # line : (address stream byte), out : (address buffered-file) -> <void> - # pseudocode: - # rewind-stream(line) - # var word-slice = {0, 0} - # while true - # word-slice = next-word(line) - # if (slice-empty?(word-slice)) break - # if (slice-starts-with?(word-slice, "#")) break - # if has-metadata?(word-slice, "disp32") - # emit(out, word-slice, 4) - # break - # if has-metadata?(word-slice, "disp16") - # emit(out, word-slice, 2) - # break - # if has-metadata?(word-slice, "disp8") - # emit(out, word-slice, 1) - # break - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-disp:loop: - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 51/push-ECX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-disp:check0: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) pass through - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-disp:break/disp32 -$emit-disp:check1: - # if (slice-starts-with?(word-slice, "#")) break - # . start/EDX = word-slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 0/r32/AL . . # copy byte at *EDX to AL - # . if (EAX == '#') break - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-disp:break/disp32 -$emit-disp:check-for-disp32: - # if (has-metadata?(word-slice, "disp32")) - # . EAX = has-metadata?(ECX, "disp32") - # . . push args - 68/push "disp32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-disp:check-for-disp16/disp8 -$emit-disp:disp32: - # emit(out, word-slice, 4) - # . . push args - 68/push 4/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # break - e9/jump $emit-disp:break/disp32 -$emit-disp:check-for-disp16: - # else if (has-metadata?(word-slice, "disp16")) - # . EAX = has-metadata?(ECX, "disp16") - # . . push args - 68/push "disp16"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-disp:check-for-disp8/disp8 -$emit-disp:disp16: - # emit(out, word-slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # break - e9/jump $emit-disp:break/disp32 -$emit-disp:check-for-disp8: - # if (has-metadata?(word-slice, "disp8")) - # . EAX = has-metadata?(ECX, "disp8") - # . . push args - 68/push "disp8"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) loop - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $emit-disp:loop/disp32 -$emit-disp:disp8: - # emit(out, word-slice, 1) - # . . push args - 68/push 1/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # break -$emit-disp:break: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-imm: # line : (address stream byte), out : (address buffered-file) -> <void> - # pseudocode: - # rewind-stream(line) - # var word-slice = {0, 0} - # while true - # word-slice = next-word(line) - # if (slice-empty?(word-slice)) break - # if (slice-starts-with?(word-slice, "#")) break - # if has-metadata?(word-slice, "imm32") - # emit(out, word-slice, 4) - # break - # if has-metadata?(word-slice, "imm16") - # emit(out, word-slice, 2) - # break - # if has-metadata?(word-slice, "imm8") - # emit(out, word-slice, 1) - # break - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-imm:loop: - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 51/push-ECX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-imm:check0: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) pass through - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-imm:break/disp32 -$emit-imm:check1: - # if (slice-starts-with?(word-slice, "#")) break - # . start/EDX = slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 0/r32/AL . . # copy byte at *EDX to AL - # . if (EAX == '#') break - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-imm:break/disp32 -$emit-imm:check-for-imm32: - # if (has-metadata?(word-slice, "imm32")) - # . EAX = has-metadata?(ECX, "imm32") - # . . push args - 68/push "imm32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-imm:check-for-imm16/disp8 -$emit-imm:imm32: - # emit(out, word-slice, 4) - # . . push args - 68/push 4/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # break - e9/jump $emit-imm:break/disp32 -$emit-imm:check-for-imm16: - # if (has-metadata?(word-slice, "imm16")) - # . EAX = has-metadata?(ECX, "imm16") - # . . push args - 68/push "imm16"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-imm:check-for-imm8/disp8 -$emit-imm:imm16: - # emit(out, word-slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # break - e9/jump $emit-imm:break/disp32 -$emit-imm:check-for-imm8: - # if (has-metadata?(word-slice, "imm8")) - # . EAX = has-metadata?(ECX, "imm8") - # . . push args - 68/push "imm8"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) loop - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $emit-imm:loop/disp32 -$emit-imm:imm8: - # emit(out, word-slice, 1) - # . . push args - 68/push 1/imm32 - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # break -$emit-imm:break: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-line-in-comment: # line : (address stream byte), out : (address buffered-file) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # write-buffered(out, " # ") - # . . push args - 68/push " # "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream-data(out, line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$emit-line-in-comment:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-passes-comments-through: - # if a line starts with '#', pass it along unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "# abcd") - # . . push args - 68/push "# abcd"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "# abcd", msg) - # . . push args - 68/push "F - test-convert-instruction-passes-comments-through"/imm32 - 68/push "# abcd"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-passes-labels-through: - # if the first word ends with ':', pass along the entire line unchanged - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "ab: # cd") - # . . push args - 68/push "ab: # cd"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the line just passed through - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "ab: # cd", msg) - # . . push args - 68/push "F - test-convert-instruction-passes-labels-through"/imm32 - 68/push "ab: # cd"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-single-opcode: - # if the instruction consists of a single opcode, strip its metadata and pass it along - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "ab/cd # comment") - # . . push args - 68/push "ab/cd # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "ab # ab/cd # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-single-opcode"/imm32 - 68/push "ab # ab/cd # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-0f-opcode: - # if the instruction starts with 0f opcode, include a second opcode - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "0f/m1 ab/m2 # comment") - # . . push args - 68/push "0f/m1 ab/m2 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "0f ab # 0f/m1 ab/m2 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-0f-opcode"/imm32 - 68/push "0f ab # 0f/m1 ab/m2 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-f2-opcode: - # if the instruction starts with f2 opcode, include a second opcode - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "f2/m1 ab/m2 # comment") - # . . push args - 68/push "f2/m1 ab/m2 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "f2 ab # f2/m1 ab/m2 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-f2-opcode"/imm32 - 68/push "f2 ab # f2/m1 ab/m2 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-f3-opcode: - # if the instruction starts with f3 opcode, include a second opcode - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "f3/m1 ab/m2 # comment") - # . . push args - 68/push "f3/m1 ab/m2 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "f3 ab # f3/m1 ab/m2 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-f3-opcode"/imm32 - 68/push "f3 ab # f3/m1 ab/m2 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-f2-0f-opcode: - # if the instruction starts with f2 0f opcode, include a second opcode - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "f2/m1 0f/m2 ab/m3 # comment") - # . . push args - 68/push "f2/m1 0f/m2 ab/m3 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "f2 0f ab # f2/m1 0f/m2 ab/m3 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-f2-0f-opcode"/imm32 - 68/push "f2 0f ab # f2/m1 0f/m2 ab/m3 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-f3-0f-opcode: - # if the instruction starts with f3 0f opcode, include a second opcode - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "f3/m1 0f/m2 ab/m3 # comment") - # . . push args - 68/push "f3/m1 0f/m2 ab/m3 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "f3 0f ab # f3/m1 0f/m2 ab/m3 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-f3-0f-opcode"/imm32 - 68/push "f3 0f ab # f3/m1 0f/m2 ab/m3 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-unused-opcodes: - # if the instruction doesn't start with f2, f3 or 0f, don't include other opcodes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "ab/m1 cd/m2 # comment") - # . . push args - 68/push "ab/m1 cd/m2 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "ab # f3/m1 0f/m2 ab/m3 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-unused-opcodes"/imm32 - 68/push "ab # ab/m1 cd/m2 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-unused-second-opcodes: - # if the second opcode isn't 0f, don't include further opcodes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "f2/m1 ab/m2 cd/m3 # comment") - # . . push args - 68/push "f2/m1 ab/m2 cd/m3 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "f2 ab # f2/m1 ab/m2 cd/m3 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-unused-second-opcodes"/imm32 - 68/push "f2 ab # f2/m1 ab/m2 cd/m3 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-unused-second-opcodes-2: - # if the second opcode isn't 0f, don't include further opcodes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "f3/m1 ab/m2 cd/m3 # comment") - # . . push args - 68/push "f3/m1 ab/m2 cd/m3 # comment"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "f3 ab # f3/m1 ab/m2 cd/m3 # comment", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-unused-second-opcodes"/imm32 - 68/push "f3 ab # f3/m1 ab/m2 cd/m3 # comment"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-modrm-byte: - # pack mod, rm32 and r32 operands into ModR/M byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 0/rm32 1/r32") - # . . push args - 68/push "8b/copy 0/mod 0/rm32 1/r32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 08 # 8b/copy 0/mod 0/rm32 1/r32", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-modrm-byte"/imm32 - 68/push "8b 08 # 8b/copy 0/mod 0/rm32 1/r32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-modrm-byte-with-non-zero-mod: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "01/add 3/mod/direct 3/rm32/EBX 1/r32/ECX") - # . . push args - 68/push "01/add 3/mod/direct 3/rm32/EBX 1/r32/ECX"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "out: ") -#? # . . push args -#? 68/push "out: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check output - # . check-stream-equal(_test-output-stream, "# abcd", msg) - # . . push args - 68/push "F - test-convert-instruction-foo"/imm32 - 68/push "01 cb # 01/add 3/mod/direct 3/rm32/EBX 1/r32/ECX"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-modrm-byte-from-subop: - # pack mod, rm32 and subop operands into ModR/M byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "ff 6/subop/push 0/mod 0/rm32") - # . . push args - 68/push "ff 6/subop/push 0/mod 0/rm32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "ff 30 # ff 6/subop/push 0/mod 0/rm32", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-modrm-byte-from-subop"/imm32 - 68/push "ff 30 # ff 6/subop/push 0/mod 0/rm32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-modrm-byte-with-missing-mod: - # pack rm32 and r32 operands into ModR/M byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/rm32 1/r32") - # . . push args - 68/push "8b/copy 0/rm32 1/r32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 08 # 8b/copy 0/rm32 1/r32", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-modrm-byte-with-missing-mod"/imm32 - 68/push "8b 08 # 8b/copy 0/rm32 1/r32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-modrm-byte-with-missing-rm32: - # pack mod and r32 operands into ModR/M byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 1/r32") - # . . push args - 68/push "8b/copy 0/mod 1/r32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 08 # 8b/copy 0/mod 1/r32", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-modrm-byte-with-missing-rm32"/imm32 - 68/push "8b 08 # 8b/copy 0/mod 1/r32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-modrm-byte-with-missing-r32: - # pack mod and rm32 operands into ModR/M byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 0/rm32") - # . . push args - 68/push "8b/copy 0/mod 0/rm32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 00 # 8b/copy 0/mod 0/rm32", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-modrm-byte-with-missing-r32"/imm32 - 68/push "8b 00 # 8b/copy 0/mod 0/rm32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-sib-byte: - # pack base, index and scale operands into SIB byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale") - # . . push args - 68/push "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-sib-byte"/imm32 - 68/push "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 1/index 0/scale"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-sib-byte-with-missing-base: - # pack index and scale operands into SIB byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale") - # . . push args - 68/push "8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-sib-byte-with-missing-base"/imm32 - 68/push "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 1/index 0/scale"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-sib-byte-with-missing-index: - # pack base and scale operands into SIB byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale") - # . . push args - 68/push "8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-sib-byte-with-missing-index"/imm32 - 68/push "8b 0c 00 # 8b/copy 0/mod 4/rm32 1/r32 0/base 0/scale"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-emits-sib-byte-with-missing-scale: - # pack base and index operands into SIB byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index") - # . . push args - 68/push "8b/copy 0/mod 4/rm32 1/r32 0/base 1/index"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 1/index", msg) - # . . push args - 68/push "F - test-convert-instruction-emits-sib-byte-with-missing-scale"/imm32 - 68/push "8b 0c 08 # 8b/copy 0/mod 4/rm32 1/r32 0/base 1/index"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-disp32-operand: - # expand /disp32 operand into 4 bytes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "e8/call 20/disp32") - # . . push args - 68/push "e8/call 20/disp32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "e8 20 00 00 00 # e8/call 20/disp32", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-disp32-operand"/imm32 - 68/push "e8 20 00 00 00 # e8/call 20/disp32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-disp16-operand: - # expand /disp16 operand into 2 bytes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "e8/call 20/disp16") - # . . push args - 68/push "e8/call 20/disp16"/imm32 # not a valid instruction - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "e8 20 00 # e8/call 20/disp16", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-disp16-operand"/imm32 - 68/push "e8 20 00 # e8/call 20/disp16"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-disp8-operand: - # expand /disp8 operand into 1 byte - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "eb/jump 20/disp8") - # . . push args - 68/push "eb/jump 20/disp8"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "eb 20 # eb/jump 20/disp8", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-disp8-operand"/imm32 - 68/push "eb 20 # eb/jump 20/disp8"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-disp8-name: - # pass /disp8 name directly through - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "eb/jump xyz/disp8") - # . . push args - 68/push "eb/jump xyz/disp8"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "eb xyz/disp8 # eb/jump xyz/disp8", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-disp8-name"/imm32 - 68/push "eb xyz/disp8 # eb/jump xyz/disp8"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-imm32-operand: - # expand /imm32 operand into 4 bytes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "68/push 0x20/imm32") - # . . push args - 68/push "68/push 0x20/imm32"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "68 20 00 00 00 # 68/push 0x20/imm32", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-imm32-operand"/imm32 - 68/push "68 20 00 00 00 # 68/push 0x20/imm32"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-imm16-operand: - # expand /imm16 operand into 2 bytes - # we don't have one of these at the moment, so this expands to an invalid instruction - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "68/push 0x20/imm16") - # . . push args - 68/push "68/push 0x20/imm16"/imm32 # not a valid instruction - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "68 20 00 # 68/push 0x20/imm16", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-imm16-operand"/imm32 - 68/push "68 20 00 # 68/push 0x20/imm16"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-instruction-handles-imm8-operand: - # expand /imm8 operand into 1 byte - # we don't have one of these at the moment, so this expands to an invalid instruction - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "68/push 0x20/imm8") - # . . push args - 68/push "68/push 0x20/imm8"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert-instruction(_test-input-stream, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call convert-instruction/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check output - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-stream-equal(_test-output-stream, "68 20 # 68/push 0x20/imm8", msg) - # . . push args - 68/push "F - test-convert-instruction-handles-imm8-operand"/imm32 - 68/push "68 20 # 68/push 0x20/imm8"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# shortcut for parse-hex-int(next-token-from-slice(word->start, word->end, '/')) -parse-datum-of-word: # word : (address slice) -> value/EAX - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 56/push-ESI - # ESI = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # slice = next-token-from-slice(word->start, word->end, '/') - # . . push args - 51/push-ECX - 68/push 0x2f/imm32/slash - ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) - ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # value/EAX = parse-hex-int(slice) - # . . push args - 51/push-ECX - # . . call - e8/call parse-hex-int/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$parse-datum-of-word:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5e/pop-to-ESI - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/subx-common.subx b/subx/apps/subx-common.subx deleted file mode 100644 index abb223fb..00000000 --- a/subx/apps/subx-common.subx +++ /dev/null @@ -1,3118 +0,0 @@ -# common helpers shared by phases of the SubX translator - -# - some limits on the programs we can translate -== data - -# maximum memory available for allocation -Heap-size: - 0x200000/imm32/2MB - -# maximum size of a single segment -Segment-size: - 0x80000/imm32/512KB - -# maximum size of input textual stream (spanning all segments) -Input-size: - 0x100000/imm32/1MB - -# maximum size of the 'labels' table in survey.subx -Max-labels: - 0x10000/imm32/4K-labels/64KB - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -# - managing tables -# SubX has rudimentary support for tables. -# -# Each table is a stream of rows. -# -# Each row consists of a 4-byte row (address to a string) and a variable-size -# value. -# -# Accessing the table performs a linear scan for a key string, and always -# requires passing in the row size. -# -# Table primitives: -# get(stream, string, row-size) -# aborts if not found -# get-or-insert(stream, string, row-size) -# inserts if not found -# get-slice(stream, slice, row-size) -# aborts if not found -# leaky-get-or-insert-slice(stream, slice, row-size) -# inserts if not found - -# 'table' is a stream of (key, value) rows -# keys are always strings (addresses; size 4 bytes) -# values may be any type, but rows (key+value) always occupy 'row-size' bytes -# scan 'table' for a row with a key 'key' and return the address of the corresponding value -# if no row is found, abort -get: # table : (address stream {string, _}), key : (address string), row-size : int -> EAX : (address _) - # pseudocode: - # curr = table->data - # max = &table->data[table->write] - # while curr < max - # if string-equal?(key, *curr) - # return curr+4 - # curr += row-size - # abort - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 56/push-ESI - # ESI = table - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # curr/ECX = table->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - # max/EDX = table->data + table->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX -$get:search-loop: - # if (curr >= max) abort - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-or-equal-unsigned $get:abort/disp8 - # if (string-equal?(key, *curr)) return curr+4 - # . EAX = string-equal?(key, *curr) - # . . push args - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return EAX = curr+4 - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $get:mismatch/disp8 - 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - eb/jump $get:end/disp8 -$get:mismatch: - # curr += row-size - 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - # loop - eb/jump $get:search-loop/disp8 -$get:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$get:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "get: key not found: "/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . _write(2/stderr, key) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . _write(2/stderr, "\n") - # . . push args - 68/push "\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -test-get: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - setup: create a table with a couple of keys - # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 68/push 0x10/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # insert(table, "code", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "code"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # insert(table, "data", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "data"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get:check1: - # EAX = get(table, "code", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "code"/imm32 - 51/push-ECX - # . . call - e8/call get/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 4, msg) - # . check-ints-equal(EAX - table, 16, msg) - # . . push args - 68/push "F - test-get/0"/imm32 - 68/push 0x10/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get:check2: - # EAX = get(table, "data", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "data"/imm32 - 51/push-ECX - # . . call - e8/call get/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 12, msg) - # . check-ints-equal(EAX - table, 24, msg) - # . . push args - 68/push "F - test-get/1"/imm32 - 68/push 0x18/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# 'table' is a stream of (key, value) rows -# keys are always strings (addresses; size 4 bytes) -# values may be any type, but rows (key+value) always occupy 'row-size' bytes -# scan 'table' for a row with a key 'key' and return the address of the corresponding value -# if no row is found, abort -get-slice: # table : (address stream {string, _}), key : (address slice), row-size : int -> EAX : (address _) - # pseudocode: - # curr = table->data - # max = &table->data[table->write] - # while curr < max - # if slice-equal?(key, *curr) - # return curr+4 - # curr += row-size - # abort - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 56/push-ESI - # ESI = table - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # curr/ECX = table->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - # max/EDX = table->data + table->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX -$get-slice:search-loop: - # if (curr >= max) abort - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-or-equal-unsigned $get-slice:abort/disp8 - # if (slice-equal?(key, *curr)) return curr+4 - # . EAX = slice-equal?(key, *curr) - # . . push args - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return EAX = curr+4 - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $get-slice:mismatch/disp8 - 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - eb/jump $get-slice:end/disp8 -$get-slice:mismatch: - # curr += row-size - 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - # loop - eb/jump $get-slice:search-loop/disp8 -$get-slice:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$get-slice:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "get-slice: key not found: "/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write-slice-buffered(Stderr, key) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 68/push Stderr/imm32 - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(Stderr) - # . . push args - 68/push Stderr/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . _write(2/stderr, "\n") - # . . push args - 68/push "\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -test-get-slice: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # - setup: create a table with a couple of keys - # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 68/push 0x10/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # insert(table, "code", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "code"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # insert(table, "data", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "data"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-slice:check1: - # (EAX..EDX) = "code" - b8/copy-to-EAX "code"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 05/add-to-EAX 4/imm32 - # var slice/EDX = {EAX, EDX} - 52/push-EDX - 50/push-EAX - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # EAX = get-slice(table, "code", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 52/push-EDX - 51/push-ECX - # . . call - e8/call get-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 4, msg) # first row's value slot returned - # . check-ints-equal(EAX - table, 16, msg) - # . . push args - 68/push "F - test-get-slice/0"/imm32 - 68/push 0x10/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-slice:check2: - # (EAX..EDX) = "data" - b8/copy-to-EAX "data"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 05/add-to-EAX 4/imm32 - # var slice/EDX = {EAX, EDX} - 52/push-EDX - 50/push-EAX - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # EAX = get-slice(table, "data" slice, 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 52/push-EDX - 51/push-ECX - # . . call - e8/call get-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 12, msg) - # . check-ints-equal(EAX - table, 24, msg) - # . . push args - 68/push "F - test-get-slice/1"/imm32 - 68/push 0x18/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-slice:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# 'table' is a stream of (key, value) rows -# keys are always strings (addresses; size 4 bytes) -# values may be any type, but rows (key+value) always occupy 'row-size' bytes -# scan 'table' for a row with a key 'key' and return the address of the corresponding value -# if no row is found, save 'key' to the next available row -# if there are no rows free, abort -# return the address of the value -# Beware: assume keys are immutable; they're inserted by reference -# TODO: pass in an allocation descriptor -get-or-insert: # table : (address stream {string, _}), key : (address string), row-size : int -> EAX : (address _) - # pseudocode: - # curr = table->data - # max = &table->data[table->write] - # while curr < max - # if string-equal?(key, *curr) - # return curr+4 - # curr += row-size - # if table->write >= table->length - # abort - # zero-out(max, row-size) - # *max = key - # table->write += row-size - # return max+4 - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 56/push-ESI - # ESI = table - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # curr/ECX = table->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - # max/EDX = table->data + table->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX -$get-or-insert:search-loop: - # if (curr >= max) break - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-or-equal-unsigned $get-or-insert:not-found/disp8 - # if (string-equal?(key, *curr)) return curr+4 - # . EAX = string-equal?(key, *curr) - # . . push args - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return EAX = curr+4 - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $get-or-insert:mismatch/disp8 - 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - eb/jump $get-or-insert:end/disp8 -$get-or-insert:mismatch: - # curr += row-size - 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - # loop - eb/jump $get-or-insert:search-loop/disp8 -$get-or-insert:not-found: - # result/EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - # if (table->write >= table->length) abort - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8) - 73/jump-if-greater-or-equal-unsigned $get-or-insert:abort/disp8 - # zero-out(max, row-size) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 52/push-EDX - # . . call - e8/call zero-out/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # *max = key - # . EAX = key - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX - # . *max = EAX - 89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX - # table->write += row-size - # . EAX = row-size - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX - # . table->write += EAX - 01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI - # return max+4 - # . EAX = max - 89/copy 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # copy EDX to EAX - # . EAX += 4 - 05/add-to-EAX 4/imm32 -$get-or-insert:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$get-or-insert:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "get-or-insert: table is full\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -test-get-or-insert: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 68/push 0x10/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -$test-get-or-insert:first-call: - # - start with an empty table, insert one key, verify that it was inserted - # EAX = get-or-insert(table, "code", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "code"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 4, msg) # first row's value slot returned - # . check-ints-equal(EAX - table, 16, msg) - # . . push args - 68/push "F - test-get-or-insert/0"/imm32 - 68/push 0x10/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-or-insert:check2: - # check-ints-equal(table->write, row-size = 8, msg) - # . . push args - 68/push "F - test-get-or-insert/1"/imm32 - 68/push 8/imm32/row-size - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-string-equal(*table->data, "code", msg) - # . . push args - 68/push "F - test-get-or-insert/2"/imm32 - 68/push "code"/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - # . . call - e8/call check-string-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-or-insert:second-call: - # - insert the same key again, verify that it was reused - # EAX = get-or-insert(table, "code", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "code"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 4, msg) - # . check-ints-equal(EAX - table, 16, msg) - # . . push args - 68/push "F - test-get-or-insert/3"/imm32 - 68/push 0x10/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # no new row inserted - # . check-ints-equal(table->write, row-size = 8, msg) - # . . push args - 68/push "F - test-get-or-insert/4"/imm32 - 68/push 8/imm32/row-size - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-string-equal(*table->data, "code", msg) - # . . push args - 68/push "F - test-get-or-insert/5"/imm32 - 68/push "code"/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - # . . call - e8/call check-string-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-or-insert:third-call: - # - insert a new key, verify that it was inserted - # EAX = get-or-insert(table, "data", 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 68/push "data"/imm32 - 51/push-ECX - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # table gets a new row - # check-ints-equal(EAX - table->data, 12, msg) # second row's value slot returned - # . check-ints-equal(EAX - table, 24, msg) - # . . push args - 68/push "F - test-get-or-insert/6"/imm32 - 68/push 0x18/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(table->write, 2 rows = 16, msg) - # . . push args - 68/push "F - test-get-or-insert/7"/imm32 - 68/push 0x10/imm32/two-rows - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-string-equal(*table->data+8, "data", msg) - # check-string-equal(*(table+20), "data", msg) - # . . push args - 68/push "F - test-get-or-insert/8"/imm32 - 68/push "data"/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0x14/disp8 . # push *(ECX+20) - # . . call - e8/call check-string-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-get-or-insert:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# 'table' is a stream of (key, value) rows -# keys are always strings (addresses; size 4 bytes) -# values may be any type, but rows (key+value) always occupy 'row-size' bytes -# scan 'table' for a row with a key 'key' and return the address of the corresponding value -# if no row is found, save 'key' in the next available row -# if there are no rows free, abort -# WARNING: leaks memory -# TODO: pass in an allocation descriptor -leaky-get-or-insert-slice: # table : (address stream {string, _}), key : (address slice), row-size : int -> EAX : (address _) - # pseudocode: - # curr = table->data - # max = &table->data[table->write] - # while curr < max - # if slice-equal?(key, *curr) - # return curr+4 - # curr += row-size - # if table->write >= table->length - # abort - # zero-out(max, row-size) - # *max = slice-to-string(Heap, key) - # table->write += row-size - # return max+4 - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 56/push-ESI - # ESI = table - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # curr/ECX = table->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 0xc/disp8 . # copy ESI+12 to ECX - # max/EDX = table->data + table->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX - 8d/copy-address 0/mod/indirect 4/rm32/sib 1/base/ECX 2/index/EDX . 2/r32/EDX . . # copy ECX+EDX to EDX -$leaky-get-or-insert-slice:search-loop: - # if (curr >= max) break - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-or-equal-unsigned $leaky-get-or-insert-slice:not-found/disp8 - # if (slice-equal?(key, *curr)) return curr+4 - # . EAX = slice-equal?(key, *curr) - # . . push args - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return EAX = curr+4 - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $leaky-get-or-insert-slice:mismatch/disp8 - 8d/copy-address 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy ECX+4 to EAX - eb/jump $leaky-get-or-insert-slice:end/disp8 -$leaky-get-or-insert-slice:mismatch: - # curr += row-size - 03/add 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0x10/disp8 . # add *(EBP+16) to ECX - # loop - eb/jump $leaky-get-or-insert-slice:search-loop/disp8 -$leaky-get-or-insert-slice:not-found: - # result/EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - # if (table->write >= table->length) abort - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # compare ECX with *(ESI+8) - 7d/jump-if-greater-or-equal $leaky-get-or-insert-slice:abort/disp8 - # zero-out(max, row-size) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 52/push-EDX - # . . call - e8/call zero-out/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # *max = slice-to-string(Heap, key) - # . EAX = slice-to-string(Heap, key) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 68/push Heap/imm32 - # . . call - e8/call slice-to-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . *max = EAX - 89/copy 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to *EDX - # table->write += row-size - # . EAX = row-size - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX - # . table->write += EAX - 01/add 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # add EAX to *ESI - # return max+4 - # . EAX = max - 89/copy 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # copy EDX to EAX - # . EAX += 4 - 05/add-to-EAX 4/imm32 -$leaky-get-or-insert-slice:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$leaky-get-or-insert-slice:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "leaky-get-or-insert-slice: table is full\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -test-leaky-get-or-insert-slice: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # var table/ECX : (address stream {string, number}) = stream(2 rows * 8 bytes) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # subtract from ESP - 68/push 0x10/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # (EAX..EDX) = "code" - b8/copy-to-EAX "code"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 05/add-to-EAX 4/imm32 - # var slice/EDX = {EAX, EDX} - 52/push-EDX - 50/push-EAX - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX -$test-leaky-get-or-insert-slice:first-call: - # - start with an empty table, insert one key, verify that it was inserted - # EAX = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 52/push-EDX - 51/push-ECX - # . . call - e8/call leaky-get-or-insert-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 4, msg) # first row's value slot returned - # . check-ints-equal(EAX - table, 16, msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/0"/imm32 - 68/push 0x10/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-leaky-get-or-insert-slice:check2: - # check-ints-equal(table->write, row-size = 8, msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/1"/imm32 - 68/push 8/imm32/row-size - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-string-equal(*table->data, "code", msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/2"/imm32 - 68/push "code"/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - # . . call - e8/call check-string-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-leaky-get-or-insert-slice:second-call: - # - insert the same key again, verify that it was reused - # EAX = leaky-get-or-insert-slice(table, "code" slice, 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 52/push-EDX - 51/push-ECX - # . . call - e8/call leaky-get-or-insert-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(EAX - table->data, 4, msg) - # . check-ints-equal(EAX - table, 16, msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/3"/imm32 - 68/push 0x10/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # no new row inserted - # . check-ints-equal(table->write, row-size = 8, msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/4"/imm32 - 68/push 8/imm32/row-size - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-string-equal(*table->data, "code", msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/5"/imm32 - 68/push "code"/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0xc/disp8 . # push *(ECX+12) - # . . call - e8/call check-string-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-leaky-get-or-insert-slice:third-call: - # - insert a new key, verify that it was inserted - # (EAX..EDX) = "data" - b8/copy-to-EAX "data"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 2/r32/EDX . . # copy *EAX to EDX - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 2/index/EDX . 2/r32/EDX 4/disp8 . # copy EAX+EDX+4 to EDX - 05/add-to-EAX 4/imm32 - # var slice/EDX = {EAX, EDX} - 52/push-EDX - 50/push-EAX - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # EAX = leaky-get-or-insert-slice(table, "data" slice, 8 bytes per row) - # . . push args - 68/push 8/imm32/row-size - 52/push-EDX - 51/push-ECX - # . . call - e8/call leaky-get-or-insert-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # table gets a new row - # check-ints-equal(EAX - table->data, 12, msg) # second row's value slot returned - # . check-ints-equal(EAX - table, 24, msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/6"/imm32 - 68/push 0x18/imm32 - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(table->write, 2 rows = 16, msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/7"/imm32 - 68/push 0x10/imm32/two-rows - ff 6/subop/push 0/mod/indirect 1/rm32/ECX . . . . . . # push *ECX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-string-equal(*table->data+8, "data", msg) - # check-string-equal(*(table+20), "data", msg) - # . . push args - 68/push "F - test-leaky-get-or-insert-slice/8"/imm32 - 68/push "data"/imm32 - ff 6/subop/push 1/mod/*+disp8 1/rm32/ECX . . . . 0x14/disp8 . # push *(ECX+20) - # . . call - e8/call check-string-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-leaky-get-or-insert-slice:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# (re)compute the bounds of the next word in the line -# return empty string on reaching end of file -next-word: # line : (address stream byte), out : (address slice) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 56/push-ESI - 57/push-EDI - # ESI = line - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # EDI = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI - # skip-chars-matching(line, ' ') - # . . push args - 68/push 0x20/imm32/space - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call skip-chars-matching/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$next-word:check0: - # if (line->read >= line->write) clear out and return - # . EAX = line->read - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - # . if (EAX < line->write) goto next check - 3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI - 7c/jump-if-lesser $next-word:check-for-comment/disp8 - # . return out = {0, 0} - c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI - c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4) - eb/jump $next-word:end/disp8 -$next-word:check-for-comment: - # out->start = &line->data[line->read] - 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 - # . 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 - # . compare - 3d/compare-EAX-and 0x23/imm32/pound - 75/jump-if-not-equal $next-word:regular-word/disp8 -$next-word:comment: - # . out->end = &line->data[line->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 - 89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) - # . line->read = line->write - 89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4) - # . return - eb/jump $next-word:end/disp8 -$next-word:regular-word: - # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call skip-chars-not-matching-whitespace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # out->end = &line->data[line->read] - 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 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4) -$next-word:end: - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # 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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # 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 - # next-word(_test-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(slice->start - _test-stream->data, 2, msg) - # . check-ints-equal(slice->start - _test-stream, 14, msg) - # . . push args - 68/push "F - test-next-word: start"/imm32 - 68/push 0xe/imm32 - # . . push slice->start - _test-stream - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(slice->end - _test-stream->data, 4, msg) - # . check-ints-equal(slice->end - _test-stream, 16, msg) - # . . push args - 68/push "F - test-next-word: end"/imm32 - 68/push 0x10/imm32 - # . . push slice->end - _test-stream - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-returns-whole-comment: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # 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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write(_test-stream, " # a") - # . . push args - 68/push " # a"/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 - # next-word(_test-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(slice->start - _test-stream->data, 2, msg) - # . check-ints-equal(slice->start - _test-stream, 14, msg) - # . . push args - 68/push "F - test-next-word-returns-whole-comment: start"/imm32 - 68/push 0xe/imm32 - # . . push slice->start - _test-stream - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # check-ints-equal(slice->end - _test-stream->data, 5, msg) - # . check-ints-equal(slice->end - _test-stream, 17, msg) - # . . push args - 68/push "F - test-next-word-returns-whole-comment: end"/imm32 - 68/push 0x11/imm32 - # . . push slice->end - _test-stream - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-stream/imm32 # subtract from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-next-word-returns-empty-string-on-eof: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # 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 - # var slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write nothing to _test-stream - # next-word(_test-stream, slice) - # . . push args - 51/push-ECX - 68/push _test-stream/imm32 - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(slice->end - slice->start, 0, msg) - # . . push args - 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32 - 68/push 0/imm32 - # . . push slice->end - slice->start - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX - 2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# write an entire stream's contents to a buffered-file -# ways to do this: -# - construct a 'maximal slice' and pass it to write-slice-buffered -# - flush the buffered-file and pass the stream directly to its fd (disabling buffering) -# we'll go with the first way for now -write-stream-data: # f : (address buffered-file), s : (address stream) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 56/push-ESI - # ESI = s - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # var slice/ECX = {s->data, s->data + s->write} - # . push s->data + s->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 s->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX - 50/push-EAX - # . ECX = ESP - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # write-slice-buffered(f, slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$write-stream-data:end: - # . restore locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5e/pop-to-ESI - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-write-stream-data: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-input-stream) - # . . push args - 68/push _test-input-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 input - # . write(_test-input-stream, "abcd") - # . . push args - 68/push "abcd"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream-data(_test-output-buffered-file, _test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check that the write happened as expected - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . check-stream-equal(_test-output-stream, "abcd", msg) - # . . push args - 68/push "F - test-write-stream-data"/imm32 - 68/push "abcd"/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -has-metadata?: # word : (address slice), s : (address string) -> EAX : boolean - # pseudocode: - # var twig : &slice = next-token-from-slice(word->start, word->end, '/') # skip name - # curr = twig->end - # while true - # twig = next-token-from-slice(curr, word->end, '/') - # if (twig.empty()) break - # if (slice-equal?(twig, s)) return true - # curr = twig->end - # return false - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 56/push-ESI - 57/push-EDI - # ESI = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # EDX = word->end - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 4/disp8 . # copy *(ESI+4) to EDX - # var twig/EDI : (address slice) = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI - # next-token-from-slice(word->start, word->end, '/', twig) - # . . push args - 57/push-EDI - 68/push 0x2f/imm32/slash - 52/push-EDX - ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # curr/ECX = twig->end - 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX -$has-metadata?:loop: - # next-token-from-slice(curr, word->end, '/', twig) - # . . push args - 57/push-EDI - 68/push 0x2f/imm32/slash - 52/push-EDX - 51/push-ECX - # . . call - 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 - # . EAX = slice-empty?(twig) - # . . push args - 57/push-EDI - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) return false - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $has-metadata?:false/disp8 - # 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) - 57/push-EDI - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return true - 3d/compare-EAX-and 0/imm32 - 75/jump-if-not-equal $has-metadata?:true/disp8 - # curr = twig->end - 8b/copy 1/mod/*+disp8 7/rm32/EDI . . . 1/r32/ECX 4/disp8 . # copy *(EDI+4) to ECX - eb/jump $has-metadata?:loop/disp8 -$has-metadata?:true: - b8/copy-to-EAX 1/imm32/true - eb/jump $has-metadata?:end/disp8 -$has-metadata?:false: - b8/copy-to-EAX 0/imm32/false -$has-metadata?:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-has-metadata-true: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "ab/imm32" - b8/copy-to-EAX "ab/imm32"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var in/ESI : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # EAX = has-metadata?(ESI, "imm32") - # . . push args - 68/push "imm32"/imm32 - 56/push-ESI - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-has-metadata-true"/imm32 - 68/push 1/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-has-metadata-false: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "ab/c" - b8/copy-to-EAX "ab/c"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var in/ESI : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # EAX = has-metadata?(ESI, "d") - # . . push args - 68/push "d"/imm32 - 56/push-ESI - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-has-metadata-false"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-has-metadata-ignore-name: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "a/b" - b8/copy-to-EAX "a/b"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var in/ESI : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # EAX = has-metadata?(ESI, "a") - # . . push args - 68/push "a"/imm32 - 56/push-ESI - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-has-metadata-ignore-name"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-has-metadata-multiple-true: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "a/b/c" - b8/copy-to-EAX "a/b/c"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var in/ESI : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # EAX = has-metadata?(ESI, "c") - # . . push args - 68/push "c"/imm32 - 56/push-ESI - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-has-metadata-multiple-true"/imm32 - 68/push 1/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-has-metadata-multiple-false: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "a/b/c" - b8/copy-to-EAX "a/b/c"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var in/ESI : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI - # EAX = has-metadata?(ESI, "d") - # . . push args - 68/push "d"/imm32 - 56/push-ESI - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-has-metadata-multiple-false"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# If datum of 'word' is not a valid name, it must be a hex int. Parse and print -# it in 'width' bytes of hex, least significant first. -# Otherwise just print the entire word including metadata. -# Always print a trailing space. -emit: # out : (address buffered-file), word : (address slice), width : int -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 56/push-ESI - 57/push-EDI - # ESI = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # var name/EDI : (address slice) = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI - # datum = next-token-from-slice(word->start, word->end, '/') - # . . push args - 57/push-EDI - 68/push 0x2f/imm32/slash - ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # push *(ESI+4) - ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI - # . . call - 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-valid-name?(datum)) write-slice-buffered(out, word) and return - # . EAX = is-valid-name?(name) - # . . push args - 57/push-EDI - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit:hex-int/disp8 -$emit:name: - # . write-slice-buffered(out, word) - # . . push args - 56/push-ESI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write-buffered(out, " ") - # . . push args - 68/push " "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . return - eb/jump $emit:end/disp8 - # otherwise emit-hex(out, parse-hex-int(datum), width) - # (Weird shit can happen here if the datum of 'word' isn't either a valid - # name or a hex number, but we're only going to be passing in real legal - # programs. We just want to make sure that valid names aren't treated as - # (valid) hex numbers.) -$emit:hex-int: - # . value/EAX = parse-hex-int(datum) - # . . push args - 57/push-EDI - # . . call - e8/call parse-hex-int/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . emit-hex(out, value, width) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$emit:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-number: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "30" - b8/copy-to-EAX "30"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit(_test-output-buffered-file, slice, 1) - # . . push args - 68/push 1/imm32 - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "30 ", msg) - # . . push args - 68/push "F - test-emit-number/1"/imm32 - 68/push "30 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-negative-number: - # test support for sign-extending negative numbers - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "-2" - b8/copy-to-EAX "-2"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit(_test-output-buffered-file, slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "fe ff ", msg) - # . . push args - 68/push "F - test-emit-number/1"/imm32 - 68/push "fe ff "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-number-with-metadata: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "-2/foo" - b8/copy-to-EAX "-2/foo"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit(_test-output-buffered-file, slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # the '/foo' will have no impact on the output - # check-stream-equal(_test-output-stream, "fe ff ", msg) - # . . push args - 68/push "F - test-emit-number-with-metadata"/imm32 - 68/push "fe ff "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-non-number: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "xyz" - b8/copy-to-EAX "xyz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit(_test-output-buffered-file, slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "xyz", msg) - # . . push args - 68/push "F - test-emit-non-number"/imm32 - 68/push "xyz "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-non-number-with-metadata: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "xyz/" - b8/copy-to-EAX "xyz/"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit(_test-output-buffered-file, slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "xyz/", msg) - # . . push args - 68/push "F - test-emit-non-number-with-metadata"/imm32 - 68/push "xyz/ "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-non-number-with-all-hex-digits-and-metadata: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # (EAX..ECX) = "abcd/xyz" - b8/copy-to-EAX "abcd/xyz"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit(_test-output-buffered-file, slice, 2) - # . . push args - 68/push 2/imm32 - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-stream-equal(_test-output-stream, "abcd/xyz") - # . . push args - 68/push "F - test-emit-non-number-with-all-hex-digits"/imm32 - 68/push "abcd/xyz "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# conditions for 'valid' names that are not at risk of looking like hex numbers -# keep in sync with the rules in labels.cc -#: - if it starts with a digit, it's treated as a number. If it can't be -#: parsed as hex it will raise an error. -#: - if it starts with '-' it's treated as a number. -#: - if it starts with '0x' it's treated as a number. (redundant) -#: - if it's two characters long, it can't be a name. Either it's a hex -#: byte, or it raises an error. -is-valid-name?: # in : (address slice) -> EAX : boolean - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 56/push-ESI - # ESI = in - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # start/ECX = in->start - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - # end/EAX = in->end - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX -$is-valid-name?:check0: - # if (start >= end) return false - 39/compare 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # compare ECX with EAX - 73/jump-if-greater-or-equal-unsigned $is-valid-name?:false/disp8 -$is-valid-name?:check1: - # EAX -= ECX - 29/subtract 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # subtract ECX from EAX - # if (EAX == 2) return false - 3d/compare-EAX-and 2/imm32 - 74/jump-if-equal $is-valid-name?:false/disp8 -$is-valid-name?:check2: - # c/EAX = *ECX - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL - # if (c == "-") return false - 3d/compare-EAX-and 2d/imm32/- - 74/jump-if-equal $is-valid-name?:false/disp8 -$is-valid-name?:check3a: - # if (c < "0") return true - 3d/compare-EAX-with 30/imm32/0 - 7c/jump-if-lesser $is-valid-name?:true/disp8 -$is-valid-name?:check3b: - # if (c > "9") return true - 3d/compare-EAX-with 39/imm32/9 - 7f/jump-if-greater $is-valid-name?:true/disp8 -$is-valid-name?:false: - # return false - b8/copy-to-EAX 0/imm32/false - eb/jump $is-valid-name?:end/disp8 -$is-valid-name?:true: - # return true - b8/copy-to-EAX 1/imm32/true -$is-valid-name?:end: - # . restore registers - 5e/pop-to-ESI - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-valid-name-digit-prefix: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "34" - b8/copy-to-EAX "34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = is-valid-name?(slice) - # . . push args - 51/push-ECX - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-is-valid-name-digit-prefix"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-valid-name-negative-prefix: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "-0x34" - b8/copy-to-EAX "-0x34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = is-valid-name?(slice) - # . . push args - 51/push-ECX - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-is-valid-name-negative-prefix"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-valid-name-0x-prefix: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "0x34" - b8/copy-to-EAX "0x34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = is-valid-name?(slice) - # . . push args - 51/push-ECX - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-is-valid-name-0x-prefix"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-valid-name-starts-with-pre-digit: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "/03" - b8/copy-to-EAX "/03"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = is-valid-name?(slice) - # . . push args - 51/push-ECX - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-is-valid-name-starts-with-pre-digit"/imm32 - 68/push 1/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-valid-name-starts-with-post-digit: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "q34" - b8/copy-to-EAX "q34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = is-valid-name?(slice) - # . . push args - 51/push-ECX - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-is-valid-name-starts-with-post-digit"/imm32 - 68/push 1/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-valid-name-starts-with-digit: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # (EAX..ECX) = "0x34" - b8/copy-to-EAX "0x34"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # EAX = is-valid-name?(slice) - # . . push args - 51/push-ECX - # . . call - e8/call is-valid-name?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-is-valid-name-starts-with-digit"/imm32 - 68/push 0/imm32/false - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# print 'n' in hex in 'width' bytes in lower-endian order, with a space after every byte -emit-hex: # out : (address buffered-file), n : int, width : int -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 57/push-EDI - # EDI = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI - # EBX = n - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 3/r32/EBX 0xc/disp8 . # copy *(EBP+12) to EBX - # EDX = width - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0x10/disp8 . # copy *(EBP+16) to EDX - # var curr/ECX = 0 - 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX -$emit-hex:loop: - # if (curr >= width) break - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 7d/jump-if-greater-or-equal $emit-hex:end/disp8 - # print-byte-buffered(out, EBX) - # . . push args - 53/push-EBX - 57/push-EDI - # . . call - e8/call print-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-byte-buffered(out, ' ') - # . . push args - 68/push 0x20/imm32/space - 57/push-EDI - # . . call - e8/call write-byte-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # EBX = EBX >> 8 - c1/shift 5/subop/logic-right 3/mod/direct 3/rm32/EBX . . . . . 8/imm8 # shift EBX right by 8 bits, while padding zeroes -$emit-hex:continue: - # ++curr - 41/increment-ECX - eb/jump $emit-hex:loop/disp8 -$emit-hex:end: - # . restore registers - 5f/pop-to-EDI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-hex-single-byte: - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # emit-hex(_test-output-buffered-file, 0xab, 1) - # . . push args - 68/push 1/imm32 - 68/push 0xab/imm32 - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(*_test-output-stream->data, 'ab ', msg) - # . . push args - 68/push "F - test-emit-hex-single-byte"/imm32 - 68/push 0x206261/imm32 - # . . push *_test-output-stream->data - b8/copy-to-EAX _test-output-stream/imm32 - ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12) - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . end - c3/return - -test-emit-hex-multiple-byte: - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # emit-hex(_test-output-buffered-file, 0x1234, 2) - # . . push args - 68/push 2/imm32 - 68/push 0x1234/imm32 - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream, "34 12 ", msg) - # . . push args - 68/push "F - test-emit-hex-multiple-byte/1"/imm32 - 68/push "34 12 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . end - c3/return - -test-emit-hex-zero-pad: - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # emit-hex(_test-output-buffered-file, 0xab, 2) - # . . push args - 68/push 2/imm32 - 68/push 0xab/imm32 - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check(_test-output-stream->data == 'ab 00 ') - # . . push args - 68/push "F - test-emit-hex-zero-pad/1"/imm32 - 68/push "ab 00 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . end - c3/return - -test-emit-hex-negative: - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # emit-hex(_test-output-buffered-file, -1, 2) - # . . push args - 68/push 2/imm32 - 68/push -1/imm32 - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-stream-equal(_test-output-stream == "ff ff ") - # . . push args - 68/push "F - test-emit-hex-negative/1"/imm32 - 68/push "ff ff "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-stream-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . end - c3/return - -# print 'arr' in hex with a space after every byte -emit-hex-array: # out : (address buffered-file), arr : (address array byte) -> <void> - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 57/push-EDI - # EDI = out - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 8/disp8 . # copy *(EBP+8) to EDI - # EDX = arr # <== 0xbdffffe4 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 2/r32/EDX 0xc/disp8 . # copy *(EBP+12) to EDX - # curr/ECX = arr->data - 8d/copy-address 1/mod/*+disp8 2/rm32/EDX . . . 1/r32/ECX 4/disp8 . # copy EDX+4 to ECX - # max/EDX = arr->data + arr->length - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 2/r32/EDX . . # copy *EDX to EDX - 01/add 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # add ECX to EDX - # EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX -$emit-hex-array:loop: - # if (curr >= width) break - 39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX - 73/jump-if-greater-or-equal-unsigned $emit-hex-array:end/disp8 - # emit-hex(out, *curr, width=1) - # . . push args - 68/push 1/imm32/width - 8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL - 50/push-EAX - 57/push-EDI - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # ++curr - 41/increment-ECX - eb/jump $emit-hex-array:loop/disp8 -$emit-hex-array:end: - # . restore registers - 5f/pop-to-EDI - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-hex-array: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . 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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # var arr/ECX (address array byte) = [01, 02, 03] - 68/push 0x00030201/imm32 # bytes 01 02 03 - 68/push 3/imm32/length - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # emit-hex-array(_test-output-buffered-file, arr) - # . . push args - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call emit-hex-array/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(_test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} - # check-next-stream-line-equal(_test-output-stream, "01 02 03 ", msg) - # . . push args - 68/push "F - test-emit-hex-array"/imm32 - 68/push "01 02 03 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -compute-width: # word : (address array byte) -> EAX : int - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - # EAX = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 8/disp8 . # copy *(EBP+8) to ECX - # ECX = word + word->length - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - # EAX = word->data - 05/add-to-EAX 4/imm32 - # var in/ECX : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # return compute-width-of-slice(ECX) - # . . push args - 51/push-ECX - # . . call - e8/call compute-width-of-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$compute-width:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -compute-width-of-slice: # s : (address slice) -> EAX : int - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - # ECX = s - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - # if (has-metadata?(word, "imm32")) return 4 - # . EAX = has-metadata?(word, "imm32") - # . . push args - 68/push "imm32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return 4 - 3d/compare-EAX-and 0/imm32 - b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now - 75/jump-if-not-equal $compute-width-of-slice:end/disp8 - # if (has-metadata?(word, "disp32")) return 4 - # . EAX = has-metadata?(word, "disp32") - # . . push args - 68/push "disp32"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return 4 - 3d/compare-EAX-and 0/imm32 - b8/copy-to-EAX 4/imm32 # ZF is set, so we can overwrite EAX now - 75/jump-if-not-equal $compute-width-of-slice:end/disp8 - # if (has-metadata?(word, "imm16")) return 2 - # . EAX = has-metadata?(word, "imm16") - # . . push args - 68/push "imm16"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return 2 - 3d/compare-EAX-and 0/imm32 - b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now - 75/jump-if-not-equal $compute-width-of-slice:end/disp8 - # if (has-metadata?(word, "disp16")) return 2 - # . EAX = has-metadata?(word, "disp16") - # . . push args - 68/push "disp16"/imm32 - 51/push-ECX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) return 2 - 3d/compare-EAX-and 0/imm32 - b8/copy-to-EAX 2/imm32 # ZF is set, so we can overwrite EAX now - 75/jump-if-not-equal $compute-width-of-slice:end/disp8 - # otherwise return 1 - b8/copy-to-EAX 1/imm32 -$compute-width-of-slice:end: - # . restore registers - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-compute-width: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -$test-compute-width:imm8: - # EAX = compute-width("0x2/imm8") - # . . push args - 68/push "0x2/imm8"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-compute-width: 0x2/imm8"/imm32 - 50/push-EAX - 68/push 1/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 -$test-compute-width:imm16: - # EAX = compute-width("4/imm16") - # . . push args - 68/push "4/imm16"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 2, msg) - # . . push args - 68/push "F - test-compute-width: 4/imm16"/imm32 - 50/push-EAX - 68/push 2/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 -$test-compute-width:imm32: - # EAX = compute-width("4/imm32") - # . . push args - 68/push "4/imm32"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 4, msg) - # . . push args - 68/push "F - test-compute-width: 4/imm32"/imm32 - 50/push-EAX - 68/push 4/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 -$test-compute-width:disp8: - # EAX = compute-width("foo/disp8") - # . . push args - 68/push "foo/disp8"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-compute-width: foo/disp8"/imm32 - 50/push-EAX - 68/push 1/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 -$test-compute-width:disp16: - # EAX = compute-width("foo/disp16") - # . . push args - 68/push "foo/disp16"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 2, msg) - # . . push args - 68/push "F - test-compute-width: foo/disp16"/imm32 - 50/push-EAX - 68/push 2/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 -$test-compute-width:disp32: - # EAX = compute-width("foo/disp32") - # . . push args - 68/push "foo/disp32"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 4, msg) - # . . push args - 68/push "F - test-compute-width: foo/disp32"/imm32 - 50/push-EAX - 68/push 4/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 -$test-compute-width:no-metadata: - # EAX = compute-width("45") - # . . push args - 68/push "45"/imm32 - # . . call - e8/call compute-width/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-compute-width: 45 (no metadata)"/imm32 - 50/push-EAX - 68/push 1/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 - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -is-label?: # word : (address slice) -> EAX : boolean - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - # ECX = word - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 8/disp8 . # copy *(EBP+8) to ECX - # ECX = word->end - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 1/r32/ECX 4/disp8 . # copy *(ECX+4) to ECX - # return *(word->end - 1) == ':' - # . EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - # . EAX = *((char *) word->end - 1) - 8a/copy-byte 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/AL -1/disp8 . # copy byte at *(ECX-1) to AL - # . return (EAX == ':') - 3d/compare-EAX-and 0x3a/imm32/colon - b8/copy-to-EAX 1/imm32/true - 74/jump-if-equal $is-label?:end/disp8 - b8/copy-to-EAX 0/imm32/false -$is-label?:end: - # . restore registers - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-is-label?: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -$test-is-label?:true: - # (EAX..ECX) = "AAA:" - b8/copy-to-EAX "AAA:"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # is-label?(slice/ECX) - # . . push args - 51/push-ECX - # . . call - e8/call is-label?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 1, msg) - # . . push args - 68/push "F - test-is-label?:true"/imm32 - 68/push 1/imm32 - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$test-is-label?:false: - # (EAX..ECX) = "AAA" - b8/copy-to-EAX "AAA"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var slice/ECX = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # is-label?(slice/ECX) - # . . push args - 51/push-ECX - # . . call - e8/call is-label?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-is-label?:false"/imm32 - 68/push 0/imm32 - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -_test-input-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 0x100/imm32 # 256 bytes - # data (16 lines x 16 bytes/line) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# a test buffered file for _test-input-stream -_test-input-buffered-file: - # file descriptor or (address stream) - _test-input-stream/imm32 - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 6/imm32 - # data - 00 00 00 00 00 00 # 6 bytes - -_test-output-stream: - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 0x200/imm32 # 512 bytes - # data (32 lines x 16 bytes/line) - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - -# a test buffered file for _test-output-stream -_test-output-buffered-file: - # file descriptor or (address stream) - _test-output-stream/imm32 - # current write index - 0/imm32 - # current read index - 0/imm32 - # length - 6/imm32 - # data - 00 00 00 00 00 00 # 6 bytes - -_test-data-segment: - 64/d 61/a 74/t 61/a -_test-data-segment-end: - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/survey b/subx/apps/survey deleted file mode 100755 index 621efa5c..00000000 --- a/subx/apps/survey +++ /dev/null Binary files differdiff --git a/subx/apps/survey.subx b/subx/apps/survey.subx deleted file mode 100644 index 15957fa2..00000000 --- a/subx/apps/survey.subx +++ /dev/null @@ -1,4787 +0,0 @@ -# Assign addresses (co-ordinates) to instructions (landmarks) in a program -# (landscape). -# Use the addresses assigned to: -# a) replace labels -# b) add segment headers with addresses and offsets correctly filled in -# -# To build (from the subx/ directory): -# $ ./subx translate *.subx apps/survey.subx -o apps/survey -# -# The expected input is a stream of bytes with segment headers, comments and -# some interspersed labels. -# $ cat x -# == code 0x1 -# l1: -# aa bb l1/imm8 -# cc dd l2/disp32 -# l2: -# ee foo/imm32 -# == data 0x10 -# foo: -# 00 -# -# The output is the stream of bytes without segment headers or label definitions, -# and with label references replaced with numeric values/displacements. -# -# $ cat x |./subx run apps/assort -# ...ELF header bytes... -# # ELF header above will specify that code segment begins at this offset -# aa bb nn # some computed address -# cc dd nn nn nn nn # some computed displacement -# ee nn nn nn nn # some computed address -# # ELF header above will specify that data segment begins at this offset -# 00 -# -# The ELF format has some persnickety constraints on the starting addresses of -# segments, so input headers are treated as guidelines and adjusted in the -# output. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: - # Heap = new-segment(Heap-size) - # . . push args - 68/push Heap/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # initialize-trace-stream(256KB) - # . . push args - 68/push 0x40000/imm32/256KB - # . . call - e8/call initialize-trace-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - - # run tests if necessary, convert stdin if not - # . prolog - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # initialize heap - # - 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - otherwise convert stdin - # convert(Stdin, Stdout) - # . . push args - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -# data structures: -# segment-info: {address, file-offset, size} (12 bytes) -# segments: (address stream {string, segment-info}) (16 bytes per row) -# label-info: {segment-name, segment-offset, address} (12 bytes) -# labels: (address stream {string, label-info}) (16 bytes per row) -# these are all inefficient; use sequential scans for lookups - -convert: # infile : (address buffered-file), out : (address buffered-file) -> <void> - # pseudocode - # var in : (address stream byte) = stream(4096) - # slurp(infile, in) - # var segments = new-stream(10 rows, 16 bytes each) - # var labels = new-stream(Max-labels rows, 16 bytes each) - # compute-offsets(in, segments, labels) - # compute-addresses(segments, labels) - # rewind-stream(in) - # emit-output(in, out, segments, labels) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 56/push-ESI - # var segments/ECX = stream(10 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 68/push 0xa0/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var labels/EDX = stream(Max-labels * 16) - # . data - 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/ESP Max-labels/disp32 # subtract *Max-labels from ESP - # . length - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Max-labels/disp32 # push *Max-labels - # . read - 68/push 0/imm32/read - # . write - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # var in/ESI = stream(Input-size * 1) - # . data - 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/ESP Input-size/disp32 # subtract *Input-size from ESP - # . length - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Input-size/disp32 # push *Input-size - # . read - 68/push 0/imm32/read - # . write - 68/push 0/imm32/write - 89/copy 3/mod/direct 6/rm32/ESI . . . 4/r32/ESP . . # copy ESP to ESI -#? # dump labels->write {{{ -#? # . write(2/stderr, "labels->write right after initialization: ") -#? # . . push args -#? 68/push "labels->write right after initialization: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . print-int32-buffered(Stderr, labels->write) -#? # . . push args -#? $watch-1: -#? ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "\n") -#? # . . push args -#? 68/push "\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # write(2/stderr, "slurp in\n") {{{ -#? # . . push args -#? 68/push "slurp in\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # slurp(infile, in) - # . . push args - 56/push-ESI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call slurp/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump labels->write {{{ -#? # . write(2/stderr, "labels->write after slurp: ") -#? # . . push args -#? 68/push "labels->write after slurp: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . print-int32-buffered(Stderr, labels->write) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "\n") -#? # . . push args -#? 68/push "\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # dump in {{{ -#? # . write(2/stderr, "in: ") -#? # . . push args -#? 68/push "in: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # write-stream(2/stderr, in) -#? # . . push args -#? 56/push-ESI -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(in) -#? # . . push args -#? 56/push-ESI -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} -#? # write(2/stderr, "compute-offsets\n") {{{ -#? # . . push args -#? 68/push "compute-offsets\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # compute-offsets(in, segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - 56/push-ESI - # . . call - e8/call compute-offsets/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -#? # write(2/stderr, "compute-addresses\n") {{{ -#? # . . push args -#? 68/push "compute-addresses\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # compute-addresses(segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call compute-addresses/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x8/imm32 # add to ESP - # rewind-stream(in) - # . . push args - 56/push-ESI - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # write(2/stderr, "emit-output\n") {{{ -#? # . . push args -#? 68/push "emit-output\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # dump labels->write {{{ -#? # . write(2/stderr, "labels->write after rewinding input: ") -#? # . . push args -#? 68/push "labels->write after rewinding input: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . print-int32-buffered(Stderr, labels) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "\n") -#? # . . push args -#? 68/push "\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # emit-output(in, out, segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - 56/push-ESI - # . . call - e8/call emit-output/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # flush(out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$convert:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x30a0/imm32 # add to ESP - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-convert-computes-addresses: - # input: - # == code 0x1 - # Entry: - # ab x/imm32 - # == data 0x1000 - # x: - # 01 - # - # trace contains (in any order): - # label x is at address 0x1079 - # segment code starts at address 0x74 - # segment code has size 5 - # segment data starts at address 0x1079 - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-input-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-input-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . 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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # initialize input - # . write(_test-input-stream, "== code 0x1\n") - # . . push args - 68/push "== code 0x1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "Entry:\n") - # . . push args - 68/push "Entry:\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "ab x/imm32\n") - # . . push args - 68/push "ab x/imm32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x1000\n") - # . . push args - 68/push "== data 0x1000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "x:\n") - # . . push args - 68/push "x:\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "01\n") - # . . push args - 68/push "01\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # convert(_test-input-buffered-file, _test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-buffered-file/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # check trace -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-trace-contains("label 'x' is at address 0x00001079.", msg) - # . . push args - 68/push "F - test-convert-computes-addresses/0"/imm32 - 68/push "label 'x' is at address 0x00001079."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'code' starts at address 0x00000074.", msg) - # . . push args - 68/push "F - test-convert-computes-addresses/1"/imm32 - 68/push "segment 'code' starts at address 0x00000074."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'code' has size 0x00000005.", msg) - # . . push args - 68/push "F - test-convert-computes-addresses/2"/imm32 - 68/push "segment 'code' has size 0x00000005."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'data' starts at address 0x00001079.", msg) - # . . push args - 68/push "F - test-convert-computes-addresses/3"/imm32 - 68/push "segment 'data' starts at address 0x00001079."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# global scratch space for compute-offsets in the data segment -== data - -compute-offsets:file-offset: # int - 0/imm32 -compute-offsets:segment-offset: # int - 0/imm32 -compute-offsets:word-slice: - 0/imm32/start - 0/imm32/end -compute-offsets:segment-tmp: # slice - 0/imm32/start - 0/imm32/end - -== code - -compute-offsets: # in : (address stream), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - # skeleton: - # for lines in 'in' - # for words in line - # switch word - # case 1 - # case 2 - # ... - # default - # - # pseudocode: - # curr-segment-name : (address string) = 0 - # var line = new-stream(512, 1) - # while true # line loop - # clear-stream(line) - # read-line(in, line) - # if (line->write == 0) break # end of file - # while true # word loop - # word-slice = next-word(line) - # if slice-empty?(word-slice) # end of line - # break - # else if slice-starts-with?(word-slice, "#") # comment - # break # end of line - # else if slice-equal?(word-slice, "==") - # if curr-segment-name != 0 - # seg = get-or-insert(segments, curr-segment-name) - # seg->size = *file-offset - seg->file-offset - # trace("segment '", curr-segment-name, "' has size ", seg->size) - # segment-tmp = next-word(line) - # curr-segment-name = slice-to-string(segment-tmp) - # if empty?(curr-segment-name) - # abort - # segment-tmp = next-word(line) - # if slice-empty?(segment-tmp) - # abort - # seg = get-or-insert(segments, curr-segment-name) - # seg->starting-address = parse-hex-int(segment-tmp) - # seg->file-offset = *file-offset - # trace("segment '", curr-segment-name, "' is at file offset ", seg->file-offset) - # segment-offset = 0 - # break (next line) - # else if is-label?(word-slice) - # strip trailing ':' from word-slice - # x : (address label-info) = get-or-insert(labels, name) - # x->segment-name = curr-segment-name - # trace("label '", word-slice, "' is in segment '", curr-segment-name, "'.") - # x->segment-offset = segment-offset - # trace("label '", word-slice, "' is at segment offset ", segment-offset, ".") - # # labels occupy no space, so no need to increment offsets - # else - # width = compute-width-of-slice(word-slice) - # *segment-offset += width - # *file-offset += width - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # curr-segment-name/ESI = 0 - 31/xor 3/mod/direct 6/rm32/ESI . . . 6/r32/ESI . . # clear ESI - # file-offset = 0 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:file-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice - # segment-offset = 0 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *compute-offsets:word-slice - # line/ECX = new-stream(512, 1) - # . EAX = new-stream(512, 1) - # . . push args - 68/push 1/imm32 - 68/push 0x200/imm32 - 68/push Heap/imm32 - # . . call - e8/call new-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . line/ECX = EAX - 89/copy 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # copy EAX to ECX -$compute-offsets:line-loop: - # clear-stream(line/ECX) - 51/push-ECX - e8/call clear-stream/disp32 - # . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # read-line(in, line/ECX) - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - e8/call read-line/disp32 - # . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if (line->write == 0) break - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $compute-offsets:break-line-loop/disp32 -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # write-stream(2/stderr, line) -#? # . . push args -#? 51/push-ECX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(line) -#? # . . push args -#? 51/push-ECX -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} -$compute-offsets:word-loop: - # EDX = word-slice - ba/copy-to-EDX compute-offsets:word-slice/imm32 - # next-word(line/ECX, word-slice/EDX) - 52/push-EDX - 51/push-ECX - e8/call next-word/disp32 - # . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice and maybe curr-segment-name {{{ -#? # . write(2/stderr, "w: ") -#? # . . push args -#? 68/push "w: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 52/push-EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . if (curr-segment-name == 0) print curr-segment-name -#? 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI -#? 74/jump-if-equal $compute-offsets:case-empty/disp8 -#? # . write(2/stderr, "segment at start of word: ") -#? # . . push args -#? 68/push "segment at start of word: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-buffered(Stderr, curr-segment-name) -#? # . . push args -#? 56/push-ESI -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$compute-offsets:case-empty: - # if slice-empty?(word/EDX) break - # . EAX = slice-empty?(word/EDX) - 52/push-EDX - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32 -$compute-offsets:case-comment: - # if slice-starts-with?(word-slice, "#") continue - 68/push "#"/imm32 - 52/push-EDX - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $compute-offsets:line-loop/disp32 -$compute-offsets:case-segment-header: - # if (!slice-equal?(word-slice/EDX, "==")) goto next case - # . EAX = slice-equal?(word-slice/EDX, "==") - 68/push "=="/imm32 - 52/push-EDX - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next case - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $compute-offsets:case-label/disp32 - # if (curr-segment-name == 0) goto construct-next-segment - 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI - 74/jump-if-equal $compute-offsets:construct-next-segment/disp8 - # seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 56/push-ESI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # seg->size = file-offset - seg->file-offset - # . save ECX - 51/push-ECX - # . EBX = *file-offset - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX - # . ECX = seg->file-offset - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX - # . EBX -= ECX - 29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX - # . seg->size = EBX - 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8) - # . restore ECX - 59/pop-to-ECX - # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".") - # . . push args - 68/push "."/imm32 - 53/push-EBX - 68/push "' has size "/imm32 - 56/push-ESI - 68/push "segment '"/imm32 - # . . call - e8/call trace-sssns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -$compute-offsets:construct-next-segment: - # next-word(line/ECX, segment-tmp) - 68/push compute-offsets:segment-tmp/imm32 - 51/push-ECX - e8/call next-word/disp32 - # . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump curr-segment-name if not null (clobbering EAX) {{{ -#? # . if (curr-segment-name == 0) goto update-curr-segment-name -#? 81 7/subop/compare 3/mod/direct 6/rm32/ESI . . . . . 0/imm32 # compare ESI -#? 74/jump-if-equal $compute-offsets:update-curr-segment-name/disp8 -#? # . write(2/stderr, "setting segment to: ") -#? # . . push args -#? 68/push "setting segment to: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . write-buffered(Stderr, curr-segment-name) -#? # . . push args -#? 56/push-ESI -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$compute-offsets:update-curr-segment-name: - # curr-segment-name = slice-to-string(segment-tmp) - # . EAX = slice-to-string(Heap, segment-tmp) - # . . push args - 68/push compute-offsets:segment-tmp/imm32 - 68/push Heap/imm32 - # . . call - e8/call slice-to-string/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . curr-segment-name = EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI - # if empty?(curr-segment-name) abort - # . if (EAX == 0) abort - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $compute-offsets:abort/disp32 - # next-word(line/ECX, segment-tmp) - 68/push compute-offsets:segment-tmp/imm32 - 51/push-ECX - e8/call next-word/disp32 - # . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # if slice-empty?(segment-tmp) abort - # . EAX = slice-empty?(segment-tmp) - 68/push compute-offsets:segment-tmp/imm32 - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) abort - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $compute-offsets:abort/disp32 - # seg/EBX = get-or-insert(segments, curr-segment-name, row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 56/push-ESI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . EBX = EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to EBX - # seg->address = parse-hex-int(segment-tmp) - # . EAX = parse-hex-int(segment-tmp) - 68/push compute-offsets:segment-tmp/imm32 - e8/call parse-hex-int/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . seg->address = EAX - 89/copy 0/mod/indirect 3/rm32/EBX . . . 0/r32/EAX . . # copy EAX to *EBX - # seg->file-offset = *file-offset - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # copy *file-offset to EAX - 89/copy 1/mod/*+disp8 3/rm32/EBX . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EBX+4) - # trace-sssns("segment '", curr-segment-name, "' is at file offset ", seg->file-offset, "") - # . . push args - 68/push "."/imm32 - 50/push-EAX - 68/push "' is at file offset "/imm32 - 56/push-ESI - 68/push "segment '"/imm32 - # . . call - e8/call trace-sssns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # segment-offset = 0 - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 0/imm32 # copy to *segment-offset - # break - e9/jump $compute-offsets:line-loop/disp32 -$compute-offsets:case-label: - # if (!is-label?(word-slice/EDX)) goto next case - # . EAX = is-label?(word-slice/EDX) - # . . push args - 52/push-EDX - # . . call - e8/call is-label?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX == 0) goto next case - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $compute-offsets:case-default/disp8 - # strip trailing ':' from word-slice - ff 1/subop/decrement 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # decrement *(EDX+4) - # x/EAX = leaky-get-or-insert-slice(labels, word-slice, row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - # . . call - e8/call leaky-get-or-insert-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -$compute-offsets:save-label-offset: - # x->segment-name = curr-segment-name - 89/copy 0/mod/indirect 0/rm32/EAX . . . 6/r32/ESI . . # copy ESI to *EAX - # trace-slsss("label '" word-slice/EDX "' is in segment '" current-segment-name "'.") - # . . push args - 68/push "'."/imm32 - 56/push-ESI - 68/push "' is in segment '"/imm32 - 52/push-EDX - 68/push "label '"/imm32 - # . . call - e8/call trace-slsss/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # x->segment-offset = segment-offset - # . EBX = segment-offset - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:segment-offset/disp32 # copy *segment-offset to EBX - # . x->segment-offset = EBX - 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 4/disp8 . # copy EBX to *(EAX+4) - # trace-slsns("label '" word-slice/EDX "' is at segment offset " *segment-offset/EAX ".") - # . . EAX = file-offset - b8/copy-to-EAX compute-offsets:segment-offset/imm32 - # . . EAX = *file-offset/EAX - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX - # . . push args - 68/push "."/imm32 - 50/push-EAX - 68/push "' is at segment offset "/imm32 - 52/push-EDX - 68/push "label '"/imm32 - # . . call - e8/call trace-slsns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # continue - e9/jump $compute-offsets:word-loop/disp32 -$compute-offsets:case-default: - # width/EAX = compute-width-of-slice(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call compute-width-of-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # segment-offset += width - 01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:segment-offset/disp32 # add EAX to *segment-offset - # file-offset += width - 01/add 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX compute-offsets:file-offset/disp32 # add EAX to *file-offset -#? # dump segment-offset {{{ -#? # . write(2/stderr, "segment-offset: ") -#? # . . push args -#? 68/push "segment-offset: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . print-int32-buffered(Stderr, segment-offset) -#? # . . push args -#? 52/push-EDX -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . compute-offsets:segment-offset/disp32 # push *segment-offset -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "\n") -#? # . . push args -#? 68/push "\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - e9/jump $compute-offsets:word-loop/disp32 -$compute-offsets:break-line-loop: - # seg/EAX = get-or-insert(segments, curr-segment-name, row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 56/push-ESI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call get-or-insert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # seg->size = file-offset - seg->file-offset - # . save ECX - 51/push-ECX - # . EBX = *file-offset - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX compute-offsets:file-offset/disp32 # copy *file-offset to EBX - # . ECX = seg->file-offset - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX - # . EBX -= ECX - 29/subtract 3/mod/direct 3/rm32/EBX . . . 1/r32/ECX . . # subtract ECX from EBX - # . seg->size = EBX - 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy EBX to *(EAX+8) - # . restore ECX - 59/pop-to-ECX - # trace-sssns("segment '", curr-segment-name, "' has size ", seg->size, ".") - # . trace-sssns("segment '", curr-segment-name, "' has size ", EBX, ".") - # . . push args - 68/push "."/imm32 - 53/push-EBX - 68/push "' has size "/imm32 - 56/push-ESI - 68/push "segment '"/imm32 - # . . call - e8/call trace-sssns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -$compute-offsets:end: - # . reclaim locals - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return -$compute-offsets:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "'==' must be followed by segment name and segment-start\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -test-compute-offsets: - # input: - # == code 0x1 - # ab x/imm32 # skip comment - # == data 0x1000 - # 00 - # x: - # 34 - # - # trace contains (in any order): - # segment 'code' is at file offset 0x0. - # segment 'code' has size 0x5. - # segment 'data' is at file offset 0x5. - # segment 'data' has size 0x2. - # label 'x' is in segment 'data'. - # label 'x' is at segment offset 0x1. - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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 - # var segments/ECX = stream(2 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x20/imm32 # subtract from ESP - 68/push 0x20/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var labels/EDX = stream(2 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x20/imm32 # subtract from ESP - 68/push 0x20/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # initialize input - # . write(_test-input-stream, "== code 0x1\n") - # . . push args - 68/push "== code 0x1\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "ab x/imm32 # skip comment\n") - # . . push args - 68/push "ab x/imm32 # skip comment\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x1000\n") - # . . push args - 68/push "== data 0x1000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "00\n") - # . . push args - 68/push "00\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "x:\n") - # . . push args - 68/push "x:\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "34\n") - # . . push args - 68/push "34\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # compute-offsets(_test-input-stream, segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - 68/push _test-input-stream/imm32 - # . . call - e8/call compute-offsets/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check trace - # . check-trace-contains("segment 'code' is at file offset 0x00000000.", msg) - # . . push args - 68/push "F - test-compute-offsets/0"/imm32 - 68/push "segment 'code' is at file offset 0x00000000."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'code' has size 0x00000005", msg) - # . . push args - 68/push "F - test-compute-offsets/1"/imm32 - 68/push "segment 'code' has size 0x00000005."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'data' is at file offset 0x00000005.", msg) - # . . push args - 68/push "F - test-compute-offsets/2"/imm32 - 68/push "segment 'data' is at file offset 0x00000005."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'data' has size 0x00000002.", msg) - # . . push args - 68/push "F - test-compute-offsets/3"/imm32 - 68/push "segment 'data' has size 0x00000002."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("label 'x' is in segment 'data'.", msg) - # . . push args - 68/push "F - test-compute-offsets/4"/imm32 - 68/push "label 'x' is in segment 'data'."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("label 'x' is at segment offset 0x00000001.", msg) - # . . push args - 68/push "F - test-compute-offsets/5"/imm32 - 68/push "label 'x' is at segment offset 0x00000001."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-ints-equal(labels->write, 0x10, msg) - # . . push args - 68/push "F - test-compute-offsets-maintains-labels-write-index"/imm32 - 68/push 0x10/imm32/1-entry - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -compute-addresses: # segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - # pseudocode: - # srow : (address segment-info) = segments->data - # max = segments->data + segments->write - # num-segments = segments->write / 16 - # starting-offset = 0x34 + (num-segments * 0x20) - # while true - # if (srow >= max) break - # s->file-offset += starting-offset - # s->address &= 0xfffff000 # clear last 12 bits for p_align - # s->address += (s->file-offset & 0x00000fff) - # trace-sssns("segment " s->key " starts at address " s->address) - # srow += 16 # row-size - # lrow : (address label-info) = labels->data - # max = labels->data + labels->write - # while true - # if (lrow >= max) break - # seg-name : (address string) = lrow->segment-name - # label-seg : (address segment-info) = get(segments, seg-name, row-size=16) - # lrow->address = label-seg->address + lrow->segment-offset - # trace-sssns("label " lrow->key " is at address " lrow->address) - # lrow += 16 # row-size - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # ESI = segments - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # starting-offset/EDI = 0x34 + (num-segments * 0x20) # make room for ELF headers - # . EDI = segments->write / 16 (row-size) - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 7/r32/EDI . . # copy *ESI to EDI - c1/shift 5/subop/logic-right 3/mod/direct 7/rm32/EDI . . . . . 4/imm8 # shift EDI right by 4 bits, while padding zeroes - # . EDI = (EDI * 0x20) + 0x34 - c1/shift 4/subop/left 3/mod/direct 7/rm32/EDI . . . . . 5/imm8 # shift EDI left by 5 bits - 81 0/subop/add 3/mod/direct 7/rm32/EDI . . . . . 0x34/imm32 # add to EDI - # srow/EAX = segments->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX - # max/ECX = segments->data + segments->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 01/add 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # add ESI to ECX -$compute-addresses:segment-loop: - # if (srow >= max) break - 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX - 73/jump-if-greater-or-equal-unsigned $compute-addresses:segment-break/disp8 - # srow->file-offset += starting-offset - 01/add 1/mod/*+disp8 0/rm32/EAX . . . 7/r32/EDI 8/disp8 . # add EDI to *(EAX+8) - # clear last 12 bits of srow->address for p_align=0x1000 - # . EDX = srow->address - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy *(EAX+4) to EDX - # . EDX &= 0xfffff000 - 81 4/subop/and 3/mod/direct 2/rm32/EDX . . . . . 0xfffff000/imm32 # bitwise and of EDX - # update last 12 bits from srow->file-offset - # . EBX = srow->file-offset - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # copy *(EAX+8) to EBX - # . EBX &= 0xfff - 81 4/subop/and 3/mod/direct 3/rm32/EBX . . . . . 0x00000fff/imm32 # bitwise and of EBX - # . srow->address = EDX | EBX - 09/or 3/mod/direct 2/rm32/EDX . . . 3/r32/EBX . . # EDX = bitwise OR with EBX - 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy EDX to *(EAX+4) - # trace-sssns("segment " srow " starts at address " srow->address ".") - # . . push args - 68/push "."/imm32 - 52/push-EDX - 68/push "' starts at address "/imm32 - ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX - 68/push "segment '"/imm32 - # . . call - e8/call trace-sssns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # srow += 16 # size of row - 05/add-to-EAX 0x10/imm32 - eb/jump $compute-addresses:segment-loop/disp8 -$compute-addresses:segment-break: -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # ESI = labels - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # lrow/EAX = labels->data - 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy ESI+12 to EAX - # max/ECX = labels->data + labels->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 1/r32/ECX . . # copy *ESI to ECX - 01/add 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # add ESI to ECX -$compute-addresses:label-loop: - # if (lrow >= max) break - 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX - 0f 83/jump-if-greater-or-equal-unsigned $compute-addresses:end/disp32 -#? # dump lrow->key {{{ -#? # . write(2/stderr, "label: ") -#? # . . push args -#? 68/push "label: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, lrow->key) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # seg-name/EDX = lrow->segment-name - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 2/r32/EDX 4/disp8 . # copy *EAX to EDX -#? # dump seg-name {{{ -#? # . write(2/stderr, "compute-addresses: seg-name: ") -#? # . . push args -#? 68/push "seg-name: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, seg-name) -#? # . . push args -#? 52/push-EDX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # label-seg/EDX : (address segment-info) = get(segments, seg-name, row-size=16) - # . save EAX - 50/push-EAX - # . EAX = get(segments, seg-name, row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call get/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . EDX = EAX - 89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX - # . restore EAX - 58/pop-to-EAX - # EBX = label-seg->address - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 3/r32/EBX . . # copy *EDX to EBX - # EBX += lrow->segment-offset - 03/add 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 8/disp8 . # add *(EAX+8) to EBX - # lrow->address = EBX - 89/copy 1/mod/*+disp8 0/rm32/EAX . . . 3/r32/EBX 0xc/disp8 . # copy EBX to *(EAX+12) - # trace-sssns("label " lrow->key " is at address " lrow->address ".") - # . . push args - 68/push "."/imm32 - 53/push-EBX - 68/push "' is at address "/imm32 - ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX - 68/push "label '"/imm32 - # . . call - e8/call trace-sssns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # lrow += 16 # size of row - 05/add-to-EAX 0x10/imm32 - e9/jump $compute-addresses:label-loop/disp32 -$compute-addresses:end: - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-compute-addresses: - # input: - # segments: - # - 'a': {0x1000, 0, 5} - # - 'b': {0x2018, 5, 1} - # - 'c': {0x5444, 6, 12} - # labels: - # - 'l1': {'a', 3, 0} - # - 'l2': {'b', 0, 0} - # - # trace contains in any order (comments in parens): - # segment 'a' starts at address 0x00001094. (0x34 + 0x20 for each segment) - # segment 'b' starts at address 0x00002099. (0x018 discarded) - # segment 'c' starts at address 0x0000509a. (0x444 discarded) - # label 'l1' is at address 0x00001097. (0x1094 + segment-offset 3) - # label 'l2' is at address 0x00002099. (0x2099 + segment-offset 0) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . var segments/ECX = stream(10 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 68/push 0xa0/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . var labels/EDX = stream(512 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP - 68/push 0x2000/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # . stream-add4(segments, "a", 0x1000, 0, 5) - 68/push 5/imm32/segment-size - 68/push 0/imm32/file-offset - 68/push 0x1000/imm32/start-address - 68/push "a"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(segments, "b", 0x2018, 5, 1) - 68/push 1/imm32/segment-size - 68/push 5/imm32/file-offset - 68/push 0x2018/imm32/start-address - 68/push "b"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(segments, "c", 0x5444, 6, 12) - 68/push 0xc/imm32/segment-size - 68/push 6/imm32/file-offset - 68/push 0x5444/imm32/start-address - 68/push "c"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(labels, "l1", "a", 3, 0) - 68/push 0/imm32/label-address - 68/push 3/imm32/segment-offset - 68/push "a"/imm32/segment-name - 68/push "l1"/imm32/label-name - 52/push-EDX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(labels, "l2", "b", 0, 0) - 68/push 0/imm32/label-address - 68/push 0/imm32/segment-offset - 68/push "b"/imm32/segment-name - 68/push "l2"/imm32/label-name - 52/push-EDX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # component under test - # . compute-addresses(segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call compute-addresses/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # checks -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . check-trace-contains("segment 'a' starts at address 0x00001094.", msg) - # . . push args - 68/push "F - test-compute-addresses/0"/imm32 - 68/push "segment 'a' starts at address 0x00001094."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'b' starts at address 0x00002099.", msg) - # . . push args - 68/push "F - test-compute-addresses/1"/imm32 - 68/push "segment 'b' starts at address 0x00002099."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'c' starts at address 0x0000509a.", msg) - # . . push args - 68/push "F - test-compute-addresses/2"/imm32 - 68/push "segment 'c' starts at address 0x0000509a."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("label 'l1' is at address 0x00001097.", msg) - # . . push args - 68/push "F - test-compute-addresses/3"/imm32 - 68/push "label 'l1' is at address 0x00001097."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("label 'l2' is at address 0x00002099.", msg) - # . . push args - 68/push "F - test-compute-addresses/4"/imm32 - 68/push "label 'l2' is at address 0x00002099."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-ints-equal(labels->write, 0x20, msg) - # . . push args - 68/push "F - test-compute-addresses/maintains-labels-write-index"/imm32 - 68/push 0x20/imm32/2-entries - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-compute-addresses-large-segments: - # input: - # segments: - # - 'a': {0x1000, 0, 0x5604} - # - 'b': {0x2018, 0x5604, 1} - # labels: - # - 'l1': {'a', 3, 0} - # - # trace contains in any order (comments in parens): - # segment 'a' starts at address 0x00001074. (0x34 + 0x20 for each segment) - # segment 'b' starts at address 0x00002678. (0x018 discarded; last 3 nibbles from 0x1074 + 0x5604) - # label 'l1' is at address 0x00001077. (0x1074 + segment-offset 3) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . var segments/ECX = stream(10 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 68/push 0xa0/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . var labels/EDX = stream(512 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP - 68/push 0x2000/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # . stream-add4(segments, "a", 0x1000, 0, 0x5604) - 68/push 0x5604/imm32/segment-size - 68/push 0/imm32/file-offset - 68/push 0x1000/imm32/start-address - 68/push "a"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(segments, "b", 0x2018, 0x5604, 1) - 68/push 1/imm32/segment-size - 68/push 0x5604/imm32/file-offset - 68/push 0x2018/imm32/start-address - 68/push "b"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(labels, "l1", "a", 3, 0) - 68/push 0/imm32/label-address - 68/push 3/imm32/segment-offset - 68/push "a"/imm32/segment-name - 68/push "l1"/imm32/label-name - 52/push-EDX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # component under test - # . compute-addresses(segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call compute-addresses/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # checks - # . check-trace-contains("segment 'a' starts at address 0x00001074.", msg) - # . . push args - 68/push "F - test-compute-addresses-large-segments/0"/imm32 - 68/push "segment 'a' starts at address 0x00001074."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("segment 'b' starts at address 0x00002678.", msg) - # . . push args - 68/push "F - test-compute-addresses-large-segments/1"/imm32 - 68/push "segment 'b' starts at address 0x00002678."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . check-trace-contains("label 'l1' is at address 0x00001077.", msg) - # . . push args - 68/push "F - test-compute-addresses-large-segments/3"/imm32 - 68/push "label 'l1' is at address 0x00001077."/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-output: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - # pseudocode: - # emit-headers(out, segments, labels) - # emit-segments(in, out, segments, labels) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP -#? # write(2/stderr, "emit-headers\n") {{{ -#? # . . push args -#? 68/push "emit-headers\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # emit-headers(out, segments, labels) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-headers/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -#? # write(2/stderr, "emit-segments\n") {{{ -#? # . . push args -#? 68/push "emit-segments\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # emit-segments(in, out, segments, labels) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-segments/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -$emit-output:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-segments: # in : (address stream), out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - # pseudocode: - # var offset-of-next-instruction = 0 - # var line = new-stream(512, 1) - # line-loop: - # while true - # clear-stream(line) - # read-line(in, line) - # if (line->write == 0) break # end of file - # offset-of-next-instruction += num-bytes(line) - # while true - # var word-slice = next-word(line) - # if slice-empty?(word-slice) # end of line - # break - # if slice-starts-with?(word-slice, "#") # comment - # break - # if is-label?(word-slice) # no need for label declarations anymore - # goto line-loop # don't insert empty lines - # if slice-equal?(word-slice, "==") # no need for segment header lines - # goto line-loop # don't insert empty lines - # if length(word-slice) == 2 - # write-slice-buffered(out, word-slice) - # write-buffered(out, " ") - # continue - # datum = next-token-from-slice(word-slice->start, word-slice->end, "/") - # info = get-slice(labels, datum) - # if !string-equal?(info->segment-name, "code") - # if has-metadata?(word-slice, "disp8") - # abort - # if has-metadata?(word-slice, "imm8") - # abort - # emit(out, info->address, 4) # global variables always translate to absolute addresses - # # code segment cases - # else if has-metadata?(word-slice, "imm8") - # abort # label should never go to imm8 - # else if has-metadata?(word-slice, "imm32") - # emit(out, info->address, 4) - # else if has-metadata?(word-slice, "disp8") - # value = info->offset - offset-of-next-instruction - # emit(out, value, 1) - # else if has-metadata?(word-slice, "disp32") - # value = info->offset - offset-of-next-instruction - # emit(out, value, 4) - # else - # abort - # write-buffered(out, "\n") - # - # registers: - # line: ECX - # word-slice: EDX - # offset-of-next-instruction: EBX - # datum: EDI - # info: ESI (inner loop only) - # temporaries: EAX, ESI (outer loop) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 56/push-ESI - 57/push-EDI - # var line/ECX : (address stream byte) = stream(512) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP - 68/push 0x200/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var word-slice/EDX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # var datum/EDI = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 7/rm32/EDI . . . 4/r32/ESP . . # copy ESP to EDI - # offset-of-next-instruction/EBX = 0 - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX -$emit-segments:line-loop: - # clear-stream(line) - # . . 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 - # read-line(in, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-line/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # write-stream(2/stderr, line) -#? # . . push args -#? 51/push-ECX -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(line) -#? # . . push args -#? 51/push-ECX -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} -$emit-segments:check-for-end-of-input: - # if (line->write == 0) break - 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX - 0f 84/jump-if-equal $emit-segments:end/disp32 - # offset-of-next-instruction += num-bytes(line) - # . EAX = num-bytes(line) - # . . push args - 51/push-ECX - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . EBX += EAX - 01/add 3/mod/direct 3/rm32/EBX . . . 0/r32/EAX . . # add EAX to EBX -$emit-segments:word-loop: - # next-word(line, word-slice) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "w: ") -#? # . . push args -#? 68/push "w: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 52/push-EDX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-segments:check-for-end-of-line: - # if (slice-empty?(word-slice)) break - # . EAX = slice-empty?(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:next-line/disp32 -$emit-segments:check-for-comment: - # if (slice-starts-with?(word-slice, "#")) break - # . start/ESI = word-slice->start - 8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *EDX to ESI - # . c/EAX = *start - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 8a/copy-byte 0/mod/indirect 6/rm32/ESI . . . 0/r32/AL . . # copy byte at *ESI to AL - # . if (EAX == '#') break - 3d/compare-EAX-and 0x23/imm32/hash - 0f 84/jump-if-equal $emit-segments:next-line/disp32 -$emit-segments:check-for-label: - # if is-label?(word-slice) break - # . EAX = is-label?(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call is-label?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:line-loop/disp32 -$emit-segments:check-for-segment-header: - # if (slice-equal?(word-slice, "==")) break - # . EAX = slice-equal?(word-slice, "==") - # . . push args - 68/push "=="/imm32 - 52/push-EDX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:line-loop/disp32 -$emit-segments:2-character: - # if (length(word-slice) != 2) goto next check - # . EAX = length(word-slice) - 8b/copy 1/mod/*+disp8 2/rm32/EDX . . . 0/r32/EAX 4/disp8 . # copy *(EDX+4) to EAX - 2b/subtract 0/mod/indirect 2/rm32/EDX . . . 0/r32/EAX . . # subtract *EDX from EAX - # . if (EAX != 2) goto next check - 3d/compare-EAX-and 2/imm32 - 75/jump-if-not-equal $emit-segments:check-metadata/disp8 - # write-slice-buffered(out, word-slice) - # . . push args - 52/push-EDX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-buffered(out, " ") - # . . push args - 68/push " "/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # continue - e9/jump $emit-segments:word-loop/disp32 -$emit-segments:check-metadata: - # - if we get here, 'word-slice' must be a label to be looked up - # datum/EDI = next-token-from-slice(word-slice->start, word-slice->end, "/") - # . . push args - 57/push-EDI - 68/push 0x2f/imm32/slash - ff 6/subop/push 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # push *(EDX+4) - ff 6/subop/push 0/mod/indirect 2/rm32/EDX . . . . . . # push *EDX - # . . call - e8/call next-token-from-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "datum: ") -#? # . . push args -#? 68/push "datum: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 57/push-EDI -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # info/ESI = get-slice(labels, datum, row-size=16) - # . EAX = get-slice(labels, datum, row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 57/push-EDI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - # . . call - e8/call get-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . ESI = EAX - 89/copy 3/mod/direct 6/rm32/ESI . . . 0/r32/EAX . . # copy EAX to ESI -$emit-segments:check-global-variable: -#? # dump info->segment-name {{{ -#? # . write(2/stderr, "aa: label segment: ") -#? # . . push args -#? 68/push "aa: label segment: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, info->segment-name) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # if string-equal?(info->segment-name, "code") goto code label checks - # . EAX = string-equal?(info->segment-name, "code") - # . . push args - 68/push "code"/imm32 - ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) goto code label checks - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:check-code-label-for-imm8/disp32 -$emit-segments:check-global-variable-for-disp8: - # if has-metadata?(word-slice, "disp8") abort - # . EAX = has-metadata?(word-slice, "disp8") - # . . push args - 68/push "disp8"/imm32 - 52/push-EDX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) abort - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32 -$emit-segments:check-global-variable-for-imm8: - # if has-metadata?(word-slice, "imm8") abort - # . EAX = has-metadata?(word-slice, "imm8") - # . . push args - 68/push "imm8"/imm32 - 52/push-EDX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) abort - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:global-variable-abort/disp32 -$emit-segments:emit-global-variable: - # emit-hex(out, info->address, 4) - # . . push args - 68/push 4/imm32 - ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # continue - e9/jump $emit-segments:word-loop/disp32 -$emit-segments:check-code-label-for-imm8: - # if (has-metadata?(word-slice, "imm8")) abort - # . EAX = has-metadata?(EDX, "imm8") - # . . push args - 68/push "imm8"/imm32 - 52/push-EDX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) abort - 3d/compare-EAX-and 0/imm32 - 0f 85/jump-if-not-equal $emit-segments:imm8-abort/disp32 -$emit-segments:check-code-label-for-imm32: - # if (!has-metadata?(word-slice, "imm32")) goto next check - # . EAX = has-metadata?(EDX, "imm32") - # . . push args - 68/push "imm32"/imm32 - 52/push-EDX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-segments:check-code-label-for-disp8/disp8 -#? # dump info->address {{{ -#? # . write(2/stderr, "info->address: ") -#? # . . push args -#? 68/push "info->address: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . print-int32-buffered(Stderr, info->address) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$emit-segments:emit-code-label-imm32: - # emit-hex(out, info->address, 4) - # . . push args - 68/push 4/imm32 - ff 6/subop/push 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # push *(ESI+8) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # continue - e9/jump $emit-segments:word-loop/disp32 -$emit-segments:check-code-label-for-disp8: - # if (!has-metadata?(word-slice, "disp8")) goto next check - # . EAX = has-metadata?(EDX, "disp8") - # . . push args - 68/push "disp8"/imm32 - 52/push-EDX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-segments:check-code-label-for-disp32/disp8 -$emit-segments:emit-code-label-disp8: - # emit-hex(out, info->offset - offset-of-next-instruction, 1) - # . . push args - 68/push 1/imm32 - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - 29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # continue - e9/jump $emit-segments:word-loop/disp32 -$emit-segments:check-code-label-for-disp32: - # if (!has-metadata?(word-slice, "disp32")) abort - # . EAX = has-metadata?(EDX, "disp32") - # . . push args - 68/push "disp32"/imm32 - 52/push-EDX - # . . call - e8/call has-metadata?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) abort - 3d/compare-EAX-and 0/imm32 - 0f 84/jump-if-equal $emit-segments:abort/disp32 -$emit-segments:emit-code-label-disp32: - # emit-hex(out, info->offset - offset-of-next-instruction, 4) - # . . push args - 68/push 4/imm32 - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - 29/subtract 3/mod/direct 0/rm32/EAX . . . 3/r32/EBX . . # subtract EBX from EAX - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call emit-hex/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # continue - e9/jump $emit-segments:word-loop/disp32 -$emit-segments:next-line: - # write-buffered(out, "\n") - # . . push args - 68/push Newline/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # loop - e9/jump $emit-segments:line-loop/disp32 -$emit-segments:end: - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x21c/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5e/pop-to-ESI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$emit-segments:global-variable-abort: - # . _write(2/stderr, error) - # . . push args - 68/push "emit-segments: must refer to global variables with /disp32 or /imm32"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -$emit-segments:imm8-abort: - # . _write(2/stderr, error) - # . . push args - 68/push "emit-segments: cannot refer to code labels with /imm8"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -$emit-segments:abort: - # print(stderr, "missing metadata in " word-slice) - # . _write(2/stderr, "missing metadata in word ") - # . . push args - 68/push "emit-segments: missing metadata in "/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write-slice-buffered(Stderr, word-slice) - # . . push args - 52/push-EDX - 68/push Stderr/imm32 - # . . call - e8/call write-slice-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . flush(Stderr) - # . . push args - 68/push Stderr/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -test-emit-segments-global-variable: - # global variables always convert to absolute addresses, regardless of metadata - # - # input: - # in: - # == code 0x1000 - # ab cd ef gh - # ij x/disp32 - # == data 0x2000 - # 00 - # x: - # 34 - # segments: - # - 'code': {0x1074, 0, 9} - # - 'data': {0x2079, 5, 2} - # labels: - # - 'x': {'data', 1, 0x207a} - # - # output: - # ab cd ef gh - # ij 7a 20 00 00 - # 00 - # 34 - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . var segments/ECX = stream(10 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 68/push 0xa0/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . var labels/EDX = stream(512 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP - 68/push 0x2000/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # initialize input - # . write(_test-input-stream, "== code 0x1000\n") - # . . push args - 68/push "== code 0x1000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "ab cd ef gh\n") - # . . push args - 68/push "ab cd ef gh\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "ij x/disp32\n") - # . . push args - 68/push "ij x/disp32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "== data 0x2000\n") - # . . push args - 68/push "== data 0x2000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "00\n") - # . . push args - 68/push "00\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "x:\n") - # . . push args - 68/push "x:\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "34\n") - # . . push args - 68/push "34\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . stream-add4(segments, "code", 0x1074, 0, 9) - 68/push 9/imm32/segment-size - 68/push 0/imm32/file-offset - 68/push 0x1074/imm32/start-address - 68/push "code"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(segments, "data", 0x2079, 5, 2) - 68/push 1/imm32/segment-size - 68/push 5/imm32/file-offset - 68/push 0x2079/imm32/start-address - 68/push "data"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(labels, "x", "data", 1, 0x207a) - 68/push 0x207a/imm32/label-address - 68/push 1/imm32/segment-offset - 68/push "data"/imm32/segment-name - 68/push "x"/imm32/label-name - 52/push-EDX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # component under test - # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call emit-segments/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # checks - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(_test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} - # . check-next-stream-line-equal(_test-output-stream, "ab cd ef gh ", msg) - # . . push args - 68/push "F - test-emit-segments-global-variable/0"/imm32 - 68/push "ab cd ef gh "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "ij 7a 20 00 00 ", msg) - # . . push args - 68/push "F - test-emit-segments-global-variable/1"/imm32 - 68/push "ij 7a 20 00 00 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "00 ", msg) - # . . push args - 68/push "F - test-emit-segments-global-variable/2"/imm32 - 68/push "00 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "34 ", msg) - # . . push args - 68/push "F - test-emit-segments-global-variable/3"/imm32 - 68/push "34 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-segments-code-label: - # labels usually convert to displacements - # - # input: - # in: - # == code 0x1000 - # ab cd - # l1: - # ef gh - # ij l1/disp32 - # segments: - # - 'code': {0x1054, 0, 9} - # labels: - # - 'l1': {'code', 2, 0x1056} - # - # output: - # ab cd - # ef gh - # ij f9 ff ff ff # -7 - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . var segments/ECX = stream(10 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 68/push 0xa0/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . var labels/EDX = stream(512 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP - 68/push 0x2000/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # initialize input - # . write(_test-input-stream, "== code 0x1000\n") - # . . push args - 68/push "== code 0x1000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "ab cd\n") - # . . push args - 68/push "ab cd\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "l1:\n") - # . . push args - 68/push "l1:\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, " ef gh\n") - # . . push args - 68/push " ef gh\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, " ij l1/disp32\n") - # . . push args - 68/push " ij l1/disp32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . stream-add4(segments, "code", 0x1054, 0, 9) - 68/push 9/imm32/segment-size - 68/push 0/imm32/file-offset - 68/push 0x1054/imm32/start-address - 68/push "code"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(labels, "l1", "code", 2, 0x1056) - 68/push 0x1056/imm32/label-address - 68/push 2/imm32/segment-offset - 68/push "code"/imm32/segment-name - 68/push "l1"/imm32/label-name - 52/push-EDX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # component under test - # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call emit-segments/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # checks - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(_test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} - # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg) - # . . push args - 68/push "F - test-emit-segments-code-label/0"/imm32 - 68/push "ab cd "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg) - # . . push args - 68/push "F - test-emit-segments-code-label/1"/imm32 - 68/push "ef gh "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg) - # . . push args - 68/push "F - test-emit-segments-code-label/2"/imm32 - 68/push "ij f9 ff ff ff "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-emit-segments-code-label-absolute: - # labels can also convert to absolute addresses - # - # input: - # in: - # == code 0x1000 - # ab cd - # l1: - # ef gh - # ij l1/imm32 - # segments: - # - 'code': {0x1054, 0, 9} - # labels: - # - 'l1': {'code', 2, 0x1056} - # - # output: - # ab cd - # ef gh - # ij 56 10 00 00 - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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-output-buffered-file+4) - # . . push args - b8/copy-to-EAX _test-output-buffered-file/imm32 - 05/add-to-EAX 4/imm32 - 50/push-EAX - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . var segments/ECX = stream(10 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0xa0/imm32 # subtract from ESP - 68/push 0xa0/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # . var labels/EDX = stream(512 * 16) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x2000/imm32 # subtract from ESP - 68/push 0x2000/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # initialize input - # . write(_test-input-stream, "== code 0x1000\n") - # . . push args - 68/push "== code 0x1000\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "ab cd\n") - # . . push args - 68/push "ab cd\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, "l1:\n") - # . . push args - 68/push "l1:\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, " ef gh\n") - # . . push args - 68/push " ef gh\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . write(_test-input-stream, " ij l1/imm32\n") - # . . push args - 68/push " ij l1/imm32\n"/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . stream-add4(segments, "code", 0x1054, 0, 9) - 68/push 9/imm32/segment-size - 68/push 0/imm32/file-offset - 68/push 0x1054/imm32/start-address - 68/push "code"/imm32/segment-name - 51/push-ECX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # . stream-add4(labels, "l1", "code", 2, 0x1056) - 68/push 0x1056/imm32/label-address - 68/push 2/imm32/segment-offset - 68/push "code"/imm32/segment-name - 68/push "l1"/imm32/label-name - 52/push-EDX - # . . call - e8/call stream-add4/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP - # component under test - # . emit-segments(_test-input-stream, _test-output-buffered-file, segments, labels) - # . . push args - 52/push-EDX - 51/push-ECX - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call emit-segments/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x10/imm32 # add to ESP - # checks - # . flush(_test-output-buffered-file) - # . . push args - 68/push _test-output-buffered-file/imm32 - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . rewind-stream(_test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? # . . call -#? e8/call rewind-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # }}} - # . check-next-stream-line-equal(_test-output-stream, "ab cd ", msg) - # . . push args - 68/push "F - test-emit-segments-code-label-absolute/0"/imm32 - 68/push "ab cd "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "ef gh ", msg) - # . . push args - 68/push "F - test-emit-segments-code-label-absolute/1"/imm32 - 68/push "ef gh "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "ij f9 ff ff ff ", msg) - # . . push args - 68/push "F - test-emit-segments-code-label-absolute/2"/imm32 - 68/push "ij 56 10 00 00 "/imm32 - 68/push _test-output-stream/imm32 - # . . call - e8/call check-next-stream-line-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-headers: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - # pseudocode: - # emit-elf-header(out, segments, labels) - # curr-segment = segments->data - # max = segments->data + segments->write - # while true - # if (curr-segment >= max) break - # emit-elf-program-header-entry(out, curr-segment) - # curr-segment += 16 # size of a row - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX -#? # write(2/stderr, "emit-elf-header\n") {{{ -#? # . . push args -#? 68/push "emit-elf-header\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # emit-elf-header(out, segments, labels) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-elf-header/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # EAX = segments - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX - # ECX = segments->write - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - # curr-segment/EAX = segments->data - 8d/copy-address 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 0xc/disp8 . # copy EAX+12 to EAX - # max/ECX = segments->data + segments->write - 01/add 3/mod/direct 1/rm32/ECX . . . 0/r32/EAX . . # add EAX to ECX -$emit-headers:loop: - # if (curr-segment >= max) break - 39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX - 0f 83/jump-if-greater-or-equal-unsigned $emit-headers:end/disp32 -#? # dump curr-segment->name {{{ -#? # . write(2/stderr, "about to emit ph entry: segment->name: ") -#? # . . push args -#? 68/push "about to emit ph entry: segment->name: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . print-int32-buffered(Stderr, &curr-segment) -#? # . . push args -#? 50/push-EAX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, " -> ") -#? # . . push args -#? 68/push " -> "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . print-int32-buffered(Stderr, curr-segment->name) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 0/rm32/EAX . . . . . . # push *EAX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call print-int32-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "\n") -#? # . . push args -#? 68/push "\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -#? # write(2/stderr, "emit-segment-header\n") {{{ -#? # . . push args -#? 68/push "emit-segment-header\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # emit-elf-program-header-entry(out, curr-segment) - # . . push args - 50/push-EAX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-elf-program-header-entry/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # curr-segment += 16 # size of a row - 81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0x10/imm32 # add to EAX - e9/jump $emit-headers:loop/disp32 -$emit-headers:end: - # . restore registers - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-elf-header: # out : (address buffered-file), segments : (address stream {string, segment-info}), labels : (address stream {string, label-info}) - # pseudocode - # *Elf_e_entry = get(labels, "Entry")->address - # *Elf_e_phnum = segments->write / 16 # size of a row - # emit-hex-array(out, Elf_header) - # write-buffered(out, "\n") - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX # just because we need to call idiv - # *Elf_e_entry = get(labels, "Entry")->address - # . EAX = labels - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0x10/disp8 . # copy *(EBP+16) to EAX - # . label-info/EAX = get(labels, "Entry", row-size=16) - # . . push args - 68/push 0x10/imm32/row-size - 68/push "Entry"/imm32 - 50/push-EAX - # . . call - e8/call get/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . EAX = label-info->address - 8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 0/r32/EAX 8/disp8 . # copy *(EAX+8) to EAX - # . *Elf_e_entry = EAX - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_entry/disp32 # copy EAX to *Elf_e_entry - # *Elf_e_phnum = segments->write / 0x10 - # . EAX = segments - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX - # . len/EAX = segments->write - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 0/r32/EAX . . # copy *EAX to EAX - # . EAX = len / 0x10 (destroying EDX) - b9/copy-to-ECX 0x10/imm32 - 31/xor 3/mod/direct 2/rm32/EDX . . . 2/r32/EDX . . # clear EDX - f7 7/subop/idiv 3/mod/direct 1/rm32/ECX . . . . . . # divide EDX:EAX by ECX, storing quotient in EAX and remainder in EDX - # . *Elf_e_phnum = EAX - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_e_phnum/disp32 # copy EAX to *Elf_e_phnum - # emit-hex-array(out, Elf_header) - # . . push args - 68/push Elf_header/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-hex-array/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-buffered(out, "\n") - # . . push args - 68/push "\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$emit-elf-header:end: - # . restore registers - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -emit-elf-program-header-entry: # out : (address buffered-file), curr-segment : (address {string, segment-info}) - # pseudocode: - # *Elf_p_offset = curr-segment->file-offset - # *Elf_p_vaddr = curr-segment->address - # *Elf_p_paddr = curr-segment->address - # *Elf_p_filesz = curr-segment->size - # *Elf_p_memsz = curr-segment->size - # if curr-segment->name == "code" - # *Elf_p_flags = 5 # r-x - # else - # *Elf_p_flags = 6 # rw- - # emit-hex-array(out, Elf_program_header_entry) - # write-buffered(out, "\n") - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 56/push-ESI - # ESI = curr-segment - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI - # *Elf_p_offset = curr-segment->file-offset - # . EAX = curr-segment->file-offset - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 8/disp8 . # copy *(ESI+8) to EAX - # . *Elf_p_offset = EAX - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_offset/disp32 # copy EAX to *Elf_p_offset - # *Elf_p_vaddr = curr-segment->address - # . EAX = curr-segment->address - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX - # . *Elf_p_vaddr = EAX - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_vaddr/disp32 # copy EAX to *Elf_p_vaddr - # *Elf_p_paddr = curr-segment->address - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_paddr/disp32 # copy EAX to *Elf_p_paddr - # *Elf_p_filesz = curr-segment->size - # . EAX = curr-segment->size - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 0xc/disp8 . # copy *(ESI+12) to EAX - # . *Elf_p_filesz = EAX - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_filesz/disp32 # copy EAX to *Elf_p_filesz - # *Elf_p_memsz = curr-segment->size - 89/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Elf_p_memsz/disp32 # copy EAX to *Elf_p_memsz - # if (!string-equal?(curr-segment->name, "code") goto next check - # . EAX = curr-segment->name - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX - # . EAX = string-equal?(curr-segment->name, "code") - # . . push args - 68/push "code"/imm32 - 50/push-EAX - # . . call - e8/call string-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) goto next check - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $emit-elf-program-header-entry:data/disp8 - # *Elf_p_flags = r-x - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 5/imm32 # copy to *Elf_p_flags - eb/jump $emit-elf-program-header-entry:really-emit/disp8 -$emit-elf-program-header-entry:data: - # otherwise *Elf_p_flags = rw- - c7 0/subop/copy 0/mod/indirect 5/rm32/.disp32 . . . Elf_p_flags/disp32 6/imm32 # copy to *Elf_p_flags -$emit-elf-program-header-entry:really-emit: - # emit-hex-array(out, Elf_program_header_entry) - # . . push args - 68/push Elf_program_header_entry/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call emit-hex-array/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-buffered(out, "\n") - # . . push args - 68/push "\n"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call write-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$emit-elf-program-header-entry:end: - # . restore registers - 5e/pop-to-ESI - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# - some helpers for tests - -stream-add4: # in : (address stream byte), key : address, val1 : address, val2 : address, val3 : address - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 56/push-ESI - # ESI = in - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - # curr/EAX = in->data + in->write - # . EAX = in->write - 8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX - # . EAX = ESI+EAX+12 - 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 - # max/EDX = in->data + in->length - # . EDX = in->length - 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 2/r32/EDX 8/disp8 . # copy *(ESI+8) to EDX - # . EDX = ESI+EDX+12 - 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ESI+EDX+12 to EDX - # if (curr >= max) abort - 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX - 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 - # *curr = key - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX - 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX - # curr += 4 - 05/add-to-EAX 4/imm32 - # if (curr >= max) abort - 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX - 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 - # *curr = val1 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x10/disp8 . # copy *(EBP+16) to ECX - 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX - # curr += 4 - 05/add-to-EAX 4/imm32 - # if (curr >= max) abort - 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX - 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 - # *curr = val2 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x14/disp8 . # copy *(EBP+20) to ECX - 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX - # curr += 4 - 05/add-to-EAX 4/imm32 - # if (curr >= max) abort - 39/compare 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # compare EAX with EDX - 73/jump-if-greater-or-equal-unsigned $stream-add4:abort/disp8 - # *curr = val3 - 8b/copy 1/mod/*+disp8 5/rm32/EBP . . 1/r32/ECX 0x18/disp8 . # copy *(EBP+24) to ECX - 89/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy ECX to *EAX - # in->write += 16 - 81 0/subop/add 0/mod/indirect 6/rm32/ESI . . . . . 0x10/imm32 # add to *ESI -$stream-add4:end: - # . restore registers - 5e/pop-to-ESI - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -$stream-add4:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "overflow in stream-add4\n"/imm32 - 68/push 2/imm32/stderr - # . . call - e8/call _write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 1) - bb/copy-to-EBX 1/imm32 - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - # never gets here - -# some variants of 'trace' that take multiple arguments in different combinations of types: -# n: int -# c: character [4-bytes, will eventually be UTF-8] -# s: (address string) -# l: (address slice) -# one gotcha: 's5' must not be empty - -trace-sssns: # s1 : (address string), s2 : (address string), s3 : (address string), n4 : int, s5 : (address string) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # write(*Trace-stream, s1) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s2) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s3) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # print-int32(*Trace-stream, n4) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call print-int32/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # trace(s5) # implicitly adds a newline and finalizes the trace line - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) - # . . call - e8/call trace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$trace-sssns:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-trace-sssns: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . *Trace-stream->write = 0 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX - # trace-sssns("A" "b" "c " 3 " e") - # . . push args - 68/push " e"/imm32 - 68/push 3/imm32 - 68/push "c "/imm32 - 68/push "b"/imm32 - 68/push "A"/imm32 - # . . call - e8/call trace-sssns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-trace-contains("Abc 0x00000003 e") - # . . push args - 68/push "F - test-trace-sssns"/imm32 - 68/push "Abc 0x00000003 e"/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -trace-snsns: # s1 : (address string), n2 : int, s3 : (address string), n4 : int, s5 : (address string) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # write(*Trace-stream, s1) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # print-int32(*Trace-stream, n2) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call print-int32/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s3) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # print-int32(*Trace-stream, n4) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call print-int32/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # trace(s5) # implicitly adds a newline and finalizes the trace line - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) - # . . call - e8/call trace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$trace-snsns:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-trace-snsns: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . *Trace-stream->write = 0 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX - # trace-snsns("A " 2 " c " 3 " e") - # . . push args - 68/push " e"/imm32 - 68/push 3/imm32 - 68/push " c "/imm32 - 68/push 2/imm32 - 68/push "A "/imm32 - # . . call - e8/call trace-snsns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-trace-contains("Abc 0x00000003 e") - # . . push args - 68/push "F - test-trace-snsns"/imm32 - 68/push "A 0x00000002 c 0x00000003 e"/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -trace-slsls: # s1 : (address string), l2 : (address slice), s3 : (address string), l4 : (address slice), s5 : (address string) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # write(*Trace-stream, s1) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-slice(*Trace-stream, l2) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s3) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-slice(*Trace-stream, l4) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # trace(s5) # implicitly adds a newline and finalizes the trace line - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) - # . . call - e8/call trace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$trace-slsls:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-trace-slsls: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . *Trace-stream->write = 0 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX - # (EAX..ECX) = "b" - b8/copy-to-EAX "b"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var b/EBX : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX - # (EAX..ECX) = "d" - b8/copy-to-EAX "d"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var d/EDX : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # trace-slsls("A" b "c" d "e") - # . . push args - 68/push "e"/imm32 - 52/push-EDX - 68/push "c"/imm32 - 53/push-EBX - 68/push "A"/imm32 - # . . call - e8/call trace-slsls/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-trace-contains("Abcde") - # . . push args - 68/push "F - test-trace-slsls"/imm32 - 68/push "Abcde"/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -trace-slsns: # s1 : (address string), l2 : (address slice), s3 : (address string), n4 : int, s5 : (address string) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # write(*Trace-stream, s1) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-slice(*Trace-stream, l2) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s3) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # print-int32(*Trace-stream, n4) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call print-int32/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # trace(s5) # implicitly adds a newline and finalizes the trace line - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) - # . . call - e8/call trace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$trace-slsns:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-trace-slsns: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . *Trace-stream->write = 0 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX - # (EAX..ECX) = "b" - b8/copy-to-EAX "b"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var b/EBX : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX - # trace-slsls("A" b "c " 3 " e") - # . . push args - 68/push " e"/imm32 - 68/push 3/imm32 - 68/push "c "/imm32 - 53/push-EBX - 68/push "A"/imm32 - # . . call - e8/call trace-slsns/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-trace-contains("Abc 0x00000003 e") - # . . push args - 68/push "F - test-trace-slsls"/imm32 - 68/push "Abc 0x00000003 e"/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -trace-slsss: # s1 : (address string), l2 : (address slice), s3 : (address string), s4 : (address string), s5 : (address string) - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # write(*Trace-stream, s1) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-slice(*Trace-stream, l2) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s3) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(*Trace-stream, s4) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x14/disp8 . # push *(EBP+20) - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # trace(s5) # implicitly adds a newline and finalizes the trace line - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x18/disp8 . # push *(EBP+24) - # . . call - e8/call trace/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$trace-slsss:end: - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-trace-slsss: - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . *Trace-stream->write = 0 - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 0/r32/EAX Trace-stream/disp32 # copy *Trace-stream to EAX - c7 0/subop/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # clear *EAX - # (EAX..ECX) = "b" - b8/copy-to-EAX "b"/imm32 - 8b/copy 0/mod/indirect 0/rm32/EAX . . . 1/r32/ECX . . # copy *EAX to ECX - 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 - 05/add-to-EAX 4/imm32 - # var b/EBX : (address slice) = {EAX, ECX} - 51/push-ECX - 50/push-EAX - 89/copy 3/mod/direct 3/rm32/EBX . . . 4/r32/ESP . . # copy ESP to EBX - # trace-slsss("A" b "c" "d" "e") - # . . push args - 68/push "e"/imm32 - 68/push "d"/imm32 - 68/push "c"/imm32 - 53/push-EBX - 68/push "A"/imm32 - # . . call - e8/call trace-slsss/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x14/imm32 # add to ESP -#? # dump *Trace-stream {{{ -#? # . write(2/stderr, "^") -#? # . . push args -#? 68/push "^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, *Trace-stream) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-stream/disp32 # push *Trace-stream -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # check-trace-contains("Abcde") - # . . push args - 68/push "F - test-trace-slsss"/imm32 - 68/push "Abcde"/imm32 - # . . call - e8/call check-trace-contains/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -num-bytes: # line : (address stream) -> EAX : int - # pseudocode: - # result = 0 - # while true - # var word-slice = next-word(line) - # if slice-empty?(word-slice) # end of line - # break - # if slice-starts-with?(word-slice, "#") # comment - # break - # if is-label?(word-slice) # no need for label declarations anymore - # break - # if slice-equal?(word-slice, "==") - # break # no need for segment header lines - # result += compute-width(word-slice) - # return result - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 51/push-ECX - 52/push-EDX - 53/push-EBX - # var result/EAX = 0 - 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - # var word-slice/ECX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX -#? # dump line {{{ -#? # . write(2/stderr, "LL: ") -#? # . . push args -#? 68/push "LL: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # write-stream(2/stderr, line) -#? # . . push args -#? ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} - # . rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -$num-bytes:loop: - # next-word(line, word-slice) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # dump word-slice {{{ -#? # . write(2/stderr, "AA: ") -#? # . . push args -#? 68/push "AA: "/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . clear-stream(Stderr+4) -#? # . . save EAX -#? 50/push-EAX -#? # . . push args -#? b8/copy-to-EAX Stderr/imm32 -#? 05/add-to-EAX 4/imm32 -#? 50/push-EAX -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . . restore EAX -#? 58/pop-to-EAX -#? # . write-slice-buffered(Stderr, word-slice) -#? # . . push args -#? 51/push-ECX -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-slice-buffered/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . flush(Stderr) -#? # . . push args -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call flush/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} -$num-bytes:check0: - # if (slice-empty?(word-slice)) break - # . save result - 50/push-EAX - # . EAX = slice-empty?(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call slice-empty?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - # . restore result now that ZF is set - 58/pop-to-EAX - 75/jump-if-not-equal $num-bytes:end/disp8 -$num-bytes:check-for-comment: - # if (slice-starts-with?(word-slice, "#")) break - # . start/EDX = word-slice->start - 8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX - # . c/EBX = *start - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX - 8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 3/r32/BL . . # copy byte at *EDX to BL - # . if (EBX == '#') break - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x23/imm32/hash # compare EBX - 74/jump-if-equal $num-bytes:end/disp8 -$num-bytes:check-for-label: - # if (slice-ends-with?(word-slice, ":")) break - # . end/EDX = word-slice->end - 8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX - # . c/EBX = *(end-1) - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX - 8a/copy-byte 1/mod/*+disp8 2/rm32/EDX . . . 3/r32/BL -1/disp8 . # copy byte at *ECX to BL - # . if (EBX == ':') break - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0x3a/imm32/colon # compare EBX - 74/jump-if-equal $num-bytes:end/disp8 -$num-bytes:check-for-segment-header: - # if (slice-equal?(word-slice, "==")) break - # . push result - 50/push-EAX - # . EAX = slice-equal?(word-slice, "==") - # . . push args - 68/push "=="/imm32 - 51/push-ECX - # . . call - e8/call slice-equal?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX != 0) break - 3d/compare-EAX-and 0/imm32 - # . restore result now that ZF is set - 58/pop-to-EAX - 75/jump-if-not-equal $num-bytes:end/disp8 -$num-bytes:loop-body: - # result += compute-width-of-slice(word-slice) - # . copy result to EDX - 89/copy 3/mod/direct 2/rm32/EDX . . . 0/r32/EAX . . # copy EAX to EDX - # . EAX = compute-width-of-slice(word-slice) - # . . push args - 51/push-ECX - # . . call - e8/call compute-width-of-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . EAX += result - 01/add 3/mod/direct 0/rm32/EAX . . . 2/r32/EDX . . # add EDX to EAX - e9/jump $num-bytes:loop/disp32 -$num-bytes:end: - # . rewind-stream(line) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . restore registers - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-handles-empty-string: - # if a line starts with '#', return 0 - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # no contents in input - # EAX = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-num-bytes-handles-empty-string"/imm32 - 68/push 0/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-ignores-comments: - # if a line starts with '#', return 0 - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # initialize input - # . write(_test-input-stream, "# abcd") - # . . push args - 68/push "# abcd"/imm32 - 68/push _test-input-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 = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-num-bytes-ignores-comments"/imm32 - 68/push 0/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-ignores-labels: - # if the first word ends with ':', return 0 - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # initialize input - # . write(_test-input-stream, "ab: # cd") - # . . push args - 68/push "ab: # cd"/imm32 - 68/push _test-input-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 = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-num-bytes-ignores-labels"/imm32 - 68/push 0/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-ignores-segment-headers: - # if the first word is '==', return 0 - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # initialize input - # . write(_test-input-stream, "== ab cd") - # . . push args - 68/push "== ab cd"/imm32 - 68/push _test-input-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 = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 0, msg) - # . . push args - 68/push "F - test-num-bytes-ignores-segment-headers"/imm32 - 68/push 0/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-counts-words-by-default: - # without metadata, count words - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # initialize input - # . write(_test-input-stream, "ab cd ef") - # . . push args - 68/push "ab cd ef"/imm32 - 68/push _test-input-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 = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 3, msg) - # . . push args - 68/push "F - test-num-bytes-counts-words-by-default"/imm32 - 68/push 3/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-ignores-trailing-comment: - # trailing comments appropriately ignored - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # initialize input - # . write(_test-input-stream, "ab cd # ef") - # . . push args - 68/push "ab cd # ef"/imm32 - 68/push _test-input-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 = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 2, msg) - # . . push args - 68/push "F - test-num-bytes-ignores-trailing-comment"/imm32 - 68/push 2/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -test-num-bytes-handles-imm32: - # if a word has the /imm32 metadata, count it as 4 bytes - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # setup - # . clear-stream(_test-input-stream) - # . . push args - 68/push _test-input-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-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 - # initialize input - # . write(_test-input-stream, "ab cd/imm32 ef") - # . . push args - 68/push "ab cd/imm32 ef"/imm32 - 68/push _test-input-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 = num-bytes(_test-input-stream) - # . . push args - 68/push _test-input-stream/imm32 - # . . call - e8/call num-bytes/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # check-ints-equal(EAX, 6, msg) - # . . push args - 68/push "F - test-num-bytes-handles-imm32"/imm32 - 68/push 6/imm32/true - 50/push-EAX - # . . call - e8/call check-ints-equal/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -== data - -# This block of bytes gets copied to the start of the output ELF file, with -# some fields filled in. -# http://www.sco.com/developers/gabi/latest/ch4.eheader.html -Elf_header: - # - length - 0x34/imm32 - # - data -$e_ident: - 7f 45/E 4c/L 46/F - 01/32-bit 01/little-endian 01/file-version 00/no-os-extensions - 00 00 00 00 00 00 00 00 # 8 bytes of padding -$e_type: - 02 00 -$e_machine: - 03 00 -$e_version: - 1/imm32 -Elf_e_entry: - 0x09000000/imm32 # approximate default; must be updated -$e_phoff: - 0x34/imm32 # offset for the 'program header table' containing segment headers -$e_shoff: - 0/imm32 # no sections -$e_flags: - 0/imm32 # unused -$e_ehsize: - 0x34 00 -$e_phentsize: - 0x20 00 -Elf_e_phnum: - 00 00 # number of segments; must be updated -$e_shentsize: - 00 00 # no sections -$e_shnum: - 00 00 -$e_shstrndx: - 00 00 - -# This block of bytes gets copied after the Elf_header once for each segment. -# Some fields need filling in each time. -# https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-83432/index.html -Elf_program_header_entry: - # - length - 0x20/imm32 - # - data -$p_type: - 1/imm32/PT_LOAD -Elf_p_offset: - 0/imm32 # byte offset in the file at which a segment begins; must be updated -Elf_p_vaddr: - 0/imm32 # starting address to store the segment at before running the program -Elf_p_paddr: - 0/imm32 # should have same value as Elf_p_vaddr -Elf_p_filesz: - 0/imm32 -Elf_p_memsz: - 0/imm32 # should have same value as Elf_p_filesz -Elf_p_flags: - 6/imm32/rw- # read/write/execute permissions for the segment; must be updated for the code segment -$p_align: - # we hold this constant; changing it will require adjusting the way we - # compute the starting address for each segment - 0x1000/imm32 - -# . . vim:nowrap:textwidth=0 diff --git a/subx/apps/tests b/subx/apps/tests deleted file mode 100755 index 52af8441..00000000 --- a/subx/apps/tests +++ /dev/null Binary files differdiff --git a/subx/apps/tests.subx b/subx/apps/tests.subx deleted file mode 100644 index 12f4902b..00000000 --- a/subx/apps/tests.subx +++ /dev/null @@ -1,279 +0,0 @@ -# Generate code for a new function called 'run-tests' which calls in sequence -# all functions starting with 'test-'. - -== code -# instruction effective address register displacement immediate -# . op subop mod rm32 base index scale r32 -# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes - -Entry: - # Heap = new-segment(Heap-size) - # . . push args - 68/push Heap/imm32 - 68/push Heap-size/imm32 - # . . call - e8/call new-segment/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # initialize-trace-stream(256KB) - # . . push args - 68/push 0x40000/imm32/256KB - # . . call - e8/call initialize-trace-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - - # run tests if necessary, convert stdin if not - # . prolog - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # initialize heap - # - 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 - # . argv[1] == "test" - # . . push args - 68/push "test"/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - 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 - 3d/compare-EAX-and 1/imm32 - 75/jump-if-not-equal $run-main/disp8 - # . run-tests() - e8/call run-tests/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: - # - otherwise convert stdin - # convert(Stdin, Stdout) - # . . push args - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call convert/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . syscall(exit, 0) - bb/copy-to-EBX 0/imm32 -$main:end: - b8/copy-to-EAX 1/imm32/exit - cd/syscall 0x80/imm8 - -convert: # in : (address buffered-file), out : (address buffered-file) -> <void> - # pseudocode - # bool tests-found = false - # var line = new-stream(512, 1) - # var new-code-segment = new-stream(Segment-size, 1) - # write(new-code-segment, "\n==code\n") - # write(new-code-segment, "run-tests:\n") - # while true - # clear-stream(line) - # read-line-buffered(in, line) - # if (line->write == 0) break # end of file - # var word-slice = next-word(line) - # if is-label?(word-slice) - # if slice-starts-with?(word-slice, "test-") - # tests-found = true - # write(new-code-segment, " e8/call ") - # write-slice(new-code-segment, word-slice) - # write(new-code-segment, "/disp32\n") - # rewind-stream(line) - # write-stream-data(out, line) - # if tests-found - # write(new-code-segment, " c3/return\n") - # write-stream-data(out, new-code-segment) - # flush(out) - # - # . prolog - 55/push-EBP - 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - # . save registers - 50/push-EAX - 51/push-ECX - 52/push-EDX - 53/push-EBX - 57/push-EDI - # var line/ECX : (address stream byte) = stream(512) - 81 5/subop/subtract 3/mod/direct 4/rm32/ESP . . . . . 0x200/imm32 # subtract from ESP - 68/push 0x200/imm32/length - 68/push 0/imm32/read - 68/push 0/imm32/write - 89/copy 3/mod/direct 1/rm32/ECX . . . 4/r32/ESP . . # copy ESP to ECX - # var word-slice/EDX = {0, 0} - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX - # tests-found?/EBX = false - 31/xor 3/mod/direct 3/rm32/EBX . . . 3/r32/EBX . . # clear EBX - # new-code-segment/EDI = new-stream(Heap, Segment-size, 1) - # . EAX = new-stream(Heap, Segment-size, 1) - # . . push args - 68/push 1/imm32 - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size - 68/push Heap/imm32 - # . . call - e8/call new-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . EDI = EAX - 89/copy 3/mod/direct 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to EDI - # write(new-code-segment, "\n== code\n") - # . . push args - 68/push "\n== code\n"/imm32 - 57/push-EDI - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(new-code-segment, "run-tests:\n") - # . . push args - 68/push "run-tests:\n"/imm32 - 57/push-EDI - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:loop: - # clear-stream(line) - # . . 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 - # read-line-buffered(in, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) - # . . call - e8/call read-line-buffered/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:check0: - # if (line->write == 0) break - 81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX - 0f 84/jump-if-equal $convert:break/disp32 - # next-word(line, word-slice) - # . . push args - 52/push-EDX - 51/push-ECX - # . . call - e8/call next-word/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:check-for-label: - # if (!is-label?(word-slice)) continue - # . EAX = is-label?(word-slice) - # . . push args - 52/push-EDX - # . . call - e8/call is-label?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . if (EAX == 0) continue - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $convert:continue/disp8 -$convert:check-label-prefix: - # strip trailing ':' from word-slice - ff 1/subop/decrement 1/mod/*+disp8 2/rm32/EDX . . . . 4/disp8 . # decrement *(EDX+4) - # if !slice-starts-with?(word-slice, "test-") continue - # . . push args - 68/push "test-"/imm32 - 52/push-EDX - # . . call - e8/call slice-starts-with?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # . if (EAX == 0) break - 3d/compare-EAX-and 0/imm32 - 74/jump-if-equal $convert:continue/disp8 -$convert:call-test-function: - # tests-found? = true - bb/copy-to-EBX 1/imm32/true - # write(new-code-segment, " e8/call ") - # . . push args - 68/push " e8/call "/imm32 - 57/push-EDI - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-slice(new-code-segment, word-slice) - # . . push args - 52/push-EDX - 57/push-EDI - # . . call - e8/call write-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write(new-code-segment, "/disp32\n") - # . . push args - 68/push "/disp32\n"/imm32 - 57/push-EDI - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:continue: - # rewind-stream(line) - # . . push args - 51/push-ECX - # . . call - e8/call rewind-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # write-stream-data(out, line) - # . . push args - 51/push-ECX - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # loop - e9/jump $convert:loop/disp32 -$convert:break: - # if (!tests-found?) goto end - 81 7/subop/compare 3/mod/direct 3/rm32/EBX . . . . . 0/imm32 # compare EBX - 74/jump-if-equal $convert:end/disp8 - # write(new-code-segment, " c3/return\n") - # . . push args - 68/push " c3/return\n"/imm32 - 57/push-EDI - # . . call - e8/call write/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - # write-stream-data(out, new-code-segment) - # . . push args - 57/push-EDI - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call write-stream-data/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -$convert:end: - # flush(out) - # . . push args - ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) - # . . call - e8/call flush/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP - # . restore registers - 5f/pop-to-EDI - 5b/pop-to-EBX - 5a/pop-to-EDX - 59/pop-to-ECX - 58/pop-to-EAX - # . epilog - 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 5d/pop-to-EBP - c3/return - -# . . vim:nowrap:textwidth=0 |