From ec73ed1230d75deb0f913a32617c9f1e0a5ca640 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 10 Jul 2020 23:44:10 -0700 Subject: 6631 --- html/118parse-hex.subx.html | 1002 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1002 insertions(+) create mode 100644 html/118parse-hex.subx.html (limited to 'html/118parse-hex.subx.html') diff --git a/html/118parse-hex.subx.html b/html/118parse-hex.subx.html new file mode 100644 index 00000000..96cf9f27 --- /dev/null +++ b/html/118parse-hex.subx.html @@ -0,0 +1,1002 @@ + + + + +Mu - 118parse-hex.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/118parse-hex.subx +
+  1 # some utilities for converting numbers from hex
+  2 # lowercase letters only for now
+  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 is-hex-int?:  # in: (addr slice) -> result/eax: boolean
+ 10     # . prologue
+ 11     55/push-ebp
+ 12     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 13     # . save registers
+ 14     51/push-ecx
+ 15     52/push-edx
+ 16     53/push-ebx
+ 17     # ecx = s
+ 18     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+ 19     # edx = s->end
+ 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>=  $is-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-!=  $is-hex-int?:initial-0/disp8
+ 33     # . ++curr
+ 34     41/increment-ecx
+ 35     # skip past leading '0x'
+ 36 $is-hex-int?:initial-0:
+ 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-!=  $is-hex-int?:loop/disp8
+ 42     # . ++curr
+ 43     41/increment-ecx
+ 44 $is-hex-int?:initial-0x:
+ 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>=  $is-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-!=  $is-hex-int?:loop/disp8
+ 53     # . ++curr
+ 54     41/increment-ecx
+ 55 $is-hex-int?:loop:
+ 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>=  $is-hex-int?:true/disp8
+ 59     # var eax: boolean = is-hex-digit?(*curr)
+ 60     # . . push args
+ 61     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+ 62     50/push-eax
+ 63     # . . call
+ 64     e8/call  is-hex-digit?/disp32
+ 65     # . . discard args
+ 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-=  $is-hex-int?:end/disp8
+ 70     # ++curr
+ 71     41/increment-ecx
+ 72     # loop
+ 73     eb/jump  $is-hex-int?:loop/disp8
+ 74 $is-hex-int?:true:
+ 75     # return true
+ 76     b8/copy-to-eax  1/imm32/true
+ 77 $is-hex-int?:end:
+ 78     # . restore registers
+ 79     5b/pop-to-ebx
+ 80     5a/pop-to-edx
+ 81     59/pop-to-ecx
+ 82     # . epilogue
+ 83     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 84     5d/pop-to-ebp
+ 85     c3/return
+ 86 
+ 87 test-is-hex-int:
+ 88     # . prologue
+ 89     55/push-ebp
+ 90     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 91     # (eax..ecx) = "34"
+ 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
+ 95     05/add-to-eax  4/imm32
+ 96     # var slice/ecx: slice = {eax, ecx}
+ 97     51/push-ecx
+ 98     50/push-eax
+ 99     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+100     # eax = is-hex-int?(slice)
+101     # . . push args
+102     51/push-ecx
+103     # . . call
+104     e8/call  is-hex-int?/disp32
+105     # . . discard args
+106     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+107     # check-ints-equal(eax, 1, msg)
+108     # . . push args
+109     68/push  "F - test-is-hex-int"/imm32
+110     68/push  1/imm32/true
+111     50/push-eax
+112     # . . call
+113     e8/call  check-ints-equal/disp32
+114     # . . discard args
+115     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+116     # . epilogue
+117     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+118     5d/pop-to-ebp
+119     c3/return
+120 
+121 test-is-hex-int-handles-letters:
+122     # . prologue
+123     55/push-ebp
+124     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+125     # (eax..ecx) = "34a"
+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}
+131     51/push-ecx
+132     50/push-eax
+133     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+134     # eax = is-hex-int?(slice)
+135     # . . push args
+136     51/push-ecx
+137     # . . call
+138     e8/call  is-hex-int?/disp32
+139     # . . discard args
+140     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+141     # check-ints-equal(eax, 1, msg)
+142     # . . push args
+143     68/push  "F - test-is-hex-int-handles-letters"/imm32
+144     68/push  1/imm32/true
+145     50/push-eax
+146     # . . call
+147     e8/call  check-ints-equal/disp32
+148     # . . discard args
+149     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+150     # . epilogue
+151     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+152     5d/pop-to-ebp
+153     c3/return
+154 
+155 test-is-hex-int-with-trailing-char:
+156     # . prologue
+157     55/push-ebp
+158     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+159     # (eax..ecx) = "34q"
+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}
+165     51/push-ecx
+166     50/push-eax
+167     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+168     # eax = is-hex-int?(slice)
+169     # . . push args
+170     51/push-ecx
+171     # . . call
+172     e8/call  is-hex-int?/disp32
+173     # . . discard args
+174     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+175     # check-ints-equal(eax, 0, msg)
+176     # . . push args
+177     68/push  "F - test-is-hex-int-with-trailing-char"/imm32
+178     68/push  0/imm32/false
+179     50/push-eax
+180     # . . call
+181     e8/call  check-ints-equal/disp32
+182     # . . discard args
+183     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+184     # . epilogue
+185     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+186     5d/pop-to-ebp
+187     c3/return
+188 
+189 test-is-hex-int-with-leading-char:
+190     # . prologue
+191     55/push-ebp
+192     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+193     # (eax..ecx) = "q34"
+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}
+199     51/push-ecx
+200     50/push-eax
+201     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+202     # eax = is-hex-int?(slice)
+203     # . . push args
+204     51/push-ecx
+205     # . . call
+206     e8/call  is-hex-int?/disp32
+207     # . . discard args
+208     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+209     # check-ints-equal(eax, 0, msg)
+210     # . . push args
+211     68/push  "F - test-is-hex-int-with-leading-char"/imm32
+212     68/push  0/imm32/false
+213     50/push-eax
+214     # . . call
+215     e8/call  check-ints-equal/disp32
+216     # . . discard args
+217     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+218     # . epilogue
+219     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+220     5d/pop-to-ebp
+221     c3/return
+222 
+223 test-is-hex-int-empty:
+224     # . prologue
+225     55/push-ebp
+226     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+227     # var slice/ecx: slice = ""
+228     68/push  0/imm32
+229     68/push  0/imm32
+230     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+231     # eax = is-hex-int?(slice)
+232     # . . push args
+233     51/push-ecx
+234     # . . call
+235     e8/call  is-hex-int?/disp32
+236     # . . discard args
+237     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+238     # check-ints-equal(eax, 0, msg)
+239     # . . push args
+240     68/push  "F - test-is-hex-int-empty"/imm32
+241     68/push  0/imm32/false
+242     50/push-eax
+243     # . . call
+244     e8/call  check-ints-equal/disp32
+245     # . . discard args
+246     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+247     # . epilogue
+248     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+249     5d/pop-to-ebp
+250     c3/return
+251 
+252 test-is-hex-int-handles-0x-prefix:
+253     # . prologue
+254     55/push-ebp
+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}
+262     51/push-ecx
+263     50/push-eax
+264     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+265     # eax = is-hex-int?(slice)
+266     # . . push args
+267     51/push-ecx
+268     # . . call
+269     e8/call  is-hex-int?/disp32
+270     # . . discard args
+271     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+272     # check-ints-equal(eax, 1, msg)
+273     # . . push args
+274     68/push  "F - test-is-hex-int-handles-0x-prefix"/imm32
+275     68/push  1/imm32/true
+276     50/push-eax
+277     # . . call
+278     e8/call  check-ints-equal/disp32
+279     # . . discard args
+280     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+281     # . epilogue
+282     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+283     5d/pop-to-ebp
+284     c3/return
+285 
+286 test-is-hex-int-handles-negative:
+287     # . prologue
+288     55/push-ebp
+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}
+296     51/push-ecx
+297     50/push-eax
+298     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+299     # eax = is-hex-int?(slice)
+300     # . . push args
+301     51/push-ecx
+302     # . . call
+303     e8/call  is-hex-int?/disp32
+304     # . . discard args
+305     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+306     # check-ints-equal(eax, 1, msg)
+307     # . . push args
+308     68/push  "F - test-is-hex-int-handles-negative"/imm32
+309     68/push  1/imm32/true
+310     50/push-eax
+311     # . . call
+312     e8/call  check-ints-equal/disp32
+313     # . . discard args
+314     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+315     # . epilogue
+316     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+317     5d/pop-to-ebp
+318     c3/return
+319 
+320 test-is-hex-int-handles-negative-0x-prefix:
+321     # . prologue
+322     55/push-ebp
+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}
+330     51/push-ecx
+331     50/push-eax
+332     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+333     # eax = is-hex-int?(slice)
+334     # . . push args
+335     51/push-ecx
+336     # . . call
+337     e8/call  is-hex-int?/disp32
+338     # . . discard args
+339     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+340     # check-ints-equal(eax, 1, msg)
+341     # . . push args
+342     68/push  "F - test-is-hex-int-handles-negative-0x-prefix"/imm32
+343     68/push  1/imm32/true
+344     50/push-eax
+345     # . . call
+346     e8/call  check-ints-equal/disp32
+347     # . . discard args
+348     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+349     # . epilogue
+350     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+351     5d/pop-to-ebp
+352     c3/return
+353 
+354 parse-hex-int:  # in: (addr array byte) -> result/eax: int
+355     # . prologue
+356     55/push-ebp
+357     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+358     # . save registers
+359     51/push-ecx
+360     52/push-edx
+361     # eax = in
+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]
+366     # . edx = 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)
+371     # . . push args
+372     52/push-edx
+373     51/push-ecx
+374     # . . call
+375     e8/call  parse-hex-int-helper/disp32
+376     # . . discard args
+377     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+378 $parse-hex-int:end:
+379     # . restore registers
+380     5a/pop-to-edx
+381     59/pop-to-ecx
+382     # . epilogue
+383     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+384     5d/pop-to-ebp
+385     c3/return
+386 
+387 parse-hex-int-from-slice:  # in: (addr slice) -> result/eax: int
+388     # . prologue
+389     55/push-ebp
+390     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+391     # . save registers
+392     51/push-ecx
+393     52/push-edx
+394     # ecx = in
+395     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+396     # edx = 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)
+401     # . . push args
+402     52/push-edx
+403     51/push-ecx
+404     # . . call
+405     e8/call  parse-hex-int-helper/disp32
+406     # . . discard args
+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
+410     5a/pop-to-edx
+411     59/pop-to-ecx
+412     # . epilogue
+413     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+414     5d/pop-to-ebp
+415     c3/return
+416 
+417 parse-hex-int-helper:  # start: (addr byte), end: (addr byte) -> result/eax: int
+418     # . prologue
+419     55/push-ebp
+420     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+421     # . save registers
+422     51/push-ecx
+423     52/push-edx
+424     53/push-ebx
+425     56/push-esi
+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
+428     # edx = max
+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
+440     # . ++curr
+441     41/increment-ecx
+442     # . negate = true
+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
+450     # . ++curr
+451     41/increment-ecx
+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
+461     # . ++curr
+462     41/increment-ecx
+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
+470     # . . call
+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
+475     # ++curr
+476     41/increment-ecx
+477     # loop
+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:
+485     # return result
+486     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy ebx to eax
+487     # . restore registers
+488     5e/pop-to-esi
+489     5b/pop-to-ebx
+490     5a/pop-to-edx
+491     59/pop-to-ecx
+492     # . epilogue
+493     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+494     5d/pop-to-ebp
+495     c3/return
+496 
+497 test-parse-hex-int-from-slice-single-digit:
+498     # . prologue
+499     55/push-ebp
+500     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+501     # (eax..ecx) = "a"
+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}
+507     51/push-ecx
+508     50/push-eax
+509     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+510     # eax = parse-hex-int-from-slice(slice)
+511     # . . push args
+512     51/push-ecx
+513     # . . call
+514     e8/call  parse-hex-int-from-slice/disp32
+515     # . . discard args
+516     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+517     # check-ints-equal(eax, 0xa, msg)
+518     # . . push args
+519     68/push  "F - test-parse-hex-int-from-slice-single-digit"/imm32
+520     68/push  0xa/imm32
+521     50/push-eax
+522     # . . call
+523     e8/call  check-ints-equal/disp32
+524     # . . discard args
+525     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+526     # . epilogue
+527     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+528     5d/pop-to-ebp
+529     c3/return
+530 
+531 test-parse-hex-int-from-slice-multi-digit:
+532     # . prologue
+533     55/push-ebp
+534     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+535     # (eax..ecx) = "34a"
+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}
+541     51/push-ecx
+542     50/push-eax
+543     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+544     # eax = parse-hex-int-from-slice(slice)
+545     # . . push args
+546     51/push-ecx
+547     # . . call
+548     e8/call  parse-hex-int-from-slice/disp32
+549     # . . discard args
+550     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+551     # check-ints-equal(eax, 0x34a, msg)
+552     # . . push args
+553     68/push  "F - test-parse-hex-int-from-slice-multi-digit"/imm32
+554     68/push  0x34a/imm32
+555     50/push-eax
+556     # . . call
+557     e8/call  check-ints-equal/disp32
+558     # . . discard args
+559     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+560     # . epilogue
+561     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+562     5d/pop-to-ebp
+563     c3/return
+564 
+565 test-parse-hex-int-from-slice-0x-prefix:
+566     # . prologue
+567     55/push-ebp
+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}
+575     51/push-ecx
+576     50/push-eax
+577     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+578     # eax = parse-hex-int-from-slice(slice)
+579     # . . push args
+580     51/push-ecx
+581     # . . call
+582     e8/call  parse-hex-int-from-slice/disp32
+583     # . . discard args
+584     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+585     # check-ints-equal(eax, 0x34a, msg)
+586     # . . push args
+587     68/push  "F - test-parse-hex-int-from-slice-0x-prefix"/imm32
+588     68/push  0x34/imm32
+589     50/push-eax
+590     # . . call
+591     e8/call  check-ints-equal/disp32
+592     # . . discard args
+593     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+594     # . epilogue
+595     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+596     5d/pop-to-ebp
+597     c3/return
+598 
+599 test-parse-hex-int-from-slice-zero:
+600     # . prologue
+601     55/push-ebp
+602     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+603     # (eax..ecx) = "0"
+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}
+609     51/push-ecx
+610     50/push-eax
+611     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+612     # eax = parse-hex-int-from-slice(slice)
+613     # . . push args
+614     51/push-ecx
+615     # . . call
+616     e8/call  parse-hex-int-from-slice/disp32
+617     # . . discard args
+618     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+619     # check-ints-equal(eax, 0x34a, msg)
+620     # . . push args
+621     68/push  "F - test-parse-hex-int-from-slice-zero"/imm32
+622     68/push  0/imm32
+623     50/push-eax
+624     # . . call
+625     e8/call  check-ints-equal/disp32
+626     # . . discard args
+627     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+628     # . epilogue
+629     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+630     5d/pop-to-ebp
+631     c3/return
+632 
+633 test-parse-hex-int-from-slice-0-prefix:
+634     # . prologue
+635     55/push-ebp
+636     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+637     # (eax..ecx) = "03"
+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}
+643     51/push-ecx
+644     50/push-eax
+645     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+646     # eax = parse-hex-int-from-slice(slice)
+647     # . . push args
+648     51/push-ecx
+649     # . . call
+650     e8/call  parse-hex-int-from-slice/disp32
+651     # . . discard args
+652     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+653     # check-ints-equal(eax, 0x3, msg)
+654     # . . push args
+655     68/push  "F - test-parse-hex-int-from-slice-0-prefix"/imm32
+656     68/push  0x3/imm32
+657     50/push-eax
+658     # . . call
+659     e8/call  check-ints-equal/disp32
+660     # . . discard args
+661     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+662     # . epilogue
+663     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+664     5d/pop-to-ebp
+665     c3/return
+666 
+667 test-parse-hex-int-from-slice-negative:
+668     # . prologue
+669     55/push-ebp
+670     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+671     # (eax..ecx) = "-03"
+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}
+677     51/push-ecx
+678     50/push-eax
+679     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+680     # eax = parse-hex-int-from-slice(slice)
+681     # . . push args
+682     51/push-ecx
+683     # . . call
+684     e8/call  parse-hex-int-from-slice/disp32
+685     # . . discard args
+686     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+687     # check-ints-equal(eax, -3, msg)
+688     # . . push args
+689     68/push  "F - test-parse-hex-int-from-slice-negative"/imm32
+690     68/push  -3/imm32
+691     50/push-eax
+692     # . . call
+693     e8/call  check-ints-equal/disp32
+694     # . . discard args
+695     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+696     # . epilogue
+697     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+698     5d/pop-to-ebp
+699     c3/return
+700 
+701 is-hex-digit?:  # c: byte -> result/eax: boolean
+702     # . prologue
+703     55/push-ebp
+704     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+705     # . save registers
+706     51/push-ecx
+707     # ecx = c
+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-<  $is-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-<=  $is-hex-digit?:true/disp8
+715     # drop case
+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->  $is-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->=  $is-hex-digit?:true/disp8
+723     # otherwise return false
+724 $is-hex-digit?:false:
+725     b8/copy-to-eax  0/imm32/false
+726     eb/jump $is-hex-digit?:end/disp8
+727 $is-hex-digit?:true:
+728     b8/copy-to-eax  1/imm32/true
+729 $is-hex-digit?:end:
+730     # . restore registers
+731     59/pop-to-ecx
+732     # . epilogue
+733     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+734     5d/pop-to-ebp
+735     c3/return
+736 
+737 test-hex-below-0:
+738     # eax = is-hex-digit?(0x2f)
+739     # . . push args
+740     68/push  0x2f/imm32
+741     # . . call
+742     e8/call  is-hex-digit?/disp32
+743     # . . discard args
+744     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+745     # check-ints-equal(eax, 0, msg)
+746     # . . push args
+747     68/push  "F - test-hex-below-0"/imm32
+748     68/push  0/imm32/false
+749     50/push-eax
+750     # . . call
+751     e8/call  check-ints-equal/disp32
+752     # . . discard args
+753     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+754     c3/return
+755 
+756 test-hex-0-to-9:
+757     # eax = is-hex-digit?(0x30)
+758     # . . push args
+759     68/push  0x30/imm32
+760     # . . call
+761     e8/call  is-hex-digit?/disp32
+762     # . . discard args
+763     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+764     # check-ints-equal(eax, 1, msg)
+765     # . . push args
+766     68/push  "F - test-hex-at-0"/imm32
+767     68/push  1/imm32/true
+768     50/push-eax
+769     # . . call
+770     e8/call  check-ints-equal/disp32
+771     # . . discard args
+772     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+773     # eax = is-hex-digit?(0x39)
+774     # . . push args
+775     68/push  0x39/imm32
+776     # . . call
+777     e8/call  is-hex-digit?/disp32
+778     # . . discard args
+779     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+780     # check-ints-equal(eax, 1, msg)
+781     # . . push args
+782     68/push  "F - test-hex-at-9"/imm32
+783     68/push  1/imm32/true
+784     50/push-eax
+785     # . . call
+786     e8/call  check-ints-equal/disp32
+787     # . . discard args
+788     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+789     c3/return
+790 
+791 test-hex-above-9-to-a:
+792     # eax = is-hex-digit?(0x3a)
+793     # . . push args
+794     68/push  0x3a/imm32
+795     # . . call
+796     e8/call  is-hex-digit?/disp32
+797     # . . discard args
+798     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+799     # check-ints-equal(eax, 0, msg)
+800     # . . push args
+801     68/push  "F - test-hex-above-9-to-a"/imm32
+802     68/push  0/imm32/false
+803     50/push-eax
+804     # . . call
+805     e8/call  check-ints-equal/disp32
+806     # . . discard args
+807     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+808     c3/return
+809 
+810 test-hex-a-to-f:
+811     # eax = is-hex-digit?(0x61)
+812     # . . push args
+813     68/push  0x61/imm32
+814     # . . call
+815     e8/call  is-hex-digit?/disp32
+816     # . . discard args
+817     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+818     # check-ints-equal(eax, 1, msg)
+819     # . . push args
+820     68/push  "F - test-hex-at-a"/imm32
+821     68/push  1/imm32/true
+822     50/push-eax
+823     # . . call
+824     e8/call  check-ints-equal/disp32
+825     # . . discard args
+826     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+827     # eax = is-hex-digit?(0x66)
+828     # . . push args
+829     68/push  0x66/imm32
+830     # . . call
+831     e8/call  is-hex-digit?/disp32
+832     # . . discard args
+833     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+834     # check-ints-equal(eax, 1, msg)
+835     # . . push args
+836     68/push  "F - test-hex-at-f"/imm32
+837     68/push  1/imm32/true
+838     50/push-eax
+839     # . . call
+840     e8/call  check-ints-equal/disp32
+841     # . . discard args
+842     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+843     c3/return
+844 
+845 test-hex-above-f:
+846     # eax = is-hex-digit?(0x67)
+847     # . . push args
+848     68/push  0x67/imm32
+849     # . . call
+850     e8/call  is-hex-digit?/disp32
+851     # . . discard args
+852     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+853     # check-ints-equal(eax, 0, msg)
+854     # . . push args
+855     68/push  "F - test-hex-above-f"/imm32
+856     68/push  0/imm32/false
+857     50/push-eax
+858     # . . call
+859     e8/call  check-ints-equal/disp32
+860     # . . discard args
+861     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+862     c3/return
+863 
+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:
+878     # return eax - '0'
+879     2d/subtract-from-eax  0x30/imm32/0
+880     c3/return
+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
+888     c3/return
+889 
+890 $from-hex-char:abort:
+891     # . _write(2/stderr, error)
+892     # . . push args
+893     68/push  "invalid hex char: "/imm32
+894     68/push  2/imm32/stderr
+895     # . . call
+896     e8/call  _write/disp32
+897     # . . discard args
+898     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+899     # . clear-stream($Stderr->buffer)
+900     # . . save eax
+901     50/push-eax
+902     # . . push args
+903     68/push  $Stderr->buffer/imm32
+904     # . . call
+905     e8/call  clear-stream/disp32
+906     # . . discard args
+907     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+908     # . . restore eax
+909     58/pop-to-eax
+910     # . write-int32-hex-buffered(Stderr, eax)
+911     # . . push args
+912     50/push-eax
+913     68/push  Stderr/imm32
+914     # . . call
+915     e8/call  write-int32-hex-buffered/disp32
+916     # . . discard args
+917     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+918     # . flush(Stderr)
+919     # . . push args
+920     68/push  Stderr/imm32
+921     # . . call
+922     e8/call  flush/disp32
+923     # . . discard args
+924     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+925     # . _write(2/stderr, "\n")
+926     # . . push args
+927     68/push  Newline/imm32
+928     68/push  2/imm32/stderr
+929     # . . call
+930     e8/call  _write/disp32
+931     # . . discard args
+932     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+933     # . syscall(exit, 1)
+934     bb/copy-to-ebx  1/imm32
+935     e8/call  syscall_exit/disp32
+936     # never gets here
+937 
+938 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0