1 # some utilities for converting numbers from hex
2 # lowercase letters only for now
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
9 hex-int?: # in: (addr slice) -> result/eax: boolean
12 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
18 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
20 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx
21 # var curr/ecx: (addr byte) = s->start
22 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx
23 # if s is empty return false
24 b8/copy-to-eax 0/imm32/false
25 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
26 73/jump-if-addr>= $hex-int?:end/disp8
27 # skip past leading '-'
28 # . if (*curr == '-') ++curr
29 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
30 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
31 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x2d/imm32/- # compare ebx
32 75/jump-if-!= $hex-int?:initial-0/disp8
35 # skip past leading '0x'
37 # . if (*curr != '0') jump to loop
38 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
39 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
40 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x30/imm32/0 # compare ebx
41 75/jump-if-!= $hex-int?:loop/disp8
45 # . if (curr >= in->end) return true
46 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
47 73/jump-if-addr>= $hex-int?:true/disp8
48 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
49 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
50 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
51 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x78/imm32/x # compare ebx
52 75/jump-if-!= $hex-int?:loop/disp8
56 # if (curr >= in->end) return true
57 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
58 73/jump-if-addr>= $hex-int?:true/disp8
59 # var eax: boolean = hex-digit?(*curr)
61 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
64 e8/call hex-digit?/disp32
66 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
67 # if (eax == false) return false
68 3d/compare-eax-and 0/imm32/false
69 74/jump-if-= $hex-int?:end/disp8
73 eb/jump $hex-int?:loop/disp8
76 b8/copy-to-eax 1/imm32/true
83 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
90 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
92 b8/copy-to-eax "34"/imm32
93 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
94 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
96 # var slice/ecx: slice = {eax, ecx}
99 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
100 # eax = hex-int?(slice)
104 e8/call hex-int?/disp32
106 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
107 # check-ints-equal(eax, 1, msg)
109 68/push "F - test-hex-int"/imm32
113 e8/call check-ints-equal/disp32
115 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
117 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
121 test-hex-int-handles-letters:
124 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
126 b8/copy-to-eax "34a"/imm32
127 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
128 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
129 05/add-to-eax 4/imm32
130 # var slice/ecx: slice = {eax, ecx}
133 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
134 # eax = hex-int?(slice)
138 e8/call hex-int?/disp32
140 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
141 # check-ints-equal(eax, 1, msg)
143 68/push "F - test-hex-int-handles-letters"/imm32
147 e8/call check-ints-equal/disp32
149 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
151 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
155 test-hex-int-with-trailing-char:
158 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
160 b8/copy-to-eax "34q"/imm32
161 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
162 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
163 05/add-to-eax 4/imm32
164 # var slice/ecx: slice = {eax, ecx}
167 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
168 # eax = hex-int?(slice)
172 e8/call hex-int?/disp32
174 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
175 # check-ints-equal(eax, 0, msg)
177 68/push "F - test-hex-int-with-trailing-char"/imm32
178 68/push 0/imm32/false
181 e8/call check-ints-equal/disp32
183 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
185 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
189 test-hex-int-with-leading-char:
192 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
194 b8/copy-to-eax "q34"/imm32
195 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
196 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
197 05/add-to-eax 4/imm32
198 # var slice/ecx: slice = {eax, ecx}
201 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
202 # eax = hex-int?(slice)
206 e8/call hex-int?/disp32
208 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
209 # check-ints-equal(eax, 0, msg)
211 68/push "F - test-hex-int-with-leading-char"/imm32
212 68/push 0/imm32/false
215 e8/call check-ints-equal/disp32
217 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
219 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
226 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
227 # var slice/ecx: slice = ""
230 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
231 # eax = hex-int?(slice)
235 e8/call hex-int?/disp32
237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
238 # check-ints-equal(eax, 0, msg)
240 68/push "F - test-hex-int-empty"/imm32
241 68/push 0/imm32/false
244 e8/call check-ints-equal/disp32
246 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
248 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
252 test-hex-int-handles-0x-prefix:
255 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
256 # (eax..ecx) = "0x3a"
257 b8/copy-to-eax "0x3a"/imm32
258 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
259 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
260 05/add-to-eax 4/imm32
261 # var slice/ecx: slice = {eax, ecx}
264 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
265 # eax = hex-int?(slice)
269 e8/call hex-int?/disp32
271 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
272 # check-ints-equal(eax, 1, msg)
274 68/push "F - test-hex-int-handles-0x-prefix"/imm32
278 e8/call check-ints-equal/disp32
280 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
282 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
286 test-hex-int-handles-negative:
289 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
290 # (eax..ecx) = "-34a"
291 b8/copy-to-eax "-34a"/imm32
292 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
293 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
294 05/add-to-eax 4/imm32
295 # var slice/ecx: slice = {eax, ecx}
298 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
299 # eax = hex-int?(slice)
303 e8/call hex-int?/disp32
305 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
306 # check-ints-equal(eax, 1, msg)
308 68/push "F - test-hex-int-handles-negative"/imm32
312 e8/call check-ints-equal/disp32
314 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
316 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
320 test-hex-int-handles-negative-0x-prefix:
323 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
324 # (eax..ecx) = "-0x3a"
325 b8/copy-to-eax "-0x3a"/imm32
326 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
327 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
328 05/add-to-eax 4/imm32
329 # var slice/ecx: slice = {eax, ecx}
332 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
333 # eax = hex-int?(slice)
337 e8/call hex-int?/disp32
339 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
340 # check-ints-equal(eax, 1, msg)
342 68/push "F - test-hex-int-handles-negative-0x-prefix"/imm32
346 e8/call check-ints-equal/disp32
348 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
350 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
354 parse-hex-int: # in: (addr array byte) -> result/eax: int
357 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
362 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
363 # var curr/ecx: (addr byte) = &in->data
364 8d/copy-address 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy eax+4 to ecx
365 # var max/edx: (addr byte) = &in->data[in->size]
367 8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx
368 # . edx = in->data + in->size
369 8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx
370 # return parse-hex-int-helper(curr, max)
375 e8/call parse-hex-int-helper/disp32
377 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
379 # . restore registers
383 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
387 parse-hex-int-from-slice: # in: (addr slice) -> result/eax: int
390 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
395 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
396 # var max/edx: (addr byte) = in->end
397 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx
398 # var curr/ecx: (addr byte) = in->start
399 8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx
400 # return parse-hex-int-helper(curr, max)
405 e8/call parse-hex-int-helper/disp32
407 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
408 $parse-hex-int-from-slice:end:
409 # . restore registers
413 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
417 parse-hex-int-helper: # start: (addr byte), end: (addr byte) -> result/eax: int
420 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
426 # var curr/ecx: (addr byte) = start
427 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
429 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
430 # var result/ebx: int = 0
431 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
432 # var negate?/esi: boolean = false
433 31/xor 3/mod/direct 6/rm32/esi . . . 6/r32/esi . . # clear esi
434 $parse-hex-int-helper:negative:
435 # if (*curr == '-') ++curr, negate = true
436 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
437 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
438 3d/compare-eax-and 0x2d/imm32/-
439 75/jump-if-!= $parse-hex-int-helper:initial-0/disp8
443 be/copy-to-esi 1/imm32/true
444 $parse-hex-int-helper:initial-0:
445 # skip past leading '0x'
446 # . if (*curr != '0') jump to loop
447 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
448 3d/compare-eax-and 0x30/imm32/0
449 75/jump-if-!= $parse-hex-int-helper:loop/disp8
452 $parse-hex-int-helper:initial-0x:
453 # . if (curr >= in->end) return result
454 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
455 73/jump-if-addr>= $parse-hex-int-helper:end/disp8
456 # . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
457 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
458 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
459 3d/compare-eax-and 0x78/imm32/x
460 75/jump-if-!= $parse-hex-int-helper:loop/disp8
463 $parse-hex-int-helper:loop:
464 # if (curr >= in->end) break
465 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
466 73/jump-if-addr>= $parse-hex-int-helper:negate/disp8
467 # var eax: int = from-hex-char(*curr)
468 # . . copy arg to eax
469 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
471 e8/call from-hex-char/disp32
472 # result = result * 16 + eax
473 c1/shift 4/subop/left 3/mod/direct 3/rm32/ebx . . . . . 4/imm8 # shift ebx left by 4 bits
474 01/add 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # add eax to ebx
478 eb/jump $parse-hex-int-helper:loop/disp8
479 $parse-hex-int-helper:negate:
480 # if (negate?) result = -result
481 81 7/subop/compare 3/mod/direct 6/rm32/esi . . . . . 0/imm32/false # compare esi
482 74/jump-if-= $parse-hex-int-helper:end/disp8
483 f7 3/subop/negate 3/mod/direct 3/rm32/ebx . . . . . . # negate ebx
484 $parse-hex-int-helper:end:
486 89/copy 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # copy ebx to eax
487 # . restore registers
493 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
497 test-parse-hex-int-from-slice-single-digit:
500 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
502 b8/copy-to-eax "a"/imm32
503 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
504 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
505 05/add-to-eax 4/imm32
506 # var slice/ecx: slice = {eax, ecx}
509 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
510 # eax = parse-hex-int-from-slice(slice)
514 e8/call parse-hex-int-from-slice/disp32
516 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
517 # check-ints-equal(eax, 0xa, msg)
519 68/push "F - test-parse-hex-int-from-slice-single-digit"/imm32
523 e8/call check-ints-equal/disp32
525 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
527 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
531 test-parse-hex-int-from-slice-multi-digit:
534 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
536 b8/copy-to-eax "34a"/imm32
537 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
538 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
539 05/add-to-eax 4/imm32
540 # var slice/ecx: slice = {eax, ecx}
543 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
544 # eax = parse-hex-int-from-slice(slice)
548 e8/call parse-hex-int-from-slice/disp32
550 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
551 # check-ints-equal(eax, 0x34a, msg)
553 68/push "F - test-parse-hex-int-from-slice-multi-digit"/imm32
557 e8/call check-ints-equal/disp32
559 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
561 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
565 test-parse-hex-int-from-slice-0x-prefix:
568 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
569 # (eax..ecx) = "0x34"
570 b8/copy-to-eax "0x34"/imm32
571 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
572 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
573 05/add-to-eax 4/imm32
574 # var slice/ecx: slice = {eax, ecx}
577 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
578 # eax = parse-hex-int-from-slice(slice)
582 e8/call parse-hex-int-from-slice/disp32
584 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
585 # check-ints-equal(eax, 0x34, msg)
587 68/push "F - test-parse-hex-int-from-slice-0x-prefix"/imm32
591 e8/call check-ints-equal/disp32
593 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
595 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
599 test-parse-hex-int-from-slice-zero:
602 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
604 b8/copy-to-eax "0"/imm32
605 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
606 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
607 05/add-to-eax 4/imm32
608 # var slice/ecx: slice = {eax, ecx}
611 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
612 # eax = parse-hex-int-from-slice(slice)
616 e8/call parse-hex-int-from-slice/disp32
618 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
619 # check-ints-equal(eax, 0, msg)
621 68/push "F - test-parse-hex-int-from-slice-zero"/imm32
625 e8/call check-ints-equal/disp32
627 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
629 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
633 test-parse-hex-int-from-slice-0-prefix:
636 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
638 b8/copy-to-eax "03"/imm32
639 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
640 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
641 05/add-to-eax 4/imm32
642 # var slice/ecx: slice = {eax, ecx}
645 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
646 # eax = parse-hex-int-from-slice(slice)
650 e8/call parse-hex-int-from-slice/disp32
652 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
653 # check-ints-equal(eax, 0x3, msg)
655 68/push "F - test-parse-hex-int-from-slice-0-prefix"/imm32
659 e8/call check-ints-equal/disp32
661 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
663 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
667 test-parse-hex-int-from-slice-negative:
670 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
672 b8/copy-to-eax "-03"/imm32
673 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
674 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
675 05/add-to-eax 4/imm32
676 # var slice/ecx: slice = {eax, ecx}
679 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
680 # eax = parse-hex-int-from-slice(slice)
684 e8/call parse-hex-int-from-slice/disp32
686 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
687 # check-ints-equal(eax, -3, msg)
689 68/push "F - test-parse-hex-int-from-slice-negative"/imm32
693 e8/call check-ints-equal/disp32
695 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
697 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
701 hex-digit?: # c: byte -> result/eax: boolean
704 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
708 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
709 # return false if c < '0'
710 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x30/imm32 # compare ecx
711 7c/jump-if-< $hex-digit?:false/disp8
712 # return true if c <= '9'
713 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x39/imm32 # compare ecx
714 7e/jump-if-<= $hex-digit?:true/disp8
716 25/and-eax-with 0x5f/imm32
717 # return false if c > 'f'
718 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x66/imm32 # compare ecx
719 7f/jump-if-> $hex-digit?:false/disp8
720 # return true if c >= 'a'
721 81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x61/imm32 # compare ecx
722 7d/jump-if->= $hex-digit?:true/disp8
723 # otherwise return false
725 b8/copy-to-eax 0/imm32/false
726 eb/jump $hex-digit?:end/disp8
728 b8/copy-to-eax 1/imm32/true
730 # . restore registers
733 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
738 # eax = hex-digit?(0x2f)
742 e8/call hex-digit?/disp32
744 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
745 # check-ints-equal(eax, 0, msg)
747 68/push "F - test-hex-below-0"/imm32
748 68/push 0/imm32/false
751 e8/call check-ints-equal/disp32
753 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
757 # eax = hex-digit?(0x30)
761 e8/call hex-digit?/disp32
763 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
764 # check-ints-equal(eax, 1, msg)
766 68/push "F - test-hex-at-0"/imm32
770 e8/call check-ints-equal/disp32
772 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
773 # eax = hex-digit?(0x39)
777 e8/call hex-digit?/disp32
779 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
780 # check-ints-equal(eax, 1, msg)
782 68/push "F - test-hex-at-9"/imm32
786 e8/call check-ints-equal/disp32
788 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
791 test-hex-above-9-to-a:
792 # eax = hex-digit?(0x3a)
796 e8/call hex-digit?/disp32
798 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
799 # check-ints-equal(eax, 0, msg)
801 68/push "F - test-hex-above-9-to-a"/imm32
802 68/push 0/imm32/false
805 e8/call check-ints-equal/disp32
807 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
811 # eax = hex-digit?(0x61)
815 e8/call hex-digit?/disp32
817 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
818 # check-ints-equal(eax, 1, msg)
820 68/push "F - test-hex-at-a"/imm32
824 e8/call check-ints-equal/disp32
826 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
827 # eax = hex-digit?(0x66)
831 e8/call hex-digit?/disp32
833 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
834 # check-ints-equal(eax, 1, msg)
836 68/push "F - test-hex-at-f"/imm32
840 e8/call check-ints-equal/disp32
842 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
846 # eax = hex-digit?(0x67)
850 e8/call hex-digit?/disp32
852 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
853 # check-ints-equal(eax, 0, msg)
855 68/push "F - test-hex-above-f"/imm32
856 68/push 0/imm32/false
859 e8/call check-ints-equal/disp32
861 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
864 from-hex-char: # in/eax: byte -> out/eax: nibble
865 $from-hex-char:check0:
866 # if (eax < '0') goto abort
867 3d/compare-eax-with 0x30/imm32/0
868 7c/jump-if-< $from-hex-char:abort/disp8
869 $from-hex-char:check1:
870 # if (eax > 'f') goto abort
871 3d/compare-eax-with 0x66/imm32/f
872 7f/jump-if-> $from-hex-char:abort/disp8
873 $from-hex-char:check2:
874 # if (eax > '9') goto next check
875 3d/compare-eax-with 0x39/imm32/9
876 7f/jump-if-> $from-hex-char:check3/disp8
877 $from-hex-char:digit:
879 2d/subtract-from-eax 0x30/imm32/0
881 $from-hex-char:check3:
882 # if (eax < 'a') goto abort
883 3d/compare-eax-with 0x61/imm32/a
884 7c/jump-if-< $from-hex-char:abort/disp8
885 $from-hex-char:letter:
886 # return eax - ('a'-10)
887 2d/subtract-from-eax 0x57/imm32/a-10
890 $from-hex-char:abort:
891 (abort "invalid hex char")
894 # . . vim:nowrap:textwidth=0