diff --git a/subx/057write.subx b/subx/057write.subx index 455146ac..203cbf76 100644 --- a/subx/057write.subx +++ b/subx/057write.subx @@ -151,8 +151,9 @@ _test-stream: # current read index 0/imm32 # length - 8/imm32 - # data - 00 00 00 00 00 00 00 00 # 8 bytes + 0x10/imm32 + # data (2 lines x 8 bytes/line) + 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 # . . vim:nowrap:textwidth=0 diff --git a/subx/066print-int.subx b/subx/066print-int.subx index 0715b414..1280f348 100644 --- a/subx/066print-int.subx +++ b/subx/066print-int.subx @@ -6,7 +6,7 @@ # . 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 a single test, while debugging -#? e8/call test-print-int32-buffered/disp32 +#? e8/call test-print-int32/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 #? b8/copy-to-EAX 1/imm32/exit @@ -171,8 +171,97 @@ test-print-byte-buffered: # . end c3/return +print-int32: # f : (address stream), n : int -> + # pseudocode: + # write(f, "0x") + # ECX = 28 + # while true + # if (ECX < 0) break + # EAX = n >> ECX + # EAX = EAX & 0xf + # append-byte(f, AL) + # ECX -= 4 + # + # . prolog + 55/push-EBP + 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + # . save registers + 50/push-EAX + 51/push-ECX + # ECX = 28 + b9/copy-to-ECX 0x1c/imm32 +$print-int32:print-hex-prefix: + # write(f, "0x") + # . . push args + 68/push "0x"/imm32 + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +$print-int32:loop: + # if (ECX < 0) break + 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX + 7c/jump-if-lesser $print-int32:end/disp8 + # EAX = n >> ECX + 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EAX + d3/>>ECX 5/subop/pad-zeroes 3/mod/direct 0/rm32/EAX . . . . . . # shift EAX right by ECX bits, padding zeroes + # EAX = to-hex-char(AL) + 25/and-EAX 0xf/imm32 + e8/call to-hex-char/disp32 + # append-byte(f, AL) + # . . push args + 50/push-EAX + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call append-byte/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # ECX -= 4 + 81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 4/imm32 # subtract from ECX + eb/jump $print-int32:loop/disp8 +$print-int32:end: + # . restore registers + 59/pop-to-ECX + 58/pop-to-EAX + # . epilog + 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 5d/pop-to-EBP + c3/return + +test-print-int32: + # - check that print-int32 prints the hex textual representation + # setup + # . clear-stream(_test-stream) + # . . push args + 68/push _test-stream/imm32 + # . . call + e8/call clear-stream/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + # print-int32(_test-stream, 0x8899aa) + # . . push args + 68/push 0x8899aa/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # check-stream-equal(_test-stream, "0x008899aa", msg) + # . . push args + 68/push "F - test-print-int32"/imm32 + 68/push "0x008899aa"/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call check-stream-equal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP + # . end + c3/return + print-int32-buffered: # f : (address buffered-file), n : int -> # pseudocode: + # write-buffered(f, "0x") # ECX = 28 # while true # if (ECX < 0) break @@ -189,6 +278,15 @@ print-int32-buffered: # f : (address buffered-file), n : int -> 51/push-ECX # ECX = 28 b9/copy-to-ECX 0x1c/imm32 +$print-int32-buffered:print-hex-prefix: + # write-buffered(f, "0x") + # . . push args + 68/push "0x"/imm32 + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call write-buffered/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP $print-int32-buffered:loop: # if (ECX < 0) break 81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0/imm32 # compare ECX @@ -271,10 +369,10 @@ test-print-int32-buffered: #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # }}} - # check-stream-equal(_test-stream, "008899aa", msg) + # check-stream-equal(_test-stream, "0x008899aa", msg) # . . push args 68/push "F - test-print-int32-buffered"/imm32 - 68/push "008899aa"/imm32 + 68/push "0x008899aa"/imm32 68/push _test-stream/imm32 # . . call e8/call check-stream-equal/disp32 diff --git a/subx/Readme.md b/subx/Readme.md index 517515d8..c91d10ab 100644 --- a/subx/Readme.md +++ b/subx/Readme.md @@ -629,13 +629,19 @@ allocated memory for it.)_ * `append-byte`: int -> stream - Will abort the entire program if there isn't enough room. * `append-byte-hex`: int -> stream + - textual representation in hex, no '0x' prefix + - Will abort the entire program if there isn't enough room. +* `print-int32`: int -> stream + - textual representation in hex, including '0x' prefix - Will abort the entire program if there isn't enough room. * `write-buffered`: string -> buffered-file * `write-slice-buffered`: slice -> buffered-file * `flush`: buffered-file * `write-byte-buffered`: int -> buffered-file * `print-byte-buffered`: int -> buffered-file - - textual representation in hex + - textual representation in hex, no '0x' prefix +* `print-int32-buffered`: int -> buffered-file + - textual representation in hex, including '0x' prefix #### reading from disk * `read`: file -> stream diff --git a/subx/apps/assort b/subx/apps/assort index 1cd0b6cf..227bf4e7 100755 Binary files a/subx/apps/assort and b/subx/apps/assort differ diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1 index 03d3d0c3..8414e3ce 100755 Binary files a/subx/apps/crenshaw2-1 and b/subx/apps/crenshaw2-1 differ diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b index 60521cb0..5dddec43 100755 Binary files a/subx/apps/crenshaw2-1b and b/subx/apps/crenshaw2-1b differ diff --git a/subx/apps/dquotes b/subx/apps/dquotes index 03e591f6..02102f04 100755 Binary files a/subx/apps/dquotes and b/subx/apps/dquotes differ diff --git a/subx/apps/dquotes.subx b/subx/apps/dquotes.subx index 6cd8d6ea..4810bcad 100644 --- a/subx/apps/dquotes.subx +++ b/subx/apps/dquotes.subx @@ -31,7 +31,7 @@ Entry: # run tests if necessary, convert stdin if not #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # . test() -#? e8/call test-convert-is-idempotent-by-default/disp32 +#? e8/call test-convert-processes-string-literals/disp32 #? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX #? eb/jump $main:end/disp8 @@ -256,6 +256,21 @@ $convert:next-line: # loop e9/jump $convert:line-loop/disp32 $convert:break: + # write-stream-data(out, new-data-segment) + # . . push args + 57/push-EDI + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + # . . call + e8/call write-stream-data/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # flush(out) + # . . push args + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0xc/disp8 . # push *(EBP+12) + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP $convert:end: # . reclaim locals 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/imm32 # add to ESP @@ -318,6 +333,13 @@ process-string-literal: # string-literal : (address slice), out : (address buff # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # emit-string-literal-data(out-segment, string-literal) + # . . push args + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x8/disp8 . # push *(EBP+8) + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 0x10/disp8 . # push *(EBP+16) + # . . call + e8/call emit-string-literal-data/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP # write(out-segment, "\n") # . . push args 68/push Newline/imm32 @@ -722,32 +744,39 @@ test-convert-processes-string-literals: # called. We just want to make sure instructions using string literals # switch to a string variable with the right value. # (Modifying string literals completely off the radar for now.) -#? # dump output {{{ -#? # . write(2/stderr, "result: ^") -#? # . . push args -#? 68/push "result: ^"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write-stream(2/stderr, _test-output-stream) -#? # . . push args -#? 68/push _test-output-stream/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write-stream/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # . write(2/stderr, "$\n") -#? # . . push args -#? 68/push "$\n"/imm32 -#? 68/push 2/imm32/stderr -#? # . . call -#? e8/call write/disp32 -#? # . . discard args -#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -#? # }}} + # 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 ", msg) # . . push args 68/push "F - test-convert-processes-string-literals/0"/imm32 @@ -769,16 +798,16 @@ test-convert-processes-string-literals: # . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg) # . . push args 68/push "F - test-convert-processes-string-literals/2"/imm32 - 68/push "2 3 "/imm32 + 68/push "2 _string2/y "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 # . . discard args 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP - # . check-next-stream-line-equal(_test-output-stream, "== data ", msg) + # . check-next-stream-line-equal(_test-output-stream, "== data", msg) # . . push args 68/push "F - test-convert-processes-string-literals/3"/imm32 - 68/push "== data "/imm32 + 68/push "== data"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 @@ -787,7 +816,7 @@ test-convert-processes-string-literals: # . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg) # . . push args 68/push "F - test-convert-processes-string-literals/4"/imm32 - 68/push "_string1: "/imm32 + 68/push "_string1:"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 @@ -796,7 +825,7 @@ test-convert-processes-string-literals: # . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg) # . . push args 68/push "F - test-convert-processes-string-literals/5"/imm32 - 68/push "1/imm32 61/a "/imm32 + 68/push "0x00000001/imm32 61/a "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 @@ -805,7 +834,7 @@ test-convert-processes-string-literals: # . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg) # . . push args 68/push "F - test-convert-processes-string-literals/6"/imm32 - 68/push "_string2: "/imm32 + 68/push "_string2:"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 @@ -814,7 +843,7 @@ test-convert-processes-string-literals: # . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg) # . . push args 68/push "F - test-convert-processes-string-literals/7"/imm32 - 68/push "2/imm32 62/b 63/c "/imm32 + 68/push "0x00000002/imm32 62/b 63/c "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 @@ -828,6 +857,9 @@ test-convert-processes-string-literals: # generate the data segment contents byte by byte for a given slice emit-string-literal-data: # out : (address stream), word : (address slice) # pseudocode + # var len = word->end - word->start - 2 # ignore the double-quotes + # append-int32-hex(out, len) + # write(out, "/imm32") # curr = word->start # ++curr # skip '"' # while true @@ -853,6 +885,30 @@ emit-string-literal-data: # out : (address stream), word : (address slice) 8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI # curr/EDX = word->start 8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX +$emit-string-literal-data:emit-length: + # TODO: handle metadata here + # print(out, "#{len}/imm32 ") + # . len/ECX = word->end - word->start - 2 + 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX + 29/subtract 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # subtract EDX from ECX + 81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 2/imm32 # subtract from ECX + # . print-int32(out, len) + # . . push args + 51/push-ECX + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call print-int32/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + # . write(out, "/imm32 ") + # . . push args + 68/push "/imm32 "/imm32 + ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8) + # . . call + e8/call write/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +$emit-string-literal-data:loop-init: # ++curr # skip initial '"' 42/increment-EDX # max/ESI = word->end @@ -1012,10 +1068,10 @@ test-emit-string-literal-data: #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # }}} - # . check-stream-equal(_test-output-stream, "61/a 62/b 63/c ", msg) + # . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg) # . . push args 68/push "F - test-emit-string-literal-data"/imm32 - 68/push "61/a 62/b 63/c "/imm32 + 68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-stream-equal/disp32 @@ -1076,10 +1132,10 @@ test-emit-string-literal-data-empty: #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # }}} - # . check-stream-equal(_test-output-stream, "", msg) + # . check-stream-equal(_test-output-stream, "0/imm32 ", msg) # . . push args 68/push "F - test-emit-string-literal-data-empty"/imm32 - 68/push ""/imm32 + 68/push "0x00000000/imm32 "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-stream-equal/disp32 @@ -1141,10 +1197,10 @@ test-emit-string-literal-data-no-metadata-for-non-alphanumerics: #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # }}} - # . check-stream-equal(_test-output-stream, "61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints + # . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints # . . push args 68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32 - 68/push "61/a 20 62/b "/imm32 + 68/push "0x00000003/imm32 61/a 20 62/b "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-stream-equal/disp32 @@ -1205,10 +1261,10 @@ test-emit-string-literal-data-handles-escape-sequences: #? # . . discard args #? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP #? # }}} - # . check-stream-equal(_test-output-stream, "61/a 22 62/b ", msg) + # . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg) # . . push args 68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32 - 68/push "61/a 22 62/b "/imm32 + 68/push "3/imm32 61/a 22 62/b "/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-stream-equal/disp32 diff --git a/subx/apps/factorial b/subx/apps/factorial index c18b8bcc..ab71d3b2 100755 Binary files a/subx/apps/factorial and b/subx/apps/factorial differ diff --git a/subx/apps/handle b/subx/apps/handle index 4fe1e044..4d4bea1f 100755 Binary files a/subx/apps/handle and b/subx/apps/handle differ diff --git a/subx/apps/hex b/subx/apps/hex index 59170942..f69e7bb3 100755 Binary files a/subx/apps/hex and b/subx/apps/hex differ diff --git a/subx/apps/pack b/subx/apps/pack index f2149b59..1c76d927 100755 Binary files a/subx/apps/pack and b/subx/apps/pack differ