https://github.com/akkartik/mu/blob/master/052kernel-string-equal.subx
  1 # Checking null-terminated strings.
  2 #
  3 # By default we create strings as arrays of bytes, and all arrays have a 4-byte
  4 # size prefix.
  5 #
  6 # However, we sometimes need to deal with null-terminated strings when
  7 # interacting with the Linux kernel. This layer implements a function for
  8 # comparing a null-terminated 'kernel string' with a size-prefixed 'SubX
  9 # string'.
 10 #
 11 # To run (from the subx directory):
 12 #   $ ./bootstrap translate 05[0-2]*.subx -o /tmp/tmp52
 13 #   $ ./bootstrap run /tmp/tmp52  # runs a series of tests
 14 #   ......  # all tests pass
 15 #
 16 # (We can't yet run the tests when given a "test" commandline argument,
 17 # because checking for it would require the function being tested! Breakage
 18 # would cause tests to not run, rather than to fail as we'd like.)
 19 
 20 == code
 21 #   instruction                     effective address                                                   register    displacement    immediate
 22 # . op          subop               mod             rm32          base        index         scale       r32
 23 # . 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
 24 
 25 Entry:  # run all tests
 26     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
 27     # syscall(exit, Num-test-failures)
 28     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
 29     b8/copy-to-eax  1/imm32/exit
 30     cd/syscall  0x80/imm8
 31 
 32 kernel-string-equal?:  # s: (addr kernel-string), benchmark: (addr array byte) -> eax: boolean
 33     # pseudocode:
 34     #   n = benchmark->size
 35     #   s1 = s
 36     #   s2 = benchmark->data
 37     #   i = 0
 38     #   while (i < n)
 39     #     c1 = *s1
 40     #     c2 = *s2
 41     #     if (c1 == 0) return false
 42     #     if (c1 != c2) return false
 43     #     ++s1, ++s2, ++i
 44     #   return *s1 == 0
 45     #
 46     # registers:
 47     #   i: ecx
 48     #   n: edx
 49     #   s1: edi
 50     #   s2: esi
 51     #   c1: eax
 52     #   c2: ebx
 53     #
 54     # . prologue
 55     55/push-ebp
 56     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 57     # . save registers
 58     51/push-ecx
 59     52/push-edx
 60     53/push-ebx
 61     56/push-esi
 62     57/push-edi
 63     # var s1/edi: (addr byte) = s
 64     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
 65     # var n/edx: int = benchmark->size
 66     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
 67     8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
 68     # var s2/esi: (addr byte) = benchmark->data
 69     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
 70     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
 71     # var i/ecx: int = 0
 72     b9/copy-to-ecx  0/imm32/exit
 73     # var c1/eax: byte = 0
 74     b8/copy-to-eax  0/imm32
 75     # var c2/ebx: byte = 0
 76     bb/copy-to-ebx  0/imm32
 77 $kernel-string-equal?:loop:
 78     # if (i >= n) break
 79     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
 80     7d/jump-if->=  $kernel-string-equal?:break/disp8
 81     # c1 = *s1
 82     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
 83     # c2 = *s2
 84     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
 85     # if (c1 == 0) return false
 86     3d/compare-eax-and  0/imm32/null
 87     74/jump-if-=  $kernel-string-equal?:false/disp8
 88     # if (c1 != c2) return false
 89     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
 90     75/jump-if-!=  $kernel-string-equal?:false/disp8
 91     # ++i
 92     41/increment-ecx
 93     # ++s1
 94     47/increment-edi
 95     # ++s2
 96     46/increment-esi
 97     eb/jump  $kernel-string-equal?:loop/disp8
 98 $kernel-string-equal?:break:
 99     # return *s1 == 0
100     8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           0/r32/AL    .               .                 # copy byte at *edi to AL
101     3d/compare-eax-and  0/imm32/null
102     75/jump-if-!=  $kernel-string-equal?:false/disp8
103 $kernel-string-equal?:true:
104     b8/copy-to-eax  1/imm32
105     eb/jump  $kernel-string-equal?:end/disp8
106 $kernel-string-equal?:false:
107     b8/copy-to-eax  0/imm32
108 $kernel-string-equal?:end:
109     # . restore registers
110     5f/pop-to-edi
111     5e/pop-to-esi
112     5b/pop-to-ebx
113     5a/pop-to-edx
114     59/pop-to-ecx
115     # . epilogue
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 # - tests
121 
122 test-compare-null-kernel-string-with-empty-array:
123     # eax = kernel-string-equal?(Null-kernel-string, "")
124     # . . push args
125     68/push  ""/imm32
126     68/push  Null-kernel-string/imm32
127     # . . call
128     e8/call  kernel-string-equal?/disp32
129     # . . discard args
130     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
131     # check-ints-equal(eax, 1, msg)
132     # . . push args
133     68/push  "F - test-compare-null-kernel-string-with-empty-array"/imm32
134     68/push  1/imm32/true
135     50/push-eax
136     # . . call
137     e8/call  check-ints-equal/disp32
138     # . . discard args
139     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
140     c3/return
141 
142 test-compare-null-kernel-string-with-non-empty-array:
143     # eax = kernel-string-equal?(Null-kernel-string, "Abc")
144     # . . push args
145     68/push  "Abc"/imm32
146     68/push  Null-kernel-string/imm32
147     # . . call
148     e8/call  kernel-string-equal?/disp32
149     # . . discard args
150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
151     # check-ints-equal(eax, 0, msg)
152     # . . push args
153     68/push  "F - test-compare-null-kernel-string-with-non-empty-array"/imm32
154     68/push  0/imm32/false
155     50/push-eax
156     # . . call
157     e8/call  check-ints-equal/disp32
158     # . . discard args
159     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
160     c3/return
161 
162 test-compare-kernel-string-with-equal-array:
163     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
164     # . . push args
165     68/push  "Abc"/imm32
166     68/push  _test-Abc-kernel-string/imm32
167     # . . call
168     e8/call  kernel-string-equal?/disp32
169     # . . discard args
170     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
171     # check-ints-equal(eax, 1, msg)
172     # . . push args
173     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
174     68/push  1/imm32/true
175     50/push-eax
176     # . . call
177     e8/call  check-ints-equal/disp32
178     # . . discard args
179     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
180     c3/return
181 
182 test-compare-kernel-string-with-inequal-array:
183     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
184     # . . push args
185     68/push  "Adc"/imm32
186     68/push  _test-Abc-kernel-string/imm32
187     # . . call
188     e8/call  kernel-string-equal?/disp32
189     # . . discard args
190     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
191     # check-ints-equal(eax, 0, msg)
192     # . . push args
193     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
194     68/push  0/imm32/false
195     50/push-eax
196     # . . call
197     e8/call  check-ints-equal/disp32
198     # . . discard args
199     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
200     c3/return
201 
202 test-compare-kernel-string-with-empty-array:
203     # eax = kernel-string-equal?(_test-Abc-kernel-string, "")
204     # . . push args
205     68/push  ""/imm32
206     68/push  _test-Abc-kernel-string/imm32
207     # . . call
208     e8/call  kernel-string-equal?/disp32
209     # . . discard args
210     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
211     # check-ints-equal(eax, 0, msg)
212     # . . push args
213     68/push  "F - test-compare-kernel-string-with-equal-array"/imm32
214     68/push  0/imm32/false
215     50/push-eax
216     # . . call
217     e8/call  check-ints-equal/disp32
218     # . . discard args
219     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
220     c3/return
221 
222 test-compare-kernel-string-with-shorter-array:
223     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
224     # . . push args
225     68/push  "Ab"/imm32
226     68/push  _test-Abc-kernel-string/imm32
227     # . . call
228     e8/call  kernel-string-equal?/disp32
229     # . . discard args
230     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
231     # check-ints-equal(eax, 0, msg)
232     # . . push args
233     68/push  "F - test-compare-kernel-string-with-shorter-array"/imm32
234     68/push  0/imm32/false
235     50/push-eax
236     # . . call
237     e8/call  check-ints-equal/disp32
238     # . . discard args
239     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
240     c3/return
241 
242 test-compare-kernel-string-with-longer-array:
243     # eax = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
244     # . . push args
245     68/push  "Abcd"/imm32
246     68/push  _test-Abc-kernel-string/imm32
247     # . . call
248     e8/call  kernel-string-equal?/disp32
249     # . . discard args
250     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
251     # check-ints-equal(eax, 0, msg)
252     # . . push args
253     68/push  "F - test-compare-kernel-string-with-longer-array"/imm32
254     68/push  0/imm32/false
255     50/push-eax
256     # . . call
257     e8/call  check-ints-equal/disp32
258     # . . discard args
259     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
260     c3/return
261 
262 == data
263 
264 Null-kernel-string:  # (addr kernel-string)
265     00/null
266 
267 _test-Abc-kernel-string:  # (addr kernel-string)
268     41/A 62/b 63/c 00/null
269 
270 # . . vim:nowrap:textwidth=0