https://github.com/akkartik/mu/blob/master/078emit-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 : (address 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 = 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-greater-or-equal  $emit-hex:end/disp8
 29     # print-byte-buffered(out, ebx)
 30     # . . push args
 31     53/push-ebx
 32     57/push-edi
 33     # . . call
 34     e8/call  print-byte-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+4)
 73     # . . push args
 74     b8/copy-to-eax  _test-output-buffered-file/imm32
 75     05/add-to-eax  4/imm32
 76     50/push-eax
 77     # . . call
 78     e8/call  clear-stream/disp32
 79     # . . discard args
 80     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 81     # emit-hex(_test-output-buffered-file, 0xab, 1)
 82     # . . push args
 83     68/push  1/imm32
 84     68/push  0xab/imm32
 85     68/push  _test-output-buffered-file/imm32
 86     # . . call
 87     e8/call  emit-hex/disp32
 88     # . . discard args
 89     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 90     # flush(_test-output-buffered-file)
 91     # . . push args
 92     68/push  _test-output-buffered-file/imm32
 93     # . . call
 94     e8/call  flush/disp32
 95     # . . discard args
 96     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 97     # check-ints-equal(*_test-output-stream->data, 'ab ', msg)
 98     # . . push args
 99     68/push  "F - test-emit-hex-single-byte"/imm32
100     68/push  0x206261/imm32
101     # . . push *_test-output-stream->data
102     b8/copy-to-eax  _test-output-stream/imm32
103     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
104     # . . call
105     e8/call  check-ints-equal/disp32
106     # . . discard args
107     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
108     # . end
109     c3/return
110 
111 test-emit-hex-multiple-byte:
112     # setup
113     # . clear-stream(_test-output-stream)
114     # . . push args
115     68/push  _test-output-stream/imm32
116     # . . call
117     e8/call  clear-stream/disp32
118     # . . discard args
119     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
120     # . clear-stream(_test-output-buffered-file+4)
121     # . . push args
122     b8/copy-to-eax  _test-output-buffered-file/imm32
123     05/add-to-eax  4/imm32
124     50/push-eax
125     # . . call
126     e8/call  clear-stream/disp32
127     # . . discard args
128     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
129     # emit-hex(_test-output-buffered-file, 0x1234, 2)
130     # . . push args
131     68/push  2/imm32
132     68/push  0x1234/imm32
133     68/push  _test-output-buffered-file/imm32
134     # . . call
135     e8/call  emit-hex/disp32
136     # . . discard args
137     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
138     # flush(_test-output-buffered-file)
139     # . . push args
140     68/push  _test-output-buffered-file/imm32
141     # . . call
142     e8/call  flush/disp32
143     # . . discard args
144     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
145     # check-stream-equal(_test-output-stream, "34 12 ", msg)
146     # . . push args
147     68/push  "F - test-emit-hex-multiple-byte/1"/imm32
148     68/push  "34 12 "/imm32
149     68/push  _test-output-stream/imm32
150     # . . call
151     e8/call  check-stream-equal/disp32
152     # . . discard args
153     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
154     # . end
155     c3/return
156 
157 test-emit-hex-zero-pad:
158     # setup
159     # . clear-stream(_test-output-stream)
160     # . . push args
161     68/push  _test-output-stream/imm32
162     # . . call
163     e8/call  clear-stream/disp32
164     # . . discard args
165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
166     # . clear-stream(_test-output-buffered-file+4)
167     # . . push args
168     b8/copy-to-eax  _test-output-buffered-file/imm32
169     05/add-to-eax  4/imm32
170     50/push-eax
171     # . . call
172     e8/call  clear-stream/disp32
173     # . . discard args
174     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
175     # emit-hex(_test-output-buffered-file, 0xab, 2)
176     # . . push args
177     68/push  2/imm32
178     68/push  0xab/imm32
179     68/push  _test-output-buffered-file/imm32
180     # . . call
181     e8/call  emit-hex/disp32
182     # . . discard args
183     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
184     # flush(_test-output-buffered-file)
185     # . . push args
186     68/push  _test-output-buffered-file/imm32
187     # . . call
188     e8/call  flush/disp32
189     # . . discard args
190     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
191     # check(_test-output-stream->data == 'ab 00 ')
192     # . . push args
193     68/push  "F - test-emit-hex-zero-pad/1"/imm32
194     68/push  "ab 00 "/imm32
195     68/push  _test-output-stream/imm32
196     # . . call
197     e8/call  check-stream-equal/disp32
198     # . . discard args
199     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
200     # . end
201     c3/return
202 
203 test-emit-hex-negative:
204     # setup
205     # . clear-stream(_test-output-stream)
206     # . . push args
207     68/push  _test-output-stream/imm32
208     # . . call
209     e8/call  clear-stream/disp32
210     # . . discard args
211     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
212     # . clear-stream(_test-output-buffered-file+4)
213     # . . push args
214     b8/copy-to-eax  _test-output-buffered-file/imm32
215     05/add-to-eax  4/imm32
216     50/push-eax
217     # . . call
218     e8/call  clear-stream/disp32
219     # . . discard args
220     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
221     # emit-hex(_test-output-buffered-file, -1, 2)
222     # . . push args
223     68/push  2/imm32
224     68/push  -1/imm32
225     68/push  _test-output-buffered-file/imm32
226     # . . call
227     e8/call  emit-hex/disp32
228     # . . discard args
229     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
230     # flush(_test-output-buffered-file)
231     # . . push args
232     68/push  _test-output-buffered-file/imm32
233     # . . call
234     e8/call  flush/disp32
235     # . . discard args
236     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
237     # check-stream-equal(_test-output-stream == "ff ff ")
238     # . . push args
239     68/push  "F - test-emit-hex-negative/1"/imm32
240     68/push  "ff ff "/imm32
241     68/push  _test-output-stream/imm32
242     # . . call
243     e8/call  check-stream-equal/disp32
244     # . . discard args
245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
246     # . end
247     c3/return
248 
249 # . . vim:nowrap:textwidth=0