diff options
Diffstat (limited to '066write-int-hex.subx')
-rw-r--r-- | 066write-int-hex.subx | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/066write-int-hex.subx b/066write-int-hex.subx new file mode 100644 index 00000000..6746891e --- /dev/null +++ b/066write-int-hex.subx @@ -0,0 +1,386 @@ +# Write out the (hex) textual representation of numbers. + +== 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 + +# convert the lowest nibble of eax to ascii and return it in the lowest byte of eax +to-hex-char: # in/eax: int -> out/eax: int + # no error checking; accepts argument in eax + # if (eax <= 9) return eax + '0' + 3d/compare-eax-with 0x9/imm32/9 + 7f/jump-if-> $to-hex-char:else/disp8 + 05/add-to-eax 0x30/imm32/0 + c3/return +$to-hex-char:else: + # otherwise return eax + 'a' - 10 + 05/add-to-eax 0x57/imm32/a-10 + c3/return + +append-byte-hex: # f: (addr stream byte), n: 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 + # AL = convert upper nibble to hex + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax + c1/shift 5/subop/logic-right 3/mod/direct 0/rm32/eax . . . . . 4/imm8 # shift eax right by 4 bits, while padding zeroes + 25/and-eax 0xf/imm32 + # . AL = to-hex-char(AL) + 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 + # AL = convert lower nibble to hex + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax + 25/and-eax 0xf/imm32 + # . AL = to-hex-char(AL) + 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 +$append-byte-hex:end: + # . restore registers + 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 + +test-append-byte-hex: + # - check that append-byte-hex adds 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 + # append-byte-hex(_test-stream, 0xa) # exercises digit, non-digit as well as leading zero + # . . push args + 68/push 0xa/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call append-byte-hex/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-stream-equal(_test-stream, "0a", msg) + # . . push args + 68/push "F - test-append-byte-hex"/imm32 + 68/push "0a"/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 the hex representation for the lowest byte of a number +write-byte-hex-buffered: # f: (addr buffered-file), n: 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 + # AL = convert upper nibble to hex + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax + c1/shift 5/subop/logic-right 3/mod/direct 0/rm32/eax . . . . . 4/imm8 # shift eax right by 4 bits, while padding zeroes + 25/and-eax 0xf/imm32 + # . AL = to-hex-char(AL) + e8/call to-hex-char/disp32 + # write-byte-buffered(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 write-byte-buffered/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # AL = convert lower nibble to hex + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax + 25/and-eax 0xf/imm32 + # . AL = to-hex-char(AL) + e8/call to-hex-char/disp32 + # write-byte-buffered(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 write-byte-buffered/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +$write-byte-hex-buffered:end: + # . restore registers + 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 + +test-write-byte-hex-buffered: + # - check that write-byte-hex-buffered 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 + # . clear-stream($_test-buffered-file->buffer) + # . . push args + 68/push $_test-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 + # write-byte-hex-buffered(_test-buffered-file, 0xa) # exercises digit, non-digit as well as leading zero + # . . push args + 68/push 0xa/imm32 + 68/push _test-buffered-file/imm32 + # . . call + e8/call write-byte-hex-buffered/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # flush(_test-buffered-file) + # . . push args + 68/push _test-buffered-file/imm32 + # . . call + e8/call flush/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp + # check-stream-equal(_test-stream, "0a", msg) + # . . push args + 68/push "F - test-write-byte-hex-buffered"/imm32 + 68/push "0a"/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: # f: (addr stream byte), 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 + # + # . 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 + # 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-< $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 + # . epilogue + 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: (addr buffered-file), n: int + # pseudocode: + # write-buffered(f, "0x") + # ecx = 28 + # while true + # if (ecx < 0) break + # eax = n >> ecx + # eax = eax & 0xf + # write-byte-buffered(f, AL) + # ecx -= 4 + # + # . 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 + # 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 + 7c/jump-if-< $print-int32-buffered: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 + # write-byte-buffered(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 write-byte-buffered/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-buffered:loop/disp8 +$print-int32-buffered:end: + # . restore registers + 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 + +test-print-int32-buffered: + # - check that print-int32-buffered 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 + # . clear-stream($_test-buffered-file->buffer) + # . . push args + 68/push $_test-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 + # print-int32-buffered(_test-buffered-file, 0x8899aa) + # . . push args + 68/push 0x8899aa/imm32 + 68/push _test-buffered-file/imm32 + # . . call + e8/call print-int32-buffered/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # flush(_test-buffered-file) + # . . push args + 68/push _test-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 line {{{ +#? # . write-stream(2/stderr, line) +#? # . . push args +#? 68/push _test-stream/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write-stream/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +#? # . write(2/stderr, "$\n") +#? # . . push args +#? 68/push "$\n"/imm32 +#? 68/push 2/imm32/stderr +#? # . . call +#? e8/call write/disp32 +#? # . . discard args +#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +#? # }}} + # check-stream-equal(_test-stream, "0x008899aa", msg) + # . . push args + 68/push "F - test-print-int32-buffered"/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 + +# . . vim:nowrap:textwidth=0 |