From 4a4a392dc7c81b301ad6b760525c5549f2f6644c Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 20 Sep 2019 11:19:30 -0700 Subject: 5683 --- html/075print-int-decimal.subx.html | 347 ++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 html/075print-int-decimal.subx.html (limited to 'html/075print-int-decimal.subx.html') diff --git a/html/075print-int-decimal.subx.html b/html/075print-int-decimal.subx.html new file mode 100644 index 00000000..b91ef8cd --- /dev/null +++ b/html/075print-int-decimal.subx.html @@ -0,0 +1,347 @@ + + + + +Mu - 075print-int-decimal.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/075print-int-decimal.subx +
+  1 # Helper to print an int32 in decimal.
+  2 
+  3 == code
+  4 #   instruction                     effective address                                                   register    displacement    immediate
+  5 # . op          subop               mod             rm32          base        index         scale       r32
+  6 # . 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
+  7 
+  8 print-int32-decimal:  # out : (address stream), n : int32
+  9     # works by generating characters from lowest to highest and pushing them
+ 10     # to the stack, before popping them one by one into the stream
+ 11     #
+ 12     # pseudocode:
+ 13     #   push sentinel
+ 14     #   eax = abs(n)
+ 15     #   while true
+ 16     #     sign-extend eax into edx
+ 17     #     eax, edx = eax/10, eax%10
+ 18     #     edx += '0'
+ 19     #     push edx
+ 20     #     if (eax == 0) break
+ 21     #   if n < 0
+ 22     #     push '-'
+ 23     #   w = out->write
+ 24     #   curr = &out->data[out->write]
+ 25     #   max = &out->data[out->length]
+ 26     #   while true
+ 27     #     pop into eax
+ 28     #     if (eax == sentinel) break
+ 29     #     if (curr >= max) abort
+ 30     #     *curr = AL
+ 31     #     ++curr
+ 32     #     ++w
+ 33     #   out->write = w
+ 34     # (based on K&R itoa: https://en.wikibooks.org/wiki/C_Programming/stdlib.h/itoa)
+ 35     # (this pseudocode contains registers because operations like division
+ 36     # require specific registers in x86)
+ 37     #
+ 38     # . prolog
+ 39     55/push-ebp
+ 40     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 41     # . save registers
+ 42     50/push-eax
+ 43     51/push-ecx
+ 44     52/push-edx
+ 45     53/push-ebx
+ 46     57/push-edi
+ 47     # ten/ecx = 10
+ 48     b9/copy-to-ecx  0xa/imm32
+ 49     # push sentinel
+ 50     68/push  0/imm32/sentinel
+ 51     # eax = abs(n)
+ 52     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
+ 53     3d/compare-eax-with  0/imm32
+ 54     7d/jump-if-greater-or-equal  $print-int32-decimal:read-loop/disp8
+ 55 $print-int32-decimal:negative:
+ 56     f7          3/subop/negate      3/mod/direct    0/rm32/eax    .           .             .           .           .               .                 # negate eax
+ 57 $print-int32-decimal:read-loop:
+ 58     # eax, edx = eax / 10, eax % 10
+ 59     99/sign-extend-eax-into-edx
+ 60     f7          7/subop/idiv        3/mod/direct    1/rm32/ecx    .           .             .           .           .               .                 # divide edx:eax by ecx, storing quotient in eax and remainder in edx
+ 61     # edx += '0'
+ 62     81          0/subop/add         3/mod/direct    2/rm32/edx    .           .             .           .           .               0x30/imm32        # add to edx
+ 63     # push edx
+ 64     52/push-edx
+ 65     # if (eax == 0) break
+ 66     3d/compare-eax-and  0/imm32
+ 67     7f/jump-if-greater  $print-int32-decimal:read-loop/disp8
+ 68 $print-int32-decimal:read-break:
+ 69     # if (n < 0) push('-')
+ 70     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       0/imm32           # compare *(ebp+12)
+ 71     7d/jump-if-greater-or-equal  $print-int32-decimal:write/disp8
+ 72 $print-int32-decimal:push-negative:
+ 73     68/push  0x2d/imm32/-
+ 74 $print-int32-decimal:write:
+ 75     # edi = out
+ 76     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
+ 77     # w/edx = out->write
+ 78     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # copy *edi to edx
+ 79     # curr/ecx = &out->data[out->write]
+ 80     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
+ 81     # max/ebx = &out->data[out->length]
+ 82     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           3/r32/ebx   8/disp8         .                 # copy *(edi+8) to ebx
+ 83     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
+ 84 $print-int32-decimal:write-loop:
+ 85     # pop into eax
+ 86     58/pop-to-eax
+ 87     # if (eax == sentinel) break
+ 88     3d/compare-eax-and  0/imm32/sentinel
+ 89     74/jump-if-equal  $print-int32-decimal:write-break/disp8
+ 90     # if (curr >= max) abort
+ 91     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx with ebx
+ 92     73/jump-if-greater-or-equal-unsigned  $print-int32-decimal:abort/disp8
+ 93 $print-int32-decimal:write-char:
+ 94     # *curr = AL
+ 95     88/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy AL to byte at *ecx
+ 96     # ++curr
+ 97     41/increment-ecx
+ 98     # ++w
+ 99     42/increment-edx
+100     eb/jump  $print-int32-decimal:write-loop/disp8
+101 $print-int32-decimal:write-break:
+102     # out->write = w
+103     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # copy edx to *edi
+104 $print-int32-decimal:end:
+105     # . restore registers
+106     5f/pop-to-edi
+107     5b/pop-to-ebx
+108     5a/pop-to-edx
+109     59/pop-to-ecx
+110     58/pop-to-eax
+111     # . epilog
+112     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+113     5d/pop-to-ebp
+114     c3/return
+115 
+116 $print-int32-decimal:abort:
+117     # . _write(2/stderr, error)
+118     # . . push args
+119     68/push  "print-int32-decimal: out of space\n"/imm32
+120     68/push  2/imm32/stderr
+121     # . . call
+122     e8/call  _write/disp32
+123     # . . discard args
+124     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+125     # . syscall(exit, 1)
+126     bb/copy-to-ebx  1/imm32
+127     b8/copy-to-eax  1/imm32/exit
+128     cd/syscall  0x80/imm8
+129     # never gets here
+130 
+131 test-print-int32-decimal:
+132     # - check that a single-digit number converts correctly
+133     # setup
+134     # . clear-stream(_test-stream)
+135     # . . push args
+136     68/push  _test-stream/imm32
+137     # . . call
+138     e8/call  clear-stream/disp32
+139     # . . discard args
+140     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+141     # print-int32-decimal(_test-stream, 9)
+142     # . . push args
+143     68/push  9/imm32
+144     68/push  _test-stream/imm32
+145     # . . call
+146     e8/call  print-int32-decimal/disp32
+147     # . . discard args
+148     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+149     # check-stream-equal(_test-stream, "9", msg)
+150     # . . push args
+151     68/push  "F - test-print-int32-decimal"/imm32
+152     68/push  "9"/imm32
+153     68/push  _test-stream/imm32
+154     # . . call
+155     e8/call  check-stream-equal/disp32
+156     # . . discard args
+157     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+158     # . end
+159     c3/return
+160 
+161 test-print-int32-decimal-zero:
+162     # - check that 0 converts correctly
+163     # setup
+164     # . clear-stream(_test-stream)
+165     # . . push args
+166     68/push  _test-stream/imm32
+167     # . . call
+168     e8/call  clear-stream/disp32
+169     # . . discard args
+170     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+171     # print-int32-decimal(_test-stream, 0)
+172     # . . push args
+173     68/push  0/imm32
+174     68/push  _test-stream/imm32
+175     # . . call
+176     e8/call  print-int32-decimal/disp32
+177     # . . discard args
+178     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+179     # check-stream-equal(_test-stream, "0", msg)
+180     # . . push args
+181     68/push  "F - test-print-int32-decimal-zero"/imm32
+182     68/push  "0"/imm32
+183     68/push  _test-stream/imm32
+184     # . . call
+185     e8/call  check-stream-equal/disp32
+186     # . . discard args
+187     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+188     # . end
+189     c3/return
+190 
+191 test-print-int32-decimal-multiple-digits:
+192     # - check that a multi-digit number converts correctly
+193     # setup
+194     # . clear-stream(_test-stream)
+195     # . . push args
+196     68/push  _test-stream/imm32
+197     # . . call
+198     e8/call  clear-stream/disp32
+199     # . . discard args
+200     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+201     # print-int32-decimal(_test-stream, 10)
+202     # . . push args
+203     68/push  0xa/imm32
+204     68/push  _test-stream/imm32
+205     # . . call
+206     e8/call  print-int32-decimal/disp32
+207     # . . discard args
+208     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+209     # check-stream-equal(_test-stream, "10", msg)
+210     # . . push args
+211     68/push  "F - test-print-int32-decimal-multiple-digits"/imm32
+212     68/push  "10"/imm32
+213     68/push  _test-stream/imm32
+214     # . . call
+215     e8/call  check-stream-equal/disp32
+216     # . . discard args
+217     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+218     # . end
+219     c3/return
+220 
+221 test-print-int32-decimal-negative:
+222     # - check that a negative single-digit number converts correctly
+223     # setup
+224     # . clear-stream(_test-stream)
+225     # . . push args
+226     68/push  _test-stream/imm32
+227     # . . call
+228     e8/call  clear-stream/disp32
+229     # . . discard args
+230     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+231     # print-int32-decimal(_test-stream, -9)
+232     # . . push args
+233     68/push  -9/imm32
+234     68/push  _test-stream/imm32
+235     # . . call
+236     e8/call  print-int32-decimal/disp32
+237     # . . discard args
+238     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+239 +-- 26 lines: #?     # dump _test-stream -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+265     # check-stream-equal(_test-stream, "-9", msg)
+266     # . . push args
+267     68/push  "F - test-print-int32-decimal-negative"/imm32
+268     68/push  "-9"/imm32
+269     68/push  _test-stream/imm32
+270     # . . call
+271     e8/call  check-stream-equal/disp32
+272     # . . discard args
+273     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+274     # . end
+275     c3/return
+276 
+277 test-print-int32-decimal-negative-multiple-digits:
+278     # - check that a multi-digit number converts correctly
+279     # setup
+280     # . clear-stream(_test-stream)
+281     # . . push args
+282     68/push  _test-stream/imm32
+283     # . . call
+284     e8/call  clear-stream/disp32
+285     # . . discard args
+286     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+287     # print-int32-decimal(_test-stream, -10)
+288     # . . push args
+289     68/push  -0xa/imm32
+290     68/push  _test-stream/imm32
+291     # . . call
+292     e8/call  print-int32-decimal/disp32
+293     # . . discard args
+294     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+295     # check-stream-equal(_test-stream, "-10", msg)
+296     # . . push args
+297     68/push  "F - test-print-int32-decimal-negative-multiple-digits"/imm32
+298     68/push  "-10"/imm32
+299     68/push  _test-stream/imm32
+300     # . . call
+301     e8/call  check-stream-equal/disp32
+302     # . . discard args
+303     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+304     # . end
+305     c3/return
+306 
+307 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0