https://github.com/akkartik/mu/blob/master/subx/apps/subx-common.subx
  1 # some common helpers shared by phases of the SubX converter
  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 # write an entire stream's contents to a buffered-file
  9 # ways to do this:
 10 #   - construct a 'maximal slice' and pass it to write-slice-buffered
 11 #   - flush the buffered-file and pass the stream directly to its fd (disabling buffering)
 12 # we'll go with the first way for now
 13 write-stream-data:  # f : (address buffered-file), s : (address stream) -> <void>
 14     # . prolog
 15     55/push-EBP
 16     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 17     # . save registers
 18     50/push-EAX
 19     51/push-ECX
 20     56/push-ESI
 21     # ESI = s
 22     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
 23     # var slice/ECX = {s->data, s->data + s->write}
 24     # . push s->data + s->write
 25     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
 26     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  0/index/EAX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+EAX+12 to EAX
 27     50/push-EAX
 28     # . push s->data
 29     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy ESI+12 to EAX
 30     50/push-EAX
 31     # . ECX = ESP
 32     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 33     # write-slice-buffered(f, slice)
 34     # . . push args
 35     51/push-ECX
 36     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
 37     # . . call
 38     e8/call  write-slice-buffered/disp32
 39     # . . discard args
 40     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 41 $write-stream-data:end:
 42     # . restore locals
 43     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 44     # . restore registers
 45     5e/pop-to-ESI
 46     59/pop-to-ECX
 47     58/pop-to-EAX
 48     # . epilog
 49     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 50     5d/pop-to-EBP
 51     c3/return
 52 
 53 test-write-stream-data:
 54     # . prolog
 55     55/push-EBP
 56     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 57     # setup
 58     # . clear-stream(_test-output-stream)
 59     # . . push args
 60     68/push  _test-output-stream/imm32
 61     # . . call
 62     e8/call  clear-stream/disp32
 63     # . . discard args
 64     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 65     # . clear-stream(_test-output-buffered-file+4)
 66     # . . push args
 67     b8/copy-to-EAX  _test-output-buffered-file/imm32
 68     05/add-to-EAX  4/imm32
 69     50/push-EAX
 70     # . . call
 71     e8/call  clear-stream/disp32
 72     # . . discard args
 73     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 74     # . clear-stream(_test-input-stream)
 75     # . . push args
 76     68/push  _test-input-stream/imm32
 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     # initialize input
 82     # . write(_test-input-stream, "abcd")
 83     # . . push args
 84     68/push  "abcd"/imm32
 85     68/push  _test-input-stream/imm32
 86     # . . call
 87     e8/call  write/disp32
 88     # . . discard args
 89     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 90     # write-stream-data(_test-output-buffered-file, _test-input-stream)
 91     # . . push args
 92     68/push  _test-input-stream/imm32
 93     68/push  _test-output-buffered-file/imm32
 94     # . . call
 95     e8/call  write-stream-data/disp32
 96     # . . discard args
 97     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 98     # check that the write happened as expected
 99     # . flush(_test-output-buffered-file)
100     # . . push args
101     68/push  _test-output-buffered-file/imm32
102     # . . call
103     e8/call  flush/disp32
104     # . . discard args
105     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
106     # . check-stream-equal(_test-output-stream, "abcd", msg)
107     # . . push args
108     68/push  "F - test-write-stream-data"/imm32
109     68/push  "abcd"/imm32
110     68/push  _test-output-stream/imm32
111     # . . call
112     e8/call  check-stream-equal/disp32
113     # . . discard args
114     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
115     # . epilog
116     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
117     5d/pop-to-EBP
118     c3/return
119 
120 == data
121 
122 _test-input-stream:
123     # current write index
124     0/imm32
125     # current read index
126     0/imm32
127     # length
128     0x100/imm32  # 256 bytes
129     # data (16 lines x 16 bytes/line)
130     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
132     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
133     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
134     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
135     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
136     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
137     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
138     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
139     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
140     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
141     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
142     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
143     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
144     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
145     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
146 
147 # a test buffered file for _test-input-stream
148 _test-input-buffered-file:
149     # file descriptor or (address stream)
150     _test-input-stream/imm32
151     # current write index
152     0/imm32
153     # current read index
154     0/imm32
155     # length
156     6/imm32
157     # data
158     00 00 00 00 00 00  # 6 bytes
159 
160 _test-output-stream:
161     # current write index
162     0/imm32
163     # current read index
164     0/imm32
165     # length
166     0x100/imm32  # 256 bytes
167     # data (16 lines x 16 bytes/line)
168     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
169     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
170     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
171     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
172     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
173     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
174     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
175     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
176     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
177     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
178     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
179     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
180     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
181     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
182     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
183     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
184 
185 # a test buffered file for _test-output-stream
186 _test-output-buffered-file:
187     # file descriptor or (address stream)
188     _test-output-stream/imm32
189     # current write index
190     0/imm32
191     # current read index
192     0/imm32
193     # length
194     6/imm32
195     # data
196     00 00 00 00 00 00  # 6 bytes
197 
198 # . . vim:nowrap:textwidth=0