https://github.com/akkartik/mu/blob/main/linux/129emit-hex.subx

      1 == code
      2 #   instruction                     effective address                                                   register    displacement    immediate
      3 # . op          subop               mod             rm32          base        index         scale       r32
      4 # . 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
      5
      6 # print 'n' in hex in 'width' bytes in lower-endian order, with a space after every byte
      7 emit-hex:  # out: (addr buffered-file), n: int, width: int
      8     # . prologue
      9     55/push-ebp
     10     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     11     # . save registers
     12     50/push-eax
     13     51/push-ecx
     14     52/push-edx
     15     53/push-ebx
     16     57/push-edi
     17     # edi = out
     18     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
     19     # ebx = n
     20     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
     21     # edx = width
     22     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0x10/disp8      .                 # copy *(ebp+16) to edx
     23     # var curr/ecx: int = 0
     24     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
     25 $emit-hex:loop:
     26     # if (curr >= width) break
     27     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
     28     7d/jump-if->=  $emit-hex:end/disp8
     29     # write-byte-hex-buffered(out, ebx)  # only BL used
     30     # . . push args
     31     53/push-ebx
     32     57/push-edi
     33     # . . call
     34     e8/call  write-byte-hex-buffered/disp32
     35     # . . discard args
     36     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     37     # write-byte-buffered(out, ' ')
     38     # . . push args
     39     68/push  0x20/imm32/space
     40     57/push-edi
     41     # . . call
     42     e8/call  write-byte-buffered/disp32
     43     # . . discard args
     44     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     45     # ebx = ebx >> 8
     46     c1/shift    5/subop/logic-right 3/mod/direct    3/rm32/ebx    .           .             .           .           .               8/imm8            # shift ebx right by 8 bits, while padding zeroes
     47 $emit-hex:continue:
     48     # ++curr
     49     41/increment-ecx
     50     eb/jump  $emit-hex:loop/disp8
     51 $emit-hex:end:
     52     # . restore registers
     53     5f/pop-to-edi
     54     5b/pop-to-ebx
     55     5a/pop-to-edx
     56     59/pop-to-ecx
     57     58/pop-to-eax
     58     # . epilogue
     59     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     60     5d/pop-to-ebp
     61     c3/return
     62
     63 test-emit-hex-single-byte:
     64     # setup
     65     # . clear-stream(_test-output-stream)
     66     # . . push args
     67     68/push  _test-output-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     # . clear-stream($_test-output-buffered-file->buffer)
     73     # . . push args
     74     68/push  $_test-output-buffered-file->buffer/imm32
     75     # . . call
     76     e8/call  clear-stream/disp32
     77     # . . discard args
     78     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     79     # emit-hex(_test-output-buffered-file, 0xab, 1)
     80     # . . push args
     81     68/push  1/imm32
     82     68/push  0xab/imm32
     83     68/push  _test-output-buffered-file/imm32
     84     # . . call
     85     e8/call  emit-hex/disp32
     86     # . . discard args
     87     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
     88     # flush(_test-output-buffered-file)
     89     # . . push args
     90     68/push  _test-output-buffered-file/imm32
     91     # . . call
     92     e8/call  flush/disp32
     93     # . . discard args
     94     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     95     # check-ints-equal(*_test-output-stream->data, 'ab ', msg)
     96     # . . push args
     97     68/push  "F - test-emit-hex-single-byte"/imm32
     98     68/push  0x206261/imm32
     99     # . . push *_test-output-stream->data
    100     b8/copy-to-eax  _test-output-stream/imm32
    101     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
    102     # . . call
    103     e8/call  check-ints-equal/disp32
    104     # . . discard args
    105     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    106     # . end
    107     c3/return
    108
    109 test-emit-hex-multiple-byte:
    110     # setup
    111     # . clear-stream(_test-output-stream)
    112     # . . push args
    113     68/push  _test-output-stream/imm32
    114     # . . call
    115     e8/call  clear-stream/disp32
    116     # . . discard args
    117     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    118     # . clear-stream($_test-output-buffered-file->buffer)
    119     # . . push args
    120     68/push  $_test-output-buffered-file->buffer/imm32
    121     # . . call
    122     e8/call  clear-stream/disp32
    123     # . . discard args
    124     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    125     # emit-hex(_test-output-buffered-file, 0x1234, 2)
    126     # . . push args
    127     68/push  2/imm32
    128     68/push  0x1234/imm32
    129     68/push  _test-output-buffered-file/imm32
    130     # . . call
    131     e8/call  emit-hex/disp32
    132     # . . discard args
    133     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    134     # flush(_test-output-buffered-file)
    135     # . . push args
    136     68/push  _test-output-buffered-file/imm32
    137     # . . call
    138     e8/call  flush/disp32
    139     # . . discard args
    140     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    141     # check-stream-equal(_test-output-stream, "34 12 ", msg)
    142     # . . push args
    143     68/push  "F - test-emit-hex-multiple-byte/1"/imm32
    144     68/push  "34 12 "/imm32
    145     68/push  _test-output-stream/imm32
    146     # . . call
    147     e8/call  check-stream-equal/disp32
    148     # . . discard args
    149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    150     # . end
    151     c3/return
    152
    153 test-emit-hex-zero-pad:
    154     # setup
    155     # . clear-stream(_test-output-stream)
    156     # . . push args
    157     68/push  _test-output-stream/imm32
    158     # . . call
    159     e8/call  clear-stream/disp32
    160     # . . discard args
    161     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    162     # . clear-stream($_test-output-buffered-file->buffer)
    163     # . . push args
    164     68/push  $_test-output-buffered-file->buffer/imm32
    165     # . . call
    166     e8/call  clear-stream/disp32
    167     # . . discard args
    168     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    169     # emit-hex(_test-output-buffered-file, 0xab, 2)
    170     # . . push args
    171     68/push  2/imm32
    172     68/push  0xab/imm32
    173     68/push  _test-output-buffered-file/imm32
    174     # . . call
    175     e8/call  emit-hex/disp32
    176     # . . discard args
    177     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    178     # flush(_test-output-buffered-file)
    179     # . . push args
    180     68/push  _test-output-buffered-file/imm32
    181     # . . call
    182     e8/call  flush/disp32
    183     # . . discard args
    184     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    185     # check(_test-output-stream->data == 'ab 00 ')
    186     # . . push args
    187     68/push  "F - test-emit-hex-zero-pad/1"/imm32
    188     68/push  "ab 00 "/imm32
    189     68/push  _test-output-stream/imm32
    190     # . . call
    191     e8/call  check-stream-equal/disp32
    192     # . . discard args
    193     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    194     # . end
    195     c3/return
    196
    197 test-emit-hex-negative:
    198     # setup
    199     # . clear-stream(_test-output-stream)
    200     # . . push args
    201     68/push  _test-output-stream/imm32
    202     # . . call
    203     e8/call  clear-stream/disp32
    204     # . . discard args
    205     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    206     # . clear-stream($_test-output-buffered-file->buffer)
    207     # . . push args
    208     68/push  $_test-output-buffered-file->buffer/imm32
    209     # . . call
    210     e8/call  clear-stream/disp32
    211     # . . discard args
    212     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    213     # emit-hex(_test-output-buffered-file, -1, 2)
    214     # . . push args
    215     68/push  2/imm32
    216     68/push  -1/imm32
    217     68/push  _test-output-buffered-file/imm32
    218     # . . call
    219     e8/call  emit-hex/disp32
    220     # . . discard args
    221     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    222     # flush(_test-output-buffered-file)
    223     # . . push args
    224     68/push  _test-output-buffered-file/imm32
    225     # . . call
    226     e8/call  flush/disp32
    227     # . . discard args
    228     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    229     # check-stream-equal(_test-output-stream == "ff ff ")
    230     # . . push args
    231     68/push  "F - test-emit-hex-negative/1"/imm32
    232     68/push  "ff ff "/imm32
    233     68/push  _test-output-stream/imm32
    234     # . . call
    235     e8/call  check-stream-equal/disp32
    236     # . . discard args
    237     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    238     # . end
    239     c3/return
    240
    241 # . . vim:nowrap:textwidth=0