diff options
author | Kartik Agaram <vc@akkartik.com> | 2019-09-19 15:30:35 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2019-09-19 15:30:35 -0700 |
commit | 825d9ebbe4d0f14c59ec42cea47a947a51bb56c6 (patch) | |
tree | 0eb6685ffb11e00519775a2ac02ade126fb60b29 /084print-int-decimal.subx | |
parent | dc8790941e39efb25c40de0420fdd4bce03f2761 (diff) | |
download | mu-825d9ebbe4d0f14c59ec42cea47a947a51bb56c6.tar.gz |
5671
Diffstat (limited to '084print-int-decimal.subx')
-rw-r--r-- | 084print-int-decimal.subx | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/084print-int-decimal.subx b/084print-int-decimal.subx new file mode 100644 index 00000000..f7898fe9 --- /dev/null +++ b/084print-int-decimal.subx @@ -0,0 +1,307 @@ +# Helper to print an int32 in decimal. + +== 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 + +print-int32-decimal: # out : (address stream), n : int32 + # works by generating characters from lowest to highest and pushing them + # to the stack, before popping them one by one into the stream + # + # pseudocode: + # push sentinel + # eax = abs(n) + # while true + # sign-extend eax into edx + # eax, edx = eax/10, eax%10 + # edx += '0' + # push edx + # if (eax == 0) break + # if n < 0 + # push '-' + # w = out->write + # curr = &out->data[out->write] + # max = &out->data[out->length] + # while true + # pop into eax + # if (eax == sentinel) break + # if (curr >= max) abort + # *curr = AL + # ++curr + # ++w + # out->write = w + # (based on K&R itoa: https://en.wikibooks.org/wiki/C_Programming/stdlib.h/itoa) + # (this pseudocode contains registers because operations like division + # require specific registers in x86) + # + # . prolog + 55/push-ebp + 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # ten/ecx = 10 + b9/copy-to-ecx 0xa/imm32 + # push sentinel + 68/push 0/imm32/sentinel + # eax = abs(n) + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax + 3d/compare-eax-with 0/imm32 + 7d/jump-if-greater-or-equal $print-int32-decimal:read-loop/disp8 +$print-int32-decimal:negative: + f7 3/subop/negate 3/mod/direct 0/rm32/eax . . . . . . # negate eax +$print-int32-decimal:read-loop: + # eax, edx = eax / 10, eax % 10 + 99/sign-extend-eax-into-edx + f7 7/subop/idiv 3/mod/direct 1/rm32/ecx . . . . . . # divide edx:eax by ecx, storing quotient in eax and remainder in edx + # edx += '0' + 81 0/subop/add 3/mod/direct 2/rm32/edx . . . . . 0x30/imm32 # add to edx + # push edx + 52/push-edx + # if (eax == 0) break + 3d/compare-eax-and 0/imm32 + 7f/jump-if-greater $print-int32-decimal:read-loop/disp8 +$print-int32-decimal:read-break: + # if (n < 0) push('-') + 81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 0/imm32 # compare *(ebp+12) + 7d/jump-if-greater-or-equal $print-int32-decimal:write/disp8 +$print-int32-decimal:push-negative: + 68/push 0x2d/imm32/- +$print-int32-decimal:write: + # edi = out + 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi + # w/edx = out->write + 8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx + # curr/ecx = &out->data[out->write] + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 1/r32/ecx 0xc/disp8 . # copy ebx+edx+12 to ecx + # max/ebx = &out->data[out->length] + 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 3/r32/ebx 8/disp8 . # copy *(edi+8) to ebx + 8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 3/index/ebx . 3/r32/ebx 0xc/disp8 . # copy edi+ebx+12 to ebx +$print-int32-decimal:write-loop: + # pop into eax + 58/pop-to-eax + # if (eax == sentinel) break + 3d/compare-eax-and 0/imm32/sentinel + 74/jump-if-equal $print-int32-decimal:write-break/disp8 + # if (curr >= max) abort + 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx + 73/jump-if-greater-or-equal-unsigned $print-int32-decimal:abort/disp8 +$print-int32-decimal:write-char: + # *curr = AL + 88/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy AL to byte at *ecx + # ++curr + 41/increment-ecx + # ++w + 42/increment-edx + eb/jump $print-int32-decimal:write-loop/disp8 +$print-int32-decimal:write-break: + # out->write = w + 89/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy edx to *edi +$print-int32-decimal:end: + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilog + 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp + 5d/pop-to-ebp + c3/return + +$print-int32-decimal:abort: + # . _write(2/stderr, error) + # . . push args + 68/push "print-int32-decimal: out of space\n"/imm32 + 68/push 2/imm32/stderr + # . . call + e8/call _write/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # . syscall(exit, 1) + bb/copy-to-ebx 1/imm32 + b8/copy-to-eax 1/imm32/exit + cd/syscall 0x80/imm8 + # never gets here + +test-print-int32-decimal: + # - check that a single-digit number converts correctly + # 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-decimal(_test-stream, 9) + # . . push args + 68/push 9/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32-decimal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-stream-equal(_test-stream, "9", msg) + # . . push args + 68/push "F - test-print-int32-decimal"/imm32 + 68/push "9"/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 + +test-print-int32-decimal-zero: + # - check that 0 converts correctly + # 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-decimal(_test-stream, 0) + # . . push args + 68/push 0/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32-decimal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-stream-equal(_test-stream, "0", msg) + # . . push args + 68/push "F - test-print-int32-decimal-zero"/imm32 + 68/push "0"/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 + +test-print-int32-decimal-multiple-digits: + # - check that a multi-digit number converts correctly + # 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-decimal(_test-stream, 10) + # . . push args + 68/push 0xa/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32-decimal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-stream-equal(_test-stream, "10", msg) + # . . push args + 68/push "F - test-print-int32-decimal-multiple-digits"/imm32 + 68/push "10"/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 + +test-print-int32-decimal-negative: + # - check that a negative single-digit number converts correctly + # 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-decimal(_test-stream, -9) + # . . push args + 68/push -9/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32-decimal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp +#? # dump _test-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, _test-stream) +#? # . . 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, "-9", msg) + # . . push args + 68/push "F - test-print-int32-decimal-negative"/imm32 + 68/push "-9"/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 + +test-print-int32-decimal-negative-multiple-digits: + # - check that a multi-digit number converts correctly + # 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-decimal(_test-stream, -10) + # . . push args + 68/push -0xa/imm32 + 68/push _test-stream/imm32 + # . . call + e8/call print-int32-decimal/disp32 + # . . discard args + 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp + # check-stream-equal(_test-stream, "-10", msg) + # . . push args + 68/push "F - test-print-int32-decimal-negative-multiple-digits"/imm32 + 68/push "-10"/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 |