https://github.com/akkartik/mu/blob/main/linux/117write-int-hex.subx

      1 # Write out the (hex) textual representation of numbers.
      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 # convert the lowest nibble of eax to ascii and return it in the lowest byte of eax
      9 to-hex-char:  # in/eax: int -> out/eax: int
     10     # no error checking; accepts argument in eax
     11     # if (eax <= 9) return eax + '0'
     12     3d/compare-eax-with  0x9/imm32/9
     13     7f/jump-if->  $to-hex-char:else/disp8
     14     05/add-to-eax  0x30/imm32/0
     15     c3/return
     16 $to-hex-char:else:
     17     # otherwise return eax + 'a' - 10
     18     05/add-to-eax  0x57/imm32/a-10
     19     c3/return
     20
     21 append-byte-hex:  # f: (addr stream byte), n: int
     22     # . prologue
     23     55/push-ebp
     24     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     25     # . save registers
     26     50/push-eax
     27     # AL = convert upper nibble to hex
     28     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
     29     c1/shift    5/subop/logic-right 3/mod/direct    0/rm32/eax    .           .             .           .           .               4/imm8            # shift eax right by 4 bits, while padding zeroes
     30     25/and-eax  0xf/imm32
     31     # . AL = to-hex-char(AL)
     32     e8/call  to-hex-char/disp32
     33     # append-byte(f, AL)
     34     # . . push args
     35     50/push-eax
     36     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
     37     # . . call
     38     e8/call  append-byte/disp32
     39     # . . discard args
     40     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     41     # AL = convert lower nibble to hex
     42     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
     43     25/and-eax  0xf/imm32
     44     # . AL = to-hex-char(AL)
     45     e8/call  to-hex-char/disp32
     46     # append-byte(f, AL)
     47     # . . push args
     48     50/push-eax
     49     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
     50     # . . call
     51     e8/call  append-byte/disp32
     52     # . . discard args
     53     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     54 $append-byte-hex:end:
     55     # . restore registers
     56     58/pop-to-eax
     57     # . epilogue
     58     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     59     5d/pop-to-ebp
     60     c3/return
     61
     62 test-append-byte-hex:
     63     # - check that append-byte-hex adds the hex textual representation
     64     # setup
     65     # . clear-stream(_test-stream)
     66     # . . push args
     67     68/push  _test-stream/imm32
     68     # . . call
     69     e8/call  clear-stream/disp32
     70     # . . discard args
     71     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     72     # append-byte-hex(_test-stream, 0xa)  # exercises digit, non-digit as well as leading zero
     73     # . . push args
     74     68/push  0xa/imm32
     75     68/push  _test-stream/imm32
     76     # . . call
     77     e8/call  append-byte-hex/disp32
     78     # . . discard args
     79     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     80     # check-stream-equal(_test-stream, "0a", msg)
     81     # . . push args
     82     68/push  "F - test-append-byte-hex"/imm32
     83     68/push  "0a"/imm32
     84     68/push  _test-stream/imm32
     85     # . . call
     86     e8/call  check-stream-equal/disp32
     87     # . . discard args
     88     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     89     # . end
     90     c3/return
     91
     92 # print the hex representation for the lowest byte of a number
     93 write-byte-hex-buffered:  # f: (addr buffered-file), n: int
     94     # . prologue
     95     55/push-ebp
     96     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     97     # . save registers
     98     50/push-eax
     99     # AL = convert upper nibble to hex
    100     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
    101     c1/shift    5/subop/logic-right 3/mod/direct    0/rm32/eax    .           .             .           .           .               4/imm8            # shift eax right by 4 bits, while padding zeroes
    102     25/and-eax  0xf/imm32
    103     # . AL = to-hex-char(AL)
    104     e8/call  to-hex-char/disp32
    105     # write-byte-buffered(f, AL)
    106     # . . push args
    107     50/push-eax
    108     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    109     # . . call
    110     e8/call  write-byte-buffered/disp32
    111     # . . discard args
    112     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    113     # AL = convert lower nibble to hex
    114     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
    115     25/and-eax  0xf/imm32
    116     # . AL = to-hex-char(AL)
    117     e8/call  to-hex-char/disp32
    118     # write-byte-buffered(f, AL)
    119     # . . push args
    120     50/push-eax
    121     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    122     # . . call
    123     e8/call  write-byte-buffered/disp32
    124     # . . discard args
    125     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    126 $write-byte-hex-buffered:end:
    127     # . restore registers
    128     58/pop-to-eax
    129     # . epilogue
    130     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    131     5d/pop-to-ebp
    132     c3/return
    133
    134 test-write-byte-hex-buffered:
    135     # - check that write-byte-hex-buffered prints the hex textual representation
    136     # setup
    137     # . clear-stream(_test-stream)
    138     # . . push args
    139     68/push  _test-stream/imm32
    140     # . . call
    141     e8/call  clear-stream/disp32
    142     # . . discard args
    143     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    144     # . clear-stream($_test-buffered-file->buffer)
    145     # . . push args
    146     68/push  $_test-buffered-file->buffer/imm32
    147     # . . call
    148     e8/call  clear-stream/disp32
    149     # . . discard args
    150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    151     # write-byte-hex-buffered(_test-buffered-file, 0xa)  # exercises digit, non-digit as well as leading zero
    152     # . . push args
    153     68/push  0xa/imm32
    154     68/push  _test-buffered-file/imm32
    155     # . . call
    156     e8/call  write-byte-hex-buffered/disp32
    157     # . . discard args
    158     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    159     # flush(_test-buffered-file)
    160     # . . push args
    161     68/push  _test-buffered-file/imm32
    162     # . . call
    163     e8/call  flush/disp32
    164     # . . discard args
    165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    166     # check-stream-equal(_test-stream, "0a", msg)
    167     # . . push args
    168     68/push  "F - test-write-byte-hex-buffered"/imm32
    169     68/push  "0a"/imm32
    170     68/push  _test-stream/imm32
    171     # . . call
    172     e8/call  check-stream-equal/disp32
    173     # . . discard args
    174     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    175     # . end
    176     c3/return
    177
    178 write-int32-hex:  # f: (addr stream byte), n: int
    179     # . prologue
    180     55/push-ebp
    181     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    182 $write-int32-hex:hex-prefix:
    183     # write(f, "0x")
    184     # . . push args
    185     68/push  "0x"/imm32
    186     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    187     # . . call
    188     e8/call  write/disp32
    189     # . . discard args
    190     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    191 $write-int32-hex:rest:
    192     # write-int32-hex-bits(f, n, 32)
    193     # . . push args
    194     68/push  0x20/imm32
    195     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    196     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    197     # . . call
    198     e8/call  write-int32-hex-bits/disp32
    199     # . . discard args
    200     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    201 $write-int32-hex:end:
    202     # . epilogue
    203     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    204     5d/pop-to-ebp
    205     c3/return
    206
    207 # print rightmost 'bits' of 'n'
    208 # bits must be multiple of 4
    209 write-int32-hex-bits:  # f: (addr stream byte), n: int, bits: int
    210     # pseudocode:
    211     #  bits -= 4
    212     #  while true
    213     #    if (bits < 0) break
    214     #    eax = n >> bits
    215     #    eax = eax & 0xf
    216     #    append-byte(f, AL)
    217     #    bits -= 4
    218     #
    219     # . prologue
    220     55/push-ebp
    221     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    222     # . save registers
    223     50/push-eax
    224     51/push-ecx
    225     # ecx = bits-4
    226     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # copy *(ebp+16) to ecx
    227     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
    228 $write-int32-hex-bits:loop:
    229     # if (bits < 0) break
    230     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32           # compare ecx
    231     7c/jump-if-<  $write-int32-hex-bits:end/disp8
    232     # eax = n >> bits
    233     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
    234     d3/>>ecx    5/subop/pad-zeroes  3/mod/direct    0/rm32/eax    .           .             .           .           .               .                 # shift eax right by ecx bits, padding zeroes
    235     # eax = to-hex-char(AL)
    236     25/and-eax  0xf/imm32
    237     e8/call  to-hex-char/disp32
    238     # append-byte(f, AL)
    239     # . . push args
    240     50/push-eax
    241     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    242     # . . call
    243     e8/call  append-byte/disp32
    244     # . . discard args
    245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    246     # bits -= 4
    247     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
    248     eb/jump  $write-int32-hex-bits:loop/disp8
    249 $write-int32-hex-bits:end:
    250     # . restore registers
    251     59/pop-to-ecx
    252     58/pop-to-eax
    253     # . epilogue
    254     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    255     5d/pop-to-ebp
    256     c3/return
    257
    258 test-write-int32-hex:
    259     # - check that write-int32-hex prints the hex textual representation
    260     # setup
    261     # . clear-stream(_test-stream)
    262     # . . push args
    263     68/push  _test-stream/imm32
    264     # . . call
    265     e8/call  clear-stream/disp32
    266     # . . discard args
    267     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    268     # write-int32-hex(_test-stream, 0x8899aa)
    269     # . . push args
    270     68/push  0x8899aa/imm32
    271     68/push  _test-stream/imm32
    272     # . . call
    273     e8/call  write-int32-hex/disp32
    274     # . . discard args
    275     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    276     # check-stream-equal(_test-stream, "0x008899aa", msg)
    277     # . . push args
    278     68/push  "F - test-write-int32-hex"/imm32
    279     68/push  "0x008899aa"/imm32
    280     68/push  _test-stream/imm32
    281     # . . call
    282     e8/call  check-stream-equal/disp32
    283     # . . discard args
    284     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    285     # . end
    286     c3/return
    287
    288 write-int32-hex-buffered:  # f: (addr buffered-file), n: int
    289     # . prologue
    290     55/push-ebp
    291     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    292 $write-int32-hex-buffered:hex-prefix:
    293     # write-buffered(f, "0x")
    294     # . . push args
    295     68/push  "0x"/imm32
    296     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    297     # . . call
    298     e8/call  write-buffered/disp32
    299     # . . discard args
    300     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    301 $write-int32-hex-buffered:rest:
    302     # write-int32-hex-bits-buffered(f, n, 32)
    303     # . . push args
    304     68/push  0x20/imm32
    305     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    306     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    307     # . . call
    308     e8/call  write-int32-hex-bits-buffered/disp32
    309     # . . discard args
    310     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    311 $write-int32-hex-buffered:end:
    312     # . epilogue
    313     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    314     5d/pop-to-ebp
    315     c3/return
    316
    317 # print rightmost 'bits' of 'n'
    318 # bits must be multiple of 4
    319 write-int32-hex-bits-buffered:  # f: (addr buffered-file), n: int, bits: int
    320     # pseudocode:
    321     #  bits -= 4
    322     #  while true
    323     #    if (bits < 0) break
    324     #    eax = n >> bits
    325     #    eax = eax & 0xf
    326     #    write-byte-buffered(f, AL)
    327     #    bits -= 4
    328     #
    329     # . prologue
    330     55/push-ebp
    331     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    332     # . save registers
    333     50/push-eax
    334     51/push-ecx
    335     # ecx = bits-4
    336     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x10/disp8      .                 # copy *(ebp+16) to ecx
    337     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
    338 $write-int32-hex-bits-buffered:loop:
    339     # if (bits < 0) break
    340     81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32           # compare ecx
    341     7c/jump-if-<  $write-int32-hex-bits-buffered:end/disp8
    342     # eax = n >> bits
    343     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   0xc/disp8       .                 # copy *(ebp+12) to eax
    344     d3/>>ecx    5/subop/pad-zeroes  3/mod/direct    0/rm32/eax    .           .             .           .           .               .                 # shift eax right by ecx bits, padding zeroes
    345     # eax = to-hex-char(AL)
    346     25/and-eax  0xf/imm32
    347     e8/call  to-hex-char/disp32
    348     # write-byte-buffered(f, AL)
    349     # . . push args
    350     50/push-eax
    351     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    352     # . . call
    353     e8/call  write-byte-buffered/disp32
    354     # . . discard args
    355     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    356     # bits -= 4
    357     81          5/subop/subtract    3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # subtract from ecx
    358     eb/jump  $write-int32-hex-bits-buffered:loop/disp8
    359 $write-int32-hex-bits-buffered:end:
    360     # . restore registers
    361     59/pop-to-ecx
    362     58/pop-to-eax
    363     # . epilogue
    364     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    365     5d/pop-to-ebp
    366     c3/return
    367
    368 test-write-int32-hex-buffered:
    369     # - check that write-int32-hex-buffered prints the hex textual representation
    370     # setup
    371     # . clear-stream(_test-stream)
    372     # . . push args
    373     68/push  _test-stream/imm32
    374     # . . call
    375     e8/call  clear-stream/disp32
    376     # . . discard args
    377     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    378     # . clear-stream($_test-buffered-file->buffer)
    379     # . . push args
    380     68/push  $_test-buffered-file->buffer/imm32
    381     # . . call
    382     e8/call  clear-stream/disp32
    383     # . . discard args
    384     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    385     # write-int32-hex-buffered(_test-buffered-file, 0x8899aa)
    386     # . . push args
    387     68/push  0x8899aa/imm32
    388     68/push  _test-buffered-file/imm32
    389     # . . call
    390     e8/call  write-int32-hex-buffered/disp32
    391     # . . discard args
    392     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    393     # flush(_test-buffered-file)
    394     # . . push args
    395     68/push  _test-buffered-file/imm32
    396     # . . call
    397     e8/call  flush/disp32
    398     # . . discard args
    399     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    400 +-- 18 lines: #?     # dump line --------------------------------------------------------------------------------------------------------------------------------------------------------
    418     # check-stream-equal(_test-stream, "0x008899aa", msg)
    419     # . . push args
    420     68/push  "F - test-write-int32-hex-buffered"/imm32
    421     68/push  "0x008899aa"/imm32
    422     68/push  _test-stream/imm32
    423     # . . call
    424     e8/call  check-stream-equal/disp32
    425     # . . discard args
    426     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    427     # . end
    428     c3/return
    429
    430 # . . vim:nowrap:textwidth=0