.
[mu.git] / linux / 130emit.subx
blob40b98be66bc4e7bd14e99b8fef1f1e033241533a
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
6 # If datum of 'word' is not a valid name, it must be a hex int. Parse and print
7 # it in 'width' bytes of hex, least significant first.
8 # Otherwise just print the entire word including metadata.
9 # Always print a trailing space.
10 emit:  # out: (addr buffered-file), word: (addr slice), width: int
11     # . prologue
12     55/push-ebp
13     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
14     # . save registers
15     50/push-eax
16     56/push-esi
17     57/push-edi
18     # esi = word
19     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
20     # var datum/edi: slice
21     68/push  0/imm32/end
22     68/push  0/imm32/start
23     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
24     # datum = next-token-from-slice(word->start, word->end, '/')
25     # . . push args
26     57/push-edi
27     68/push  0x2f/imm32/slash
28     ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # push *(esi+4)
29     ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
30     # . . call
31     e8/call  next-token-from-slice/disp32
32     # . . discard args
33     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
34     # if (valid-name?(datum)) write-slice-buffered(out, word) and return
35     # . eax = valid-name?(name)
36     # . . push args
37     57/push-edi
38     # . . call
39     e8/call  valid-name?/disp32
40     # . . discard args
41     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
42     # . if (eax != false)
43     3d/compare-eax-and  0/imm32/false
44     74/jump-if-=  $emit:hex-int/disp8
45 $emit:name:
46     # . write-slice-buffered(out, word)
47     # . . push args
48     56/push-esi
49     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
50     # . . call
51     e8/call  write-slice-buffered/disp32
52     # . . discard args
53     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
54     # . write-buffered(out, " ")
55     # . . push args
56     68/push  Space/imm32
57     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
58     # . . call
59     e8/call  write-buffered/disp32
60     # . . discard args
61     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
62     # . return
63     eb/jump  $emit:end/disp8
64     # otherwise emit-hex(out, parse-hex-int-from-slice(datum), width)
65     #   (Weird shit can happen here if the datum of 'word' isn't either a valid
66     #   name or a hex number. `emit` is mostly used by translate_subx, which
67     #   is currently designed to only receive legal SubX programs. We just
68     #   want to make sure that valid names aren't treated as (valid) hex
69     #   numbers.)
70 $emit:hex-int:
71     # . var value/eax: int = parse-hex-int-from-slice(datum)
72     # . . push args
73     57/push-edi
74     # . . call
75     e8/call  parse-hex-int-from-slice/disp32
76     # . . discard args
77     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
78     # . emit-hex(out, value, width)
79     # . . push args
80     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
81     50/push-eax
82     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
83     # . . call
84     e8/call  emit-hex/disp32
85     # . . discard args
86     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
87 $emit:end:
88     # . reclaim locals
89     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
90     # . restore registers
91     5f/pop-to-edi
92     5e/pop-to-esi
93     58/pop-to-eax
94     # . epilogue
95     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
96     5d/pop-to-ebp
97     c3/return
99 test-emit-number:
100     # . prologue
101     55/push-ebp
102     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
103     # setup
104     # . clear-stream(_test-output-stream)
105     # . . push args
106     68/push  _test-output-stream/imm32
107     # . . call
108     e8/call  clear-stream/disp32
109     # . . discard args
110     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
111     # . clear-stream($_test-output-buffered-file->buffer)
112     # . . push args
113     68/push  $_test-output-buffered-file->buffer/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     # (eax..ecx) = "30"
119     b8/copy-to-eax  "30"/imm32
120     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
121     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
122     05/add-to-eax  4/imm32
123     # var slice/ecx: slice = {eax, ecx}
124     51/push-ecx
125     50/push-eax
126     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
127     # emit(_test-output-buffered-file, slice, 1)
128     # . . push args
129     68/push  1/imm32
130     51/push-ecx
131     68/push  _test-output-buffered-file/imm32
132     # . . call
133     e8/call  emit/disp32
134     # . . discard args
135     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
136     # flush(_test-output-buffered-file)
137     # . . push args
138     68/push  _test-output-buffered-file/imm32
139     # . . call
140     e8/call  flush/disp32
141     # . . discard args
142     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
143     # check-stream-equal(_test-output-stream, "30 ", msg)
144     # . . push args
145     68/push  "F - test-emit-number/1"/imm32
146     68/push  "30 "/imm32
147     68/push  _test-output-stream/imm32
148     # . . call
149     e8/call  check-stream-equal/disp32
150     # . . discard args
151     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
152     # . epilogue
153     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
154     5d/pop-to-ebp
155     c3/return
157 test-emit-negative-number:
158     # test support for sign-extending negative numbers
159     # . prologue
160     55/push-ebp
161     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
162     # setup
163     # . clear-stream(_test-output-stream)
164     # . . push args
165     68/push  _test-output-stream/imm32
166     # . . call
167     e8/call  clear-stream/disp32
168     # . . discard args
169     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
170     # . clear-stream($_test-output-buffered-file->buffer)
171     # . . push args
172     68/push  $_test-output-buffered-file->buffer/imm32
173     # . . call
174     e8/call  clear-stream/disp32
175     # . . discard args
176     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
177     # (eax..ecx) = "-2"
178     b8/copy-to-eax  "-2"/imm32
179     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
180     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
181     05/add-to-eax  4/imm32
182     # var slice/ecx: slice = {eax, ecx}
183     51/push-ecx
184     50/push-eax
185     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
186     # emit(_test-output-buffered-file, slice, 2)
187     # . . push args
188     68/push  2/imm32
189     51/push-ecx
190     68/push  _test-output-buffered-file/imm32
191     # . . call
192     e8/call  emit/disp32
193     # . . discard args
194     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
195     # flush(_test-output-buffered-file)
196     # . . push args
197     68/push  _test-output-buffered-file/imm32
198     # . . call
199     e8/call  flush/disp32
200     # . . discard args
201     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
202     # check-stream-equal(_test-output-stream, "fe ff ", msg)
203     # . . push args
204     68/push  "F - test-emit-number/1"/imm32
205     68/push  "fe ff "/imm32
206     68/push  _test-output-stream/imm32
207     # . . call
208     e8/call  check-stream-equal/disp32
209     # . . discard args
210     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
211     # . epilogue
212     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
213     5d/pop-to-ebp
214     c3/return
216 test-emit-number-with-metadata:
217     # . prologue
218     55/push-ebp
219     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
220     # setup
221     # . clear-stream(_test-output-stream)
222     # . . push args
223     68/push  _test-output-stream/imm32
224     # . . call
225     e8/call  clear-stream/disp32
226     # . . discard args
227     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
228     # . clear-stream($_test-output-buffered-file->buffer)
229     # . . push args
230     68/push  $_test-output-buffered-file->buffer/imm32
231     # . . call
232     e8/call  clear-stream/disp32
233     # . . discard args
234     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
235     # (eax..ecx) = "-2/foo"
236     b8/copy-to-eax  "-2/foo"/imm32
237     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
238     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
239     05/add-to-eax  4/imm32
240     # var slice/ecx: slice = {eax, ecx}
241     51/push-ecx
242     50/push-eax
243     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
244     # emit(_test-output-buffered-file, slice, 2)
245     # . . push args
246     68/push  2/imm32
247     51/push-ecx
248     68/push  _test-output-buffered-file/imm32
249     # . . call
250     e8/call  emit/disp32
251     # . . discard args
252     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
253     # flush(_test-output-buffered-file)
254     # . . push args
255     68/push  _test-output-buffered-file/imm32
256     # . . call
257     e8/call  flush/disp32
258     # . . discard args
259     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
260     # the '/foo' will have no impact on the output
261     # check-stream-equal(_test-output-stream, "fe ff ", msg)
262     # . . push args
263     68/push  "F - test-emit-number-with-metadata"/imm32
264     68/push  "fe ff "/imm32
265     68/push  _test-output-stream/imm32
266     # . . call
267     e8/call  check-stream-equal/disp32
268     # . . discard args
269     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
270     # . epilogue
271     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
272     5d/pop-to-ebp
273     c3/return
275 test-emit-non-number:
276     # . prologue
277     55/push-ebp
278     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
279     # setup
280     # . clear-stream(_test-output-stream)
281     # . . push args
282     68/push  _test-output-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     # . clear-stream($_test-output-buffered-file->buffer)
288     # . . push args
289     68/push  $_test-output-buffered-file->buffer/imm32
290     # . . call
291     e8/call  clear-stream/disp32
292     # . . discard args
293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
294     # (eax..ecx) = "xyz"
295     b8/copy-to-eax  "xyz"/imm32
296     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
297     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
298     05/add-to-eax  4/imm32
299     # var slice/ecx: slice = {eax, ecx}
300     51/push-ecx
301     50/push-eax
302     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
303     # emit(_test-output-buffered-file, slice, 2)
304     # . . push args
305     68/push  2/imm32
306     51/push-ecx
307     68/push  _test-output-buffered-file/imm32
308     # . . call
309     e8/call  emit/disp32
310     # . . discard args
311     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
312     # flush(_test-output-buffered-file)
313     # . . push args
314     68/push  _test-output-buffered-file/imm32
315     # . . call
316     e8/call  flush/disp32
317     # . . discard args
318     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
319     # check-stream-equal(_test-output-stream, "xyz", msg)
320     # . . push args
321     68/push  "F - test-emit-non-number"/imm32
322     68/push  "xyz "/imm32
323     68/push  _test-output-stream/imm32
324     # . . call
325     e8/call  check-stream-equal/disp32
326     # . . discard args
327     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
328     # . epilogue
329     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
330     5d/pop-to-ebp
331     c3/return
333 test-emit-non-number-with-metadata:
334     # . prologue
335     55/push-ebp
336     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
337     # setup
338     # . clear-stream(_test-output-stream)
339     # . . push args
340     68/push  _test-output-stream/imm32
341     # . . call
342     e8/call  clear-stream/disp32
343     # . . discard args
344     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
345     # . clear-stream($_test-output-buffered-file->buffer)
346     # . . push args
347     68/push  $_test-output-buffered-file->buffer/imm32
348     # . . call
349     e8/call  clear-stream/disp32
350     # . . discard args
351     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
352     # (eax..ecx) = "xyz/"
353     b8/copy-to-eax  "xyz/"/imm32
354     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
355     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
356     05/add-to-eax  4/imm32
357     # var slice/ecx: slice = {eax, ecx}
358     51/push-ecx
359     50/push-eax
360     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
361     # emit(_test-output-buffered-file, slice, 2)
362     # . . push args
363     68/push  2/imm32
364     51/push-ecx
365     68/push  _test-output-buffered-file/imm32
366     # . . call
367     e8/call  emit/disp32
368     # . . discard args
369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
370     # flush(_test-output-buffered-file)
371     # . . push args
372     68/push  _test-output-buffered-file/imm32
373     # . . call
374     e8/call  flush/disp32
375     # . . discard args
376     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
377     # check-stream-equal(_test-output-stream, "xyz/", msg)
378     # . . push args
379     68/push  "F - test-emit-non-number-with-metadata"/imm32
380     68/push  "xyz/ "/imm32
381     68/push  _test-output-stream/imm32
382     # . . call
383     e8/call  check-stream-equal/disp32
384     # . . discard args
385     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
386     # . epilogue
387     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
388     5d/pop-to-ebp
389     c3/return
391 test-emit-non-number-with-all-hex-digits-and-metadata:
392     # . prologue
393     55/push-ebp
394     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
395     # setup
396     # . clear-stream(_test-output-stream)
397     # . . push args
398     68/push  _test-output-stream/imm32
399     # . . call
400     e8/call  clear-stream/disp32
401     # . . discard args
402     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
403     # . clear-stream($_test-output-buffered-file->buffer)
404     # . . push args
405     68/push  $_test-output-buffered-file->buffer/imm32
406     # . . call
407     e8/call  clear-stream/disp32
408     # . . discard args
409     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
410     # (eax..ecx) = "abcd/xyz"
411     b8/copy-to-eax  "abcd/xyz"/imm32
412     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
413     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
414     05/add-to-eax  4/imm32
415     # var slice/ecx: slice = {eax, ecx}
416     51/push-ecx
417     50/push-eax
418     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
419     # emit(_test-output-buffered-file, slice, 2)
420     # . . push args
421     68/push  2/imm32
422     51/push-ecx
423     68/push  _test-output-buffered-file/imm32
424     # . . call
425     e8/call  emit/disp32
426     # . . discard args
427     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
428     # flush(_test-output-buffered-file)
429     # . . push args
430     68/push  _test-output-buffered-file/imm32
431     # . . call
432     e8/call  flush/disp32
433     # . . discard args
434     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
435 #?     # dump output {{{
436 #?     # . write(2/stderr, "^")
437 #?     # . . push args
438 #?     68/push  "^"/imm32
439 #?     68/push  2/imm32/stderr
440 #?     # . . call
441 #?     e8/call  write/disp32
442 #?     # . . discard args
443 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
444 #?     # . write-stream(2/stderr, _test-output-stream)
445 #?     # . . push args
446 #?     68/push  _test-output-stream/imm32
447 #?     68/push  2/imm32/stderr
448 #?     # . . call
449 #?     e8/call  write-stream/disp32
450 #?     # . . discard args
451 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
452 #?     # . write(2/stderr, "$\n")
453 #?     # . . push args
454 #?     68/push  "$\n"/imm32
455 #?     68/push  2/imm32/stderr
456 #?     # . . call
457 #?     e8/call  write/disp32
458 #?     # . . discard args
459 #?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
460 #?     # }}}
461     # check-stream-equal(_test-output-stream, "abcd/xyz")
462     # . . push args
463     68/push  "F - test-emit-non-number-with-all-hex-digits"/imm32
464     68/push  "abcd/xyz "/imm32
465     68/push  _test-output-stream/imm32
466     # . . call
467     e8/call  check-stream-equal/disp32
468     # . . discard args
469     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
470     # . epilogue
471     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
472     5d/pop-to-ebp
473     c3/return