https://github.com/akkartik/mu/blob/master/subx/069slice.subx
  1 # new data structure: a slice is an open interval of addresses [start, end)
  2 # that includes 'start' but not 'end'
  3 
  4 == code
  5 #   instruction                     effective address                                                   register    displacement    immediate
  6 # . op          subop               mod             rm32          base        index         scale       r32
  7 # . 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
  8 
  9 # main:
 10     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
 11     # syscall(exit, Num-test-failures)
 12     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 13     b8/copy-to-EAX  1/imm32/exit
 14     cd/syscall  0x80/imm8
 15 
 16 slice-empty?:  # s : (address slice) -> bool/EAX
 17     # . prolog
 18     55/push-EBP
 19     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 20     # . save registers
 21     51/push-ECX
 22     # ECX = s
 23     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
 24     # if s->start == s->end return true
 25     # . EAX = s->start
 26     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
 27     # . compare EAX with s->end
 28     39/compare                      1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # compare EAX and *(ECX+4)
 29     b8/copy-to-EAX  1/imm32/true
 30     74/jump-if-equal  $slice-empty?:end/disp8
 31     b8/copy-to-EAX  0/imm32/false
 32 $slice-empty?:end:
 33     # . restore registers
 34     59/pop-to-ECX
 35     # . epilog
 36     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 37     5d/pop-to-EBP
 38     c3/return
 39 
 40 test-slice-empty-true:
 41     # . prolog
 42     55/push-EBP
 43     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 44     # var slice/ECX = {34, 34}
 45     68/push  34/imm32/end
 46     68/push  34/imm32/start
 47     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 48     # slice-empty?(slice)
 49     # . . push args
 50     51/push-ECX
 51     # . . call
 52     e8/call  slice-empty?/disp32
 53     # . . discard args
 54     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 55     # check-ints-equal(EAX, 1, msg)
 56     # . . push args
 57     68/push  "F - test-slice-empty-true"/imm32
 58     68/push  1/imm32
 59     50/push-EAX
 60     # . . call
 61     e8/call  check-ints-equal/disp32
 62     # . . discard args
 63     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 64     # . epilog
 65     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 66     5d/pop-to-EBP
 67     c3/return
 68 
 69 test-slice-empty-false:
 70     # . prolog
 71     55/push-EBP
 72     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 73     # var slice/ECX = {34, 23}
 74     68/push  23/imm32/end
 75     68/push  34/imm32/start
 76     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 77     # slice-empty?(slice)
 78     # . . push args
 79     51/push-ECX
 80     # . . call
 81     e8/call  slice-empty?/disp32
 82     # . . discard args
 83     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 84     # check-ints-equal(EAX, 0, msg)
 85     # . . push args
 86     68/push  "F - test-slice-empty-false"/imm32
 87     68/push  0/imm32
 88     50/push-EAX
 89     # . . call
 90     e8/call  check-ints-equal/disp32
 91     # . . discard args
 92     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 93     # . epilog
 94     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 95     5d/pop-to-EBP
 96     c3/return
 97 
 98 slice-equal?:  # s : (address slice), k : (address kernel-string) -> bool/EAX
 99     # . prolog
100     55/push-EBP
101     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
102     # . save registers
103     51/push-ECX
104     52/push-EDX
105     53/push-EBX
106     56/push-ESI
107     # EAX = ECX = false
108     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
109     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
110     # ESI = s
111     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
112     # curr/EDX = s->start
113     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
114     # max/ESI = s->end
115     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
116     # EBX = k
117     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
118 $slice-equal?:loop:
119     # AL = *k
120     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
121     # if (curr >= max) return *k == 0
122     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           6/r32/ESI   .               .                 # compare EDX and ESI
123     7c/jump-if-lesser  $slice-equal?:check2/disp8
124     3d/compare-with-EAX  0/imm32
125     74/jump-if-equal  $slice-equal?:true/disp8
126     eb/jump  $slice-equal?:false/disp8
127 $slice-equal?:check2:
128     # if (EAX == 0) return false
129     3d/compare-with-EAX  0/imm32
130     74/jump-if-equal  $slice-equal?:false/disp8
131     # CL = *curr
132     8a/copy-byte                    0/mod/indirect  2/rm32/EDX    .           .             .           1/r32/CL    .               .                 # copy byte at *EDX to CL
133     # if (EAX != ECX) return false
134     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX and ECX
135     75/jump-if-not-equal  $slice-equal?:false/disp8
136     # ++k
137     43/increment-EBX
138     # ++curr
139     42/increment-EDX
140     eb/jump $slice-equal?:loop/disp8
141 $slice-equal?:false:
142     b8/copy-to-EAX  0/imm32
143     eb/jump  $slice-equal?:end/disp8
144 $slice-equal?:true:
145     b8/copy-to-EAX  1/imm32
146 $slice-equal?:end:
147     # . restore registers
148     5e/pop-to-ESI
149     5b/pop-to-EBX
150     5a/pop-to-EDX
151     59/pop-to-ECX
152     # . epilog
153     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
154     5d/pop-to-EBP
155     c3/return
156 
157 test-slice-equal:
158     # - slice-equal?(slice("Abc"), "Abc") == 1
159     # . prolog
160     55/push-EBP
161     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
162     # var slice/ECX
163     68/push  _test-slice-data-3/imm32/end
164     68/push  _test-slice-data-0/imm32/start
165     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
166     # EAX = slice-equal?(ECX, "Abc")
167     # . . push args
168     68/push  _test-Abc-kernel-string/imm32
169     51/push-ECX
170     # . . call
171     e8/call  slice-equal?/disp32
172     # . . discard args
173     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
174     # check-ints-equal(EAX, 1, msg)
175     # . . push args
176     68/push  "F - test-slice-equal"/imm32
177     68/push  1/imm32
178     50/push-EAX
179     # . . call
180     e8/call  check-ints-equal/disp32
181     # . . discard args
182     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
183     # . epilog
184     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
185     5d/pop-to-EBP
186     c3/return
187 
188 test-slice-equal-false:
189     # - slice-equal?(slice("bcd"), "Abc") == 0
190     # . prolog
191     55/push-EBP
192     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
193     # var slice/ECX
194     68/push  _test-slice-data-4/imm32/end
195     68/push  _test-slice-data-1/imm32/start
196     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
197     # EAX = slice-equal?(ECX, "Abc")
198     # . . push args
199     68/push  _test-Abc-kernel-string/imm32
200     51/push-ECX
201     # . . call
202     e8/call  slice-equal?/disp32
203     # . . discard args
204     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
205     # check-ints-equal(EAX, 0, msg)
206     # . . push args
207     68/push  "F - test-slice-equal-false"/imm32
208     68/push  0/imm32
209     50/push-EAX
210     # . . call
211     e8/call  check-ints-equal/disp32
212     # . . discard args
213     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
214     # . epilog
215     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
216     5d/pop-to-EBP
217     c3/return
218 
219 test-slice-equal-too-long:
220     # - slice-equal?(slice("Abcd"), "Abc") == 0
221     # . prolog
222     55/push-EBP
223     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
224     # var slice/ECX
225     68/push  _test-slice-data-4/imm32/end
226     68/push  _test-slice-data-0/imm32/start
227     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
228     # EAX = slice-equal?(ECX, "Abc")
229     # . . push args
230     68/push  _test-Abc-kernel-string/imm32
231     51/push-ECX
232     # . . call
233     e8/call  slice-equal?/disp32
234     # . . discard args
235     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
236     # check-ints-equal(EAX, 0, msg)
237     # . . push args
238     68/push  "F - test-slice-equal-too-long"/imm32
239     68/push  0/imm32
240     50/push-EAX
241     # . . call
242     e8/call  check-ints-equal/disp32
243     # . . discard args
244     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
245     # . epilog
246     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
247     5d/pop-to-EBP
248     c3/return
249 
250 test-slice-equal-too-short:
251     # - slice-equal?(slice("A"), "Abc") == 0
252     # . prolog
253     55/push-EBP
254     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
255     # var slice/ECX
256     68/push  _test-slice-data-1/imm32/end
257     68/push  _test-slice-data-0/imm32/start
258     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
259     # EAX = slice-equal?(ECX, "Abc")
260     # . . push args
261     68/push  _test-Abc-kernel-string/imm32
262     51/push-ECX
263     # . . call
264     e8/call  slice-equal?/disp32
265     # . . discard args
266     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
267     # check-ints-equal(EAX, 0, msg)
268     # . . push args
269     68/push  "F - test-slice-equal-too-short"/imm32
270     68/push  0/imm32
271     50/push-EAX
272     # . . call
273     e8/call  check-ints-equal/disp32
274     # . . discard args
275     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
276     # . epilog
277     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
278     5d/pop-to-EBP
279     c3/return
280 
281 test-slice-equal-empty:
282     # - slice-equal?(slice(""), "Abc") == 0
283     # . prolog
284     55/push-EBP
285     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
286     # var slice/ECX
287     68/push  _test-slice-data-0/imm32/end
288     68/push  _test-slice-data-0/imm32/start
289     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
290     # EAX = slice-equal?(ECX, "Abc")
291     # . . push args
292     68/push  _test-Abc-kernel-string/imm32
293     51/push-ECX
294     # . . call
295     e8/call  slice-equal?/disp32
296     # . . discard args
297     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
298     # check-ints-equal(EAX, 0, msg)
299     # . . push args
300     68/push  "F - test-slice-equal-empty"/imm32
301     68/push  0/imm32
302     50/push-EAX
303     # . . call
304     e8/call  check-ints-equal/disp32
305     # . . discard args
306     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
307     # . epilog
308     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
309     5d/pop-to-EBP
310     c3/return
311 
312 test-slice-equal-with-empty:
313     # - slice-equal?(slice("Ab"), "") == 0
314     # . prolog
315     55/push-EBP
316     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
317     # var slice/ECX
318     68/push  _test-slice-data-2/imm32/end
319     68/push  _test-slice-data-0/imm32/start
320     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
321     # EAX = slice-equal?(ECX, "")
322     # . . push args
323     68/push  Null-kernel-string/imm32
324     51/push-ECX
325     # . . call
326     e8/call  slice-equal?/disp32
327     # . . discard args
328     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
329     # check-ints-equal(EAX, 0, msg)
330     # . . push args
331     68/push  "F - test-slice-equal-with-empty"/imm32
332     68/push  0/imm32
333     50/push-EAX
334     # . . call
335     e8/call  check-ints-equal/disp32
336     # . . discard args
337     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
338     # . epilog
339     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
340     5d/pop-to-EBP
341     c3/return
342 
343 test-slice-equal-empty-with-empty:
344     # - slice-equal?(slice(""), "") == 1
345     # . prolog
346     55/push-EBP
347     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
348     # var slice/ECX
349     68/push  _test-slice-data-0/imm32/end
350     68/push  _test-slice-data-0/imm32/start
351     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
352     # EAX = slice-equal?(ECX, "")
353     # . . push args
354     68/push  Null-kernel-string/imm32
355     51/push-ECX
356     # . . call
357     e8/call  slice-equal?/disp32
358     # . . discard args
359     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
360     # check-ints-equal(EAX, 1, msg)
361     # . . push args
362     68/push  "F - test-slice-equal-empty-with-empty"/imm32
363     68/push  1/imm32
364     50/push-EAX
365     # . . call
366     e8/call  check-ints-equal/disp32
367     # . . discard args
368     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
369     # . epilog
370     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
371     5d/pop-to-EBP
372     c3/return
373 
374 == data
375 
376 _test-slice-data-0:
377     41/A
378 _test-slice-data-1:
379     62/b
380 _test-slice-data-2:
381     63/c
382 _test-slice-data-3:
383     64/d
384 _test-slice-data-4:
385 
386 # . . vim:nowrap:textwidth=0