diff options
Diffstat (limited to 'apps/survey_baremetal.subx')
-rw-r--r-- | apps/survey_baremetal.subx | 2720 |
1 files changed, 0 insertions, 2720 deletions
diff --git a/apps/survey_baremetal.subx b/apps/survey_baremetal.subx deleted file mode 100644 index c42cd900..00000000 --- a/apps/survey_baremetal.subx +++ /dev/null @@ -1,2720 +0,0 @@ -# Assign addresses (co-ordinates) to instructions (landmarks) in a program -# (landscape). -# Use the addresses assigned to replace labels. -# -# To build: -# $ ./bootstrap translate init.linux [01]*.subx apps/subx-params.subx apps/survey_baremetal.subx -o apps/survey_baremetal -# -# The expected input is a stream of bytes and some interspersed labels. -# Comments and '==' segment headers are allowed, but ignored. The emitted code -# will all lie in a single header, and start at address 0x9400. -# $ cat x -# == code -# l1: -# aa bb l1/imm8 -# cc dd l2/disp32 -# l2: -# ee foo/imm32 -# == data -# 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 |./bootstrap run apps/survey_baremetal -# aa bb nn # some computed address -# cc dd nn nn nn nn # some computed displacement -# ee nn nn nn nn # address right after this instruction -# # data segment interleaved with code -# 00 - -== 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 - # . prologue - 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp - - # 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(Trace-size) - # . . push args - ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Trace-size/disp32 # push *Heap-size - # . . call - e8/call initialize-trace-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - - # - if argc > 1 and argv[1] == "test", then return run_tests() - # if (argc <= 1) goto interactive - 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp - 7e/jump-if-<= $subx-survey-main:interactive/disp8 - # if (!kernel-string-equal?(argv[1], "test")) goto interactive - # . eax = kernel-string-equal?(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 - # . if (eax == false) goto interactive - 3d/compare-eax-and 0/imm32/false - 74/jump-if-= $subx-survey-main:interactive/disp8 - # run-tests() - e8/call run-tests/disp32 - # syscall(exit, *Num-test-failures) - 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx - eb/jump $subx-survey-main:end/disp8 -$subx-survey-main:interactive: - # - otherwise convert stdin - # subx-survey(Stdin, Stdout) - # . . push args - 68/push Stdout/imm32 - 68/push Stdin/imm32 - # . . call - e8/call subx-survey/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 -$subx-survey-main:end: - e8/call syscall_exit/disp32 - -subx-survey: # infile: (addr buffered-file), out: (addr buffered-file) - # pseudocode - # var in: (stream byte Input-size) - # slurp(infile, in) - # var labels: (stream {label-name, address} Max-labels) - # compute-offsets(in, labels) - # rewind-stream(in) - # emit-output(in, out, labels) - # - # . prologue - 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 labels/edx: (stream {label-name, address} Max-labels) - # (we get more rows than Max-labels advertises because row size is smaller than in survey_elf) - # . data - 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Max-labels/disp32 # subtract *Max-labels from esp - # . size - 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 byte Input-size) - # . data - 2b/subtract 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Input-size/disp32 # subtract *Input-size from esp - # . size - 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 - # 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 - # compute-offsets(in, labels) - # . . push args - 52/push-edx - 56/push-esi - # . . call - e8/call compute-offsets/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 - # emit-output(in, out, labels) - # . . push args - 52/push-edx - 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 . . . . . 0xc/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 -$subx-survey:end: - # . reclaim locals - 03/add 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Max-labels/disp32 # add *Max-labels to esp - 03/add 0/mod/indirect 5/rm32/.disp32 . . 4/r32/esp Input-size/disp32 # add *Input-size to esp - # . restore registers - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-subx-survey-computes-addresses: - # input: - # == code - # Entry: - # ab x/imm32 - # == data - # x: - # 01 - # - # trace contains (in any order): - # label x is at address 0x9405 - # - # . prologue - 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->buffer) - # . . push args - 68/push $_test-input-buffered-file->buffer/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . 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->buffer) - # . . push args - 68/push $_test-output-buffered-file->buffer/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # initialize input - # . 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, "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\n") - # . . push args - 68/push "== data\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 - # subx-survey(_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 subx-survey/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 0x00009405.", msg) - # . . push args - 68/push "F - test-subx-survey-computes-addresses/0"/imm32 - 68/push "label 'x' is at address 0x00009405."/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 - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -compute-offsets: # in: (addr stream byte), labels: (addr stream {(handle array byte), address}) - # pseudocode: - # var current-address = 0x9400 - # var line: (stream byte 512) - # 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, "==") # no need for segment header - # break - # else if is-label?(word-slice) - # strip trailing ':' from word-slice - # trace("label '" word-slice "' is at address " current-address ".") - # # labels occupy no space, so no need to increment offsets - # else - # width = compute-width-of-slice(word-slice) - # current-address += width - # - # . prologue - 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 current-address/esi: int = 0x9400 - be/copy-to-esi 0x9400/imm32 - # var line/ecx: (stream byte 512) - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp - 68/push 0x200/imm32/size - 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: (addr slice) - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx -$compute-offsets: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 - # 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-= $compute-offsets:end/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: - # next-word(line, word-slice) - 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 -$compute-offsets:case-empty: - # if slice-empty?(word-slice) break - # . eax = slice-empty?(word-slice) - 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 != false) break - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $compute-offsets:line-loop/disp32 -$compute-offsets:case-comment: - # if slice-starts-with?(word-slice, "#") break - 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 != false) break - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $compute-offsets:line-loop/disp32 -$compute-offsets:case-segment-header: - # if slice-equal?(word-slice, "==") break - # . eax = slice-equal?(word-slice, "==") - 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 != false) break - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $compute-offsets:line-loop/disp32 -$compute-offsets:case-label: - # if (!is-label?(word-slice)) goto next case - # . 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 == false) goto next case - 3d/compare-eax-and 0/imm32/false - 0f 84/jump-if-= $compute-offsets:case-default/disp32 - # strip trailing ':' from word-slice - ff 1/subop/decrement 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # decrement *(edx+4) - # var tmp/eax: (addr int) = get-or-insert-slice(labels, word-slice, row-size=12) - # . . push args - 68/push Heap/imm32 - 68/push 0xc/imm32/row-size - 52/push-edx - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12) - # . . call - e8/call get-or-insert-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # *tmp = current-address - 89/copy 0/mod/indirect 0/rm32/eax . . . 6/r32/esi . . # copy esi to *eax - # trace-slsns("label '" word-slice "' is at address " current-address ".") - # . . push args - 68/push "."/imm32 - 56/push-esi - 68/push "' is at address "/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 - # current-address += width - 01/add 3/mod/direct 6/rm32/esi . . . 0/r32/eax . . # add eax to *esi -#? # 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->buffer) -#? # . . push args -#? 68/push $Stderr->buffer/imm32 -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp -#? # . write-int32-hex-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 write-int32-hex-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 Newline/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: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 - # . epilogue - 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 - e8/call syscall_exit/disp32 - # never gets here - -test-compute-offsets: - # input: - # == code - # ab x/imm32 # skip comment - # == data - # 00 - # x: - # 34 - # - # trace contains (in any order): - # label 'x' is at address 0x9406. - # - # . prologue - 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 labels/edx: (stream byte 2*12) - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # subtract from esp - 68/push 0x18/imm32/size - 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\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, "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\n") - # . . push args - 68/push "== data\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, labels) - # . . push args - 52/push-edx - 68/push _test-input-stream/imm32 - # . . call - e8/call compute-offsets/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 -#? # }}} - # . check-trace-contains("label 'x' is at address 0x00009406.", msg) - # . . push args - 68/push "F - test-compute-offsets"/imm32 - 68/push "label 'x' is at address 0x00009406."/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, 0xc, msg) - # . . push args - 68/push "F - test-compute-offsets-maintains-labels-write-index"/imm32 - 68/push 0xc/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 - # . reclaim locals - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x24/imm32 # add to esp - # . epilogue - 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 emit-output -== data - -emit-output:datum: # slice - 0/imm32/start - 0/imm32/end - -== code - -emit-output: # in: (addr stream byte), out: (addr buffered-file), labels: (addr stream {(handle array byte), address}) - # pseudocode: - # var address-of-next-instruction = 0x9400 - # var line: (stream byte 512) - # line-loop: - # while true - # clear-stream(line) - # read-line(in, line) - # if (line->write == 0) break # end of file - # address-of-next-instruction += num-bytes(line) - # var is-far-jump-or-call? = is-far-jump-or-call?(line) - # rewind-stream(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 - # var datum: (addr slice) = next-token-from-slice(word-slice->start, word-slice->end, "/") - # var address: (addr int) = get-slice(labels, datum) - # if has-metadata?(word-slice, "imm8") - # abort - # else if has-metadata?(word-slice, "imm32") - # emit(out, *address, 4) - # else if has-metadata?(word-slice, "disp8") - # value = *address - address-of-next-instruction - # emit(out, value, 1) - # else if has-metadata?(word-slice, "disp32") - # if is-far-jump-or-call? - # value = *address - address-of-next-instruction - # else - # value = *address - # emit(out, value, 4) - # else - # abort - # write-buffered(out, "\n") - # - # registers: - # line: ecx - # word-slice: edx - # address-of-next-instruction: ebx - # is-far-jump-or-call?: edi - # address: esi (inner loop only) - # temporaries: eax, esi (outer loop) - # - # . prologue - 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: (stream byte 512) - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp - 68/push 0x200/imm32/size - 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: slice - 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 address-of-next-instruction/ebx = 0x9400 - bb/copy-to-ebx 0x9400/imm32 -$emit-output: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-output: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-= $emit-output:end/disp32 - # address-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 - # var is-far-jump-or-call?/edi: boolean = is-far-jump-or-call?(line) - # . . push args - 51/push-ecx - # . . call - e8/call is-far-jump-or-call?/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/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-output: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-output: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/false - 0f 85/jump-if-!= $emit-output:next-line/disp32 -$emit-output: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-= $emit-output:next-line/disp32 -$emit-output: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 != false) break - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $emit-output:line-loop/disp32 -$emit-output: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 != false) break - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $emit-output:line-loop/disp32 -$emit-output:2-character: - # if (size(word-slice) != 2) goto next check - # . eax = size(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-!= $emit-output: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 Space/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-output:word-loop/disp32 -$emit-output:check-metadata: - # - if we get here, 'word-slice' must be a label to be looked up - # datum = next-token-from-slice(word-slice->start, word-slice->end, "/") - # . . push args - 68/push emit-output:datum/imm32 - 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 datum {{{ -#? # . 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, datum) -#? # . . push args -#? 68/push emit-output:datum/imm32 -#? 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 -#? # }}} - # address/esi: (addr int) = get-slice(labels, datum, row-size=12, "label table") - # . eax = get-slice(labels, datum, row-size=24, "label table") - # . . push args - 68/push "label table"/imm32 - 68/push 0xc/imm32/row-size - 68/push emit-output:datum/imm32 - ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) - # . . call - e8/call get-slice/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # . esi = eax - 89/copy 3/mod/direct 6/rm32/esi . . . 0/r32/eax . . # copy eax to esi -$emit-output:check-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 != false) abort - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $emit-output:imm8-abort/disp32 -$emit-output:check-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 == false) goto next check - 3d/compare-eax-and 0/imm32/false - 74/jump-if-= $emit-output:check-disp8/disp8 -#? # dump *address {{{ -#? # . write(2/stderr, "*address: ") -#? # . . push args -#? 68/push "*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 -#? # . write-int32-hex-buffered(Stderr, *address) -#? # . . push args -#? ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi -#? 68/push Stderr/imm32 -#? # . . call -#? e8/call write-int32-hex-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:emit-imm32: - # emit-hex(out, *address, 4) - # . . push args - 68/push 4/imm32 - ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi - 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-output:word-loop/disp32 -$emit-output:check-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 == false) goto next check - 3d/compare-eax-and 0/imm32/false - 74/jump-if-= $emit-output:check-disp32/disp8 -$emit-output:emit-disp8: - # emit-hex(out, *address - address-of-next-instruction, 1) - # . . push args - 68/push 1/imm32 - 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi 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-output:word-loop/disp32 -$emit-output:check-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 == false) abort - 3d/compare-eax-and 0/imm32/false - 0f 84/jump-if-= $emit-output:abort/disp32 -$emit-output:emit-disp32: - # var value/eax = *address - 8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax - # if (is-far-jump-or-call?) value -= address-of-next-instruction - 81 7/subop/compare 3/mod/direct 7/rm32/edi . . . . . 0/imm32/false # compare edi - 74/jump-if-= $emit-output:really-emit-disp32/disp8 - 29/subtract 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # subtract ebx from eax -$emit-output:really-emit-disp32: - # emit-hex(out, value, 4) - # . . push args - 68/push 4/imm32 - 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-output:word-loop/disp32 -$emit-output: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-output:line-loop/disp32 -$emit-output: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 - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$emit-output:global-variable-abort: - # . _write(2/stderr, error) - # . . push args - 68/push "emit-output: 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 - e8/call syscall_exit/disp32 - # never gets here - -$emit-output:imm8-abort: - # . _write(2/stderr, error) - # . . push args - 68/push "emit-output: 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 - e8/call syscall_exit/disp32 - # never gets here - -$emit-output:abort: - # print(stderr, "missing metadata in " word-slice) - # . _write(2/stderr, "missing metadata in word ") - # . . push args - 68/push "emit-output: 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 - e8/call syscall_exit/disp32 - # never gets here - -test-emit-output-non-far-control-flow: - # labels turn into absolute addresses if opcodes are not far jumps or calls - # - # input: - # in: - # == code - # ab cd ef gh - # ij x/disp32 - # == data - # 00 - # 34 - # labels: - # - 'x': 0x11223344 - # - # output: - # ab cd ef gh - # ij 44 33 22 11 - # 00 - # 34 - # - # . prologue - 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->buffer) - # . . push args - 68/push $_test-output-buffered-file->buffer/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . var labels/edx: (stream byte 8*24) - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp - 68/push 0xc0/imm32/size - 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 - # . var h/ebx: (handle array byte) - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # initialize input - # . 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, "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\n") - # . . push args - 68/push "== data\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, "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-add2(labels, "x", 0x11223344) - 68/push 0x11223344/imm32/label-address - # . . push handle for "x" - 53/push-ebx - 68/push "x"/imm32 - 68/push Heap/imm32 - e8/call copy-array/disp32 - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4) - ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx - # . . push labels - 52/push-edx - # . . call - e8/call stream-add2/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # component under test - # . emit-output(_test-input-stream, _test-output-buffered-file, labels) - # . . push args - 52/push-edx - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call emit-output/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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-output-non-far-control-flow/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 44 33 22 11 ", msg) - # . . push args - 68/push "F - test-emit-output-non-far-control-flow/1"/imm32 - 68/push "ij 44 33 22 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, "00 ", msg) - # . . push args - 68/push "F - test-emit-output-non-far-control-flow/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-output-non-far-control-flow/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 - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-emit-output-code-label: - # labels turn into PC-relative addresses if opcodes are far jumps or calls - # - # input: - # in: - # == code - # ab cd - # ef gh - # e8 l1/disp32 - # labels: - # - 'l1': 0x9410 - # - # output: - # ab cd - # ef gh - # e8 07 00 00 00 # 0x9410 - 0x9409 = 7 - # - # . prologue - 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->buffer) - # . . push args - 68/push $_test-output-buffered-file->buffer/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . var labels/edx: (stream byte 8*24) - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp - 68/push 0xc0/imm32/size - 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 - # . var h/ebx: (handle array byte) - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # initialize input - # . 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, "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, "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, "e8 l1/disp32\n") - # . . push args - 68/push "e8 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-add2(labels, "l1", 0x9410) - 68/push 0x9410/imm32/label-address - # . . push handle for "l1" - 53/push-ebx - 68/push "l1"/imm32 - 68/push Heap/imm32 - e8/call copy-array/disp32 - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4) - ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx - # . . push labels - 52/push-edx - # . . call - e8/call stream-add2/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # component under test - # . emit-output(_test-input-stream, _test-output-buffered-file, labels) - # . . push args - 52/push-edx - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call emit-output/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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-output-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-output-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, "e8 07 00 00 00 ", msg) - # . . push args - 68/push "F - test-emit-output-code-label/2"/imm32 - 68/push "e8 07 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 - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-emit-output-code-label-absolute: - # labels can also convert to absolute addresses - # - # input: - # in: - # == code - # ab cd - # ef gh - # ij l1/imm32 - # labels: - # - 'l1': 0x1056 - # - # output: - # ab cd - # ef gh - # ij 56 10 00 00 - # - # . prologue - 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->buffer) - # . . push args - 68/push $_test-output-buffered-file->buffer/imm32 - # . . call - e8/call clear-stream/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp - # . var labels/edx: (stream byte 8*24) - 81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xc0/imm32 # subtract from esp - 68/push 0xc0/imm32/size - 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 - # . var h/ebx: (handle array byte) - 68/push 0/imm32 - 68/push 0/imm32 - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # initialize input - # . write(_test-input-stream, "== code 0x1000\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, "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, "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-add2(labels, "l1", 0x1056) - 68/push 0x1056/imm32/label-address - # . . push handle for "l1" - 53/push-ebx - 68/push "l1"/imm32 - 68/push Heap/imm32 - e8/call copy-array/disp32 - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp - ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 4/disp8 . # push *(ebx+4) - ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx - # . . push labels - 52/push-edx - # . . call - e8/call stream-add2/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp - # component under test - # . emit-output(_test-input-stream, _test-output-buffered-file, labels) - # . . push args - 52/push-edx - 68/push _test-output-buffered-file/imm32 - 68/push _test-input-stream/imm32 - # . . call - e8/call emit-output/disp32 - # . . discard args - 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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-output-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-output-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-output-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 - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -# reads line to make some checks -# don't assume the read state of line after calling this function -is-far-jump-or-call?: # line: (addr stream byte) -> result/edi: boolean - # . prologue - 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 - # ecx = line - 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx - # var word-slice/edx: slice - 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-slice/ebx: slice - 68/push 0/imm32/end - 68/push 0/imm32/start - 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx - # result = false - bf/copy-to-edi 0/imm32/false -$is-far-jump-or-call?:check-first-word: - # 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 - # if (slice-empty?(word-slice)) return false - # . 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) return - 3d/compare-eax-and 0/imm32/false - 0f 85/jump-if-!= $is-far-jump-or-call?:end/disp32 - # datum = next-token-from-slice(word-slice->start, word-slice->end, "/") - # . . push args - 53/push-ebx - 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 - # if (datum-slice == "e8") return true - # . eax = slice-equal?(datum-slice, "e8") - # . . push args - 68/push "e8"/imm32 - 53/push-ebx - # . . 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 != false) return true - 3d/compare-eax-and 0/imm32/false - 75/jump-if-!= $is-far-jump-or-call?:return-true/disp8 - # if (datum-slice == "e9") return true - # . eax = slice-equal?(datum-slice, "e9") - # . . push args - 68/push "e9"/imm32 - 53/push-ebx - # . . 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 != false) return true - 3d/compare-eax-and 0/imm32/false - 75/jump-if-!= $is-far-jump-or-call?:return-true/disp8 - # if (datum-slice != "0f") return false - # . eax = slice-equal?(datum-slice, "0f") - # . . push args - 68/push "0f"/imm32 - 53/push-ebx - # . . 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 == false) return - 3d/compare-eax-and 0/imm32/false - 74/jump-if-= $is-far-jump-or-call?:end/disp8 -$is-far-jump-or-call?:check-second-word: - # 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 - # if (slice-empty?(word-slice)) return false - # . 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) return - 3d/compare-eax-and 0/imm32/false - 75/jump-if-!= $is-far-jump-or-call?:end/disp8 - # if datum of word-slice does not start with "8", return false - # . start/eax = word-slice->start - 8b/copy 0/mod/indirect 2/rm32/edx . . . 0/r32/eax . . # copy *edx to eax - # . c/eax = *start - 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL - 81 4/subop/and 3/mod/direct 0/rm32/eax . . . . . 0xff/imm32 # bitwise and of eax - # . if (eax != '8') return - 3d/compare-eax-and 0x38/imm32/8 - 75/jump-if-!= $is-far-jump-or-call?:end/disp8 - # otherwise return true -$is-far-jump-or-call?:return-true: - bf/copy-to-edi 1/imm32/true -$is-far-jump-or-call?:end: - # . reclaim 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 - # . epilogue - 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-add2: # in: (addr stream byte), key: handle, val: int - # . prologue - 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->size] - # . edx = in->size - 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-addr>= $stream-add2:abort/disp8 - # *curr = key->alloc-id - 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-addr>= $stream-add2:abort/disp8 - # *curr = key->payload - 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-addr>= $stream-add2:abort/disp8 - # *curr = val - 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 - # in->write += 0xc - 81 0/subop/add 0/mod/indirect 6/rm32/esi . . . . . 0xc/imm32 # add to *esi -$stream-add2:end: - # . restore registers - 5e/pop-to-esi - 5a/pop-to-edx - 59/pop-to-ecx - 58/pop-to-eax - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -$stream-add2:abort: - # . _write(2/stderr, error) - # . . push args - 68/push "overflow in stream-add2\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 - e8/call syscall_exit/disp32 - # 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: (addr array byte) -# l: (addr slice) -# one gotcha: 's5' must not be empty - -trace-slsns: # s1: (addr array byte), l2: (addr slice), s3: (addr array byte), n4: int, s5: (addr array byte) - # . prologue - 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-int32-hex(*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 write-int32-hex/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: - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -test-trace-slsns: - # . prologue - 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: 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 - # . epilogue - 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp - 5d/pop-to-ebp - c3/return - -num-bytes: # line: (addr stream byte) -> 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 - # - # . prologue - 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: slice - 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->buffer) -#? # . . push args -#? 68/push $Stderr->buffer/imm32 -#? # . . call -#? e8/call clear-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp -#? # . write-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 != false) break - 3d/compare-eax-and 0/imm32/false - # . restore result now that ZF is set - 58/pop-to-eax - 75/jump-if-!= $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-= $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-= $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 != false) break - 3d/compare-eax-and 0/imm32/false - # . restore result now that ZF is set - 58/pop-to-eax - 75/jump-if-!= $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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 - # . prologue - 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 - # . epilogue - 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 |