From 71e4f3812982dba2efb471283d310224e8db363e Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 3 Mar 2021 22:09:50 -0800 Subject: 7842 - new directory organization Baremetal is now the default build target and therefore has its sources at the top-level. Baremetal programs build using the phase-2 Mu toolchain that requires a Linux kernel. This phase-2 codebase which used to be at the top-level is now under the linux/ directory. Finally, the phase-2 toolchain, while self-hosting, has a way to bootstrap from a C implementation, which is now stored in linux/bootstrap. The bootstrap C implementation uses some literate programming tools that are now in linux/bootstrap/tools. So the whole thing has gotten inverted. Each directory should build one artifact and include the main sources (along with standard library). Tools used for building it are relegated to sub-directories, even though those tools are often useful in their own right, and have had lots of interesting programs written using them. A couple of things have gotten dropped in this process: - I had old ways to run on just a Linux kernel, or with a Soso kernel. No more. - I had some old tooling for running a single test at the cursor. I haven't used that lately. Maybe I'll bring it back one day. The reorg isn't done yet. Still to do: - redo documentation everywhere. All the README files, all other markdown, particularly vocabulary.md. - clean up how-to-run comments at the start of programs everywhere - rethink what to do with the html/ directory. Do we even want to keep supporting it? In spite of these shortcomings, all the scripts at the top-level, linux/ and linux/bootstrap are working. The names of the scripts also feel reasonable. This is a good milestone to take stock at. --- linux/assort.subx | 1062 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1062 insertions(+) create mode 100644 linux/assort.subx (limited to 'linux/assort.subx') diff --git a/linux/assort.subx b/linux/assort.subx new file mode 100644 index 00000000..c4a38410 --- /dev/null +++ b/linux/assort.subx @@ -0,0 +1,1062 @@ +# 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: +# $ ./bootstrap translate init.linux [01]*.subx apps/subx-params.subx apps/assort.subx -o apps/assort +# $ cat x +# == code +# abc +# == code +# def +# $ cat x |./bootstrap 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: # run tests if necessary, convert stdin if not + # . prologue + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + + # 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 + + # - 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-assort-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-assort-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-assort-main:end/disp8 +$subx-assort-main:interactive: + # - 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 + # subx-assort(Stdin, Stdout, Stderr, ed) + # . . push args + 50/push-eax/ed + 68/push Stderr/imm32 + 68/push Stdout/imm32 + 68/push Stdin/imm32 + # . . call + e8/call subx-assort/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 +$subx-assort-main:end: + e8/call syscall_exit/disp32 + +# data structure: +# table: (addr stream {(handle array byte), (handle stream byte)}) (16 bytes/row) +# inefficient; uses sequential search for looking up segments by name + +subx-assort: # in: (addr buffered-file), out: (addr buffered-file) + # pseudocode: + # var table: (addr stream {(handle array byte), (handle stream byte)} 10 rows) + # read-segments(in, table) + # write-segments(out, table) + # + # . prologue + 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: (stream {string, (handle stream byte)} 160) # 10 rows * 16 bytes/row + 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 + # 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 +$subx-assort: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 +$subx-assort: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 +$subx-assort:end: + # . reclaim locals + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xac/imm32 # add to esp + # . restore registers + 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-assort: + # . 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 (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 Newline/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 + # subx-assort(_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-assort/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-subx-assort/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-subx-assort/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-subx-assort/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-subx-assort/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-subx-assort/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-subx-assort/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-subx-assort/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-subx-assort/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 + # . epilogue + 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 5d/pop-to-ebp + c3/return + +read-segments: # in: (addr buffered-file), table: (addr stream {(handle array byte), (handle stream byte)}) + # pseudocode: + # var curr-segment: (addr stream byte) = 0 + # var line: (stream byte 512) + # while true + # clear-stream(line) + # read-line-buffered(in, line) + # if (line->write == 0) break # end of file + # var word-slice = next-word-or-string(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-or-string(line) + # var segment-slot: (addr handle stream byte) = get-or-insert-slice(table, segment-name, row-size=16) + # if *segment-slot != 0 + # curr-segment = lookup(*segment-slot) + # continue + # new-stream(Heap, Segment-size, 1, segment-slot) + # curr-segment = lookup(*segment-slot) + # 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 + # + # . 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/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: 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 +$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-= $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-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 +$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 != false) continue + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $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 + # . var start/esi: (addr byte) = word-slice->start + 8b/copy 0/mod/indirect 2/rm32/edx . . . 6/r32/esi . . # copy *ecx to esi + # . var c/eax: byte = *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 (c == '#') continue + 3d/compare-eax-and 0x23/imm32/hash + 0f 84/jump-if-= $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->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 +#? 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 == false) goto next check + 3d/compare-eax-and 0/imm32/false + 0f 84/jump-if-= $read-segments:regular-line/disp32 + # segment-name = next-word-or-string(line) + # . . 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 +#? # 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->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 +#? 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 +#? # }}} + # var segment-slot/edi: (addr handle stream byte) = get-or-insert-slice(table, segment-name, row-size=16, Heap) + # . eax = get-or-insert-slice(table, segment-name, row-size=16, Heap) + # . . push args + 68/push Heap/imm32 + 68/push 0x10/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 + # . edi = eax + 89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi +#? # print("slot: " segment-slot "\n") {{{ +#? # . write("slot: ") +#? # . . push args +#? 68/push "slot: "/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, segment-slot) +#? # . . push args +#? 57/push-edi +#? 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("\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 +#? # }}} + # if (*segment-slot != 0) update curr-segment and continue + 81 7/subop/compare 0/mod/indirect 7/rm32/edi . . . . . 0/imm32 # compare edi + 0f 84/jump-if-= $read-segments:create-segment/disp32 + # var curr-segment/ebx: (addr stream byte) = lookup(*segment-slot) + # . eax = lookup(*segment-slot) + # . . push args + ff 6/subop/push 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # push *(edi+4) + ff 6/subop/push 0/mod/indirect 7/rm32/edi . . . . . . # push *edi + # . . call + e8/call lookup/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # . ebx = eax + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + # continue + e9/jump $read-segments:loop/disp32 +$read-segments:create-segment: + # new-stream(Heap, Segment-size, 1, segment-slot) + # . . push args + 57/push-edi + 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 . . . . . 0x10/imm32 # add to esp + # var curr-segment/ebx: (addr stream byte) = lookup(*segment-slot) + # . eax = lookup(*segment-slot) + # . . push args + ff 6/subop/push 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # push *(edi+4) + ff 6/subop/push 0/mod/indirect 7/rm32/edi . . . . . . # push *edi + # . . call + e8/call lookup/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # . ebx = eax + 89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx + # 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 +#? # }}} +#? # print("addr: " curr-segment->write "\n") {{{ +#? # . write("addr: ") +#? # . . push args +#? 68/push "addr: "/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, curr-segment) +#? # . . push args +#? 53/push-ebx +#? 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("\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 +#? # }}} +#? # print("write: " curr-segment->write "\n") {{{ +#? # . write("write: ") +#? # . . push args +#? 68/push "write: "/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, curr-segment->write) +#? # . . push args +#? ff 6/subop/push 0/mod/indirect 3/rm32/ebx . . . . . . # push *ebx +#? 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("\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 +#? # }}} +#? # print("size: " curr-segment->size "\n") {{{ +#? # . write("size: ") +#? # . . push args +#? 68/push "size: "/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, curr-segment->size) +#? # . . push args +#? ff 6/subop/push 1/mod/*+disp8 3/rm32/ebx . . . . 8/disp8 . # push *(ebx+8) +#? 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("\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 +#? # }}} + # 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 + 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 + +write-segments: # out: (addr buffered-file), table: (addr stream {(handle array byte), (handle stream byte)}) + # pseudocode: + # var curr = table->data + # var max = &table->data[table->write] + # while curr < max + # var stream: (addr stream byte) = lookup(table[i].stream) + # write-stream-data(out, stream) + # curr += 16 + # flush(out) + # + # . prologue + 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 + # var write/edx: int = table->write + 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx + # var curr/esi: (addr byte) = table->data + 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0xc/imm32 # add to eax + # var max/edx: (addr byte) = 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-addr>= $write-segments:break/disp8 + # var stream/eax: (addr stream byte) = lookup(table[i].stream) + # . . push args + ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 0xc/disp8 . # push *(esi+12) + ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 8/disp8 . # push *(esi+8) + # . . call + e8/call lookup/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # 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 += 16 + 81 0/subop/add 3/mod/direct 6/rm32/esi . . . . . 0x10/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 + # . 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 -- cgit 1.4.1-2-gfad0