https://github.com/akkartik/mu/blob/main/123slice.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 slice-empty?:  # s: (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     # ecx = s
  16     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
  17     # if (s->start >= s->end) return true
  18     # . eax = s->start
  19     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
  20     # . if (eax >= s->end) return true
  21     3b/compare                      1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # compare eax with *(ecx+4)
  22     b8/copy-to-eax  1/imm32/true
  23     73/jump-if-addr>=  $slice-empty?:end/disp8
  24     b8/copy-to-eax  0/imm32/false
  25 $slice-empty?:end:
  26     # . restore registers
  27     59/pop-to-ecx
  28     # . epilogue
  29     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
  30     5d/pop-to-ebp
  31     c3/return
  32 
  33 test-slice-empty-true:
  34     # . prologue
  35     55/push-ebp
  36     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
  37     # var slice/ecx: slice = {34, 34}
  38     68/push  34/imm32/end
  39     68/push  34/imm32/start
  40     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
  41     # slice-empty?(slice)
  42     # . . push args
  43     51/push-ecx
  44     # . . call
  45     e8/call  slice-empty?/disp32
  46     # . . discard args
  47     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
  48     # check-ints-equal(eax, 1, msg)
  49     # . . push args
  50     68/push  "F - test-slice-empty-true"/imm32
  51     68/push  1/imm32
  52     50/push-eax
  53     # . . call
  54     e8/call  check-ints-equal/disp32
  55     # . . discard args
  56     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
  57     # . epilogue
  58     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
  59     5d/pop-to-ebp
  60     c3/return
  61 
  62 test-slice-empty-false:
  63     # . prologue
  64     55/push-ebp
  65     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
  66     # var slice/ecx: slice = {32, 34}
  67     68/push  34/imm32/end
  68     68/push  32/imm32/start
  69     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
  70     # slice-empty?(slice)
  71     # . . push args
  72     51/push-ecx
  73     # . . call
  74     e8/call  slice-empty?/disp32
  75     # . . discard args
  76     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
  77     # check-ints-equal(eax, 0, msg)
  78     # . . push args
  79     68/push  "F - test-slice-empty-false"/imm32
  80     68/push  0/imm32
  81     50/push-eax
  82     # . . call
  83     e8/call  check-ints-equal/disp32
  84     # . . discard args
  85     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
  86     # . epilogue
  87     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
  88     5d/pop-to-ebp
  89     c3/return
  90 
  91 test-slice-empty-if-start-greater-than-end:
  92     # . prologue
  93     55/push-ebp
  94     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
  95     # var slice/ecx: slice = {34, 32}
  96     68/push  32/imm32/end
  97     68/push  34/imm32/start
  98     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
  99     # slice-empty?(slice)
 100     # . . push args
 101     51/push-ecx
 102     # . . call
 103     e8/call  slice-empty?/disp32
 104     # . . discard args
 105     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 106     # check-ints-equal(eax, 1, msg)
 107     # . . push args
 108     68/push  "F - test-slice-empty-if-start-greater-than-end"/imm32
 109     68/push  1/imm32
 110     50/push-eax
 111     # . . call
 112     e8/call  check-ints-equal/disp32
 113     # . . discard args
 114     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 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 slice-equal?:  # s: (addr slice), p: (addr array byte) -> result/eax: boolean
 121     # pseudocode:
 122     #   if (p == 0) return (s == 0)
 123     #   currs = s->start
 124     #   maxs = s->end
 125     #   if (maxs - currs != p->size) return false
 126     #   currp = p->data
 127     #   while currs < maxs
 128     #     if (*currs != *currp) return false
 129     #     ++currs
 130     #     ++currp
 131     #   return true
 132     #
 133     # registers:
 134     #   currs: edx
 135     #   maxs: esi
 136     #   currp: ebx
 137     #   *currs: eax
 138     #   *currp: ecx
 139     #
 140     # . prologue
 141     55/push-ebp
 142     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 143     # . save registers
 144     51/push-ecx
 145     52/push-edx
 146     53/push-ebx
 147     56/push-esi
 148     # esi = s
 149     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
 150     # var currs/edx: (addr byte) = s->start
 151     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
 152     # var maxs/esi: (addr byte) = s->end
 153     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           6/r32/esi   4/disp8         .                 # copy *(esi+4) to esi
 154     # var ssize/eax: int = maxs - currs
 155     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           6/r32/esi   .               .                 # copy esi to eax
 156     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # subtract edx from eax
 157     # ebx = p
 158     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
 159     # if (p != 0) goto next check
 160     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0/imm32           # compare ebx
 161     75/jump-if-!=  $slice-equal?:nonnull-string/disp8
 162 $slice-equal?:null-string:
 163     # return s->start == s->end
 164     3d/compare-eax-and  0/imm32
 165     74/jump-if-=  $slice-equal?:true/disp8
 166     eb/jump  $slice-equal?:false/disp8
 167 $slice-equal?:nonnull-string:
 168     # if (ssize != p->size) return false
 169     39/compare                      0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # compare *ebx and eax
 170     75/jump-if-!=  $slice-equal?:false/disp8
 171     # var currp/ebx: (addr byte) = p->data
 172     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
 173     # var c1/eax: byte = 0
 174     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
 175     # var c2/ecx: byte = 0
 176     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
 177 $slice-equal?:loop:
 178     # if (currs >= maxs) return true
 179     39/compare                      3/mod/direct    2/rm32/edx    .           .             .           6/r32/esi   .               .                 # compare edx with esi
 180     73/jump-if-addr>=  $slice-equal?:true/disp8
 181     # c1 = *currp
 182     8a/copy-byte                    0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/AL    .               .                 # copy byte at *ebx to AL
 183     # c2 = *currs
 184     8a/copy-byte                    0/mod/indirect  2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
 185     # if (c1 != c2) return false
 186     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax and ecx
 187     75/jump-if-!=  $slice-equal?:false/disp8
 188     # ++currp
 189     43/increment-ebx
 190     # ++currs
 191     42/increment-edx
 192     eb/jump $slice-equal?:loop/disp8
 193 $slice-equal?:false:
 194     b8/copy-to-eax  0/imm32
 195     eb/jump  $slice-equal?:end/disp8
 196 $slice-equal?:true:
 197     b8/copy-to-eax  1/imm32
 198 $slice-equal?:end:
 199     # . restore registers
 200     5e/pop-to-esi
 201     5b/pop-to-ebx
 202     5a/pop-to-edx
 203     59/pop-to-ecx
 204     # . epilogue
 205     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 206     5d/pop-to-ebp
 207     c3/return
 208 
 209 test-slice-equal:
 210     # - slice-equal?(slice("Abc"), "Abc") == 1
 211     # . prologue
 212     55/push-ebp
 213     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 214     # (eax..ecx) = "Abc"
 215     b8/copy-to-eax  "Abc"/imm32
 216     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 217     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
 218     05/add-to-eax  4/imm32
 219     # var slice/ecx: slice = {eax, ecx}
 220     51/push-ecx
 221     50/push-eax
 222     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
 223     # eax = slice-equal?(ecx, "Abc")
 224     # . . push args
 225     68/push  "Abc"/imm32
 226     51/push-ecx
 227     # . . call
 228     e8/call  slice-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, 1, msg)
 232     # . . push args
 233     68/push  "F - test-slice-equal"/imm32
 234     68/push  1/imm32
 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     # . epilogue
 241     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 242     5d/pop-to-ebp
 243     c3/return
 244 
 245 test-slice-equal-false:
 246     # - slice-equal?(slice("bcd"), "Abc") == 0
 247     # . prologue
 248     55/push-ebp
 249     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 250     # (eax..ecx) = "bcd"
 251     b8/copy-to-eax  "bcd"/imm32
 252     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 253     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
 254     05/add-to-eax  4/imm32
 255     # var slice/ecx: slice = {eax, ecx}
 256     51/push-ecx
 257     50/push-eax
 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  "Abc"/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-false"/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     # . epilogue
 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-too-long:
 282     # - slice-equal?(slice("Abcd"), "Abc") == 0
 283     # . prologue
 284     55/push-ebp
 285     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 286     # (eax..ecx) = "Abcd"
 287     b8/copy-to-eax  "Abcd"/imm32
 288     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 289     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
 290     05/add-to-eax  4/imm32
 291     # var slice/ecx: slice = {eax, ecx}
 292     51/push-ecx
 293     50/push-eax
 294     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
 295     # eax = slice-equal?(ecx, "Abc")
 296     # . . push args
 297     68/push  "Abc"/imm32
 298     51/push-ecx
 299     # . . call
 300     e8/call  slice-equal?/disp32
 301     # . . discard args
 302     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 303     # check-ints-equal(eax, 0, msg)
 304     # . . push args
 305     68/push  "F - test-slice-equal-too-long"/imm32
 306     68/push  0/imm32
 307     50/push-eax
 308     # . . call
 309     e8/call  check-ints-equal/disp32
 310     # . . discard args
 311     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 312     # . epilogue
 313     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 314     5d/pop-to-ebp
 315     c3/return
 316 
 317 test-slice-equal-too-short:
 318     # - slice-equal?(slice("A"), "Abc") == 0
 319     # . prologue
 320     55/push-ebp
 321     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 322     # (eax..ecx) = "A"
 323     b8/copy-to-eax  "A"/imm32
 324     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 325     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
 326     05/add-to-eax  4/imm32
 327     # var slice/ecx: slice = {eax, ecx}
 328     51/push-ecx
 329     50/push-eax
 330     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
 331     # eax = slice-equal?(ecx, "Abc")
 332     # . . push args
 333     68/push  "Abc"/imm32
 334     51/push-ecx
 335     # . . call
 336     e8/call  slice-equal?/disp32
 337     # . . discard args
 338     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 339     # check-ints-equal(eax, 0, msg)
 340     # . . push args
 341     68/push  "F - test-slice-equal-too-short"/imm32
 342     68/push  0/imm32
 343     50/push-eax
 344     # . . call
 345     e8/call  check-ints-equal/disp32
 346     # . . discard args
 347     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 348     # . epilogue
 349     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 350     5d/pop-to-ebp
 351     c3/return
 352 
 353 test-slice-equal-empty:
 354     # - slice-equal?(slice(""), "Abc") == 0
 355     # . prologue
 356     55/push-ebp
 357     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 358     # var slice/ecx: slice
 359     68/push  0/imm32/end
 360     68/push  0/imm32/start
 361     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
 362     # eax = slice-equal?(ecx, "Abc")
 363     # . . push args
 364     68/push  "Abc"/imm32
 365     51/push-ecx
 366     # . . call
 367     e8/call  slice-equal?/disp32
 368     # . . discard args
 369     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 370     # check-ints-equal(eax, 0, msg)
 371     # . . push args
 372     68/push  "F - test-slice-equal-empty"/imm32
 373     68/push  0/imm32
 374     50/push-eax
 375     # . . call
 376     e8/call  check-ints-equal/disp32
 377     # . . discard args
 378     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 379     # . epilogue
 380     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 381     5d/pop-to-ebp
 382     c3/return
 383 
 384 "Normal"> . </span>           <span class="Normal"> . </span>          4/r32/esp  <span class="Normal"> . </span>             <span class="Normal"> . </span>                <span class="subxComment"># copy esp to ebp</span>
<span id="L17" class="LineNr"> 17 </span>    <span class="subxS1Comment"># . save registers</span>
<span id="L18" class="LineNr"> 18 </span>    51/push-ecx
<span id="L19" class="LineNr"> 19 </span>    56/push-esi
<span id="L20" class="LineNr"> 20 </span>    <span class="subxComment"># esi = s</span>
<span id="L21" class="LineNr"> 21 </span>    8b/copy                         1/mod/*+disp8   5/rm32/ebp   <span class="Normal"> . </span>         <span class="Normal"> . </span>           <span class="Normal"> . </span>          6/r32/esi   8/disp8        <span class="Normal"> . </span>                <span class="subxComment"># copy *(ebp+8) to esi</span>
<span id="L22" class="LineNr"> 22 </span>    <span class="subxComment"># ecx = s-&gt;read</span>
<span id="L23" class="LineNr"> 23 </span>    8b/copy                         1/mod/*+disp8   6/rm32/esi   <span class="Normal"> . </span>         <span class="Normal"> . </span>           <span class="Normal"> . </span>          1/r32/ecx   4/disp8        <span class="Normal"> . </span>                <span class="subxComment"># copy *(esi+4) to ecx</span>
<span id="L24" class="LineNr"> 24 </span>    <span class="subxComment"># if (f-&gt;read &gt;= f-&gt;write) abort</span>
<span id="L25" class="LineNr"> 25 </span>    3b/compare                      0/mod/indirect  6/rm32/esi   <span class="Normal"> . </span>         <span class="Normal"> . </span>           <span class="Normal"> . </span>          1/r32/ecx  <span class="Normal"> . </span>             <span class="Normal"> . </span>                <span class="subxComment"># compare ecx with *esi</span>
<span id="L26" class="LineNr"> 26 </span>    0f 8d/jump-if-&gt;=  $read-byte:<a href='501draw-text.mu.html#L481'>abort</a>/disp32
<span id="L27" class="LineNr"> 27 </span>    <span class="subxComment"># result = f-&gt;data[f-&gt;read]</span>
<span id="L28" class="LineNr"> 28 </span>    31/xor                          3/mod/direct    0/rm32/eax   <span class="Normal"> . </span>         <span class="Normal"> . </span>           <span class="Normal"> . </span>          0/r32/eax  <span class="Normal"> . </span>             <span class="Normal"> . </span>                <span class="subxComment"># clear eax</span>
<span id="L29" class="LineNr"> 29 </span>    8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx  <span class="Normal"> . </span>          0/r32/AL    0xc/disp8      <span class="Normal"> . </span>                <span class="subxComment"># copy byte at *(esi+ecx+12) to AL</span>
<span id="L30" class="LineNr"> 30 </span>    <span class="subxComment"># ++f-&gt;read</span>
<span id="L31" class="LineNr"> 31 </span>    ff          0/subop/increment   1/mod/*+disp8   6/rm32/esi   <span class="Normal"> . </span>         <span class="Normal"> . </span>           <span class="Normal"> . </span>         <span class="Normal"> . </span>          4/disp8        <span class="Normal"> . </span>                <span class="subxComment"># increment *(esi+4)</span>
<span id="L32" class="LineNr"> 32 </span><span class="Constant">$read-byte:end</span>:
<span id="L33" class="LineNr"> 33 </span>    <span class="subxS1Comment"># . restore registers</span>
<span id="L34" class="LineNr"> 34 </span>    5e/pop-to-esi
<span id="L35" class="LineNr"> 35 </span>    59/pop-to-ecx
<span id="L36" class="LineNr"> 36 </span>    <span class="subxS1Comment"># . epilogue</span>
<span id="L37" class="LineNr"> 37 </span>    89/copy                         3/mod/direct    4/rm32/esp   <span class="Normal"> . </span>         <span class="Normal"> . </span>           <span class="Normal"> . </span>          5/r32/ebp  <span class="Normal"> . </span>             <span class="Normal"> . </span>                <span class="subxComment"># copy ebp to esp</span>
<span id="L38" class="LineNr"> 38 </span>    5d/pop-to-ebp
<span id="L39" class="LineNr"> 39 </span>    c3/return
<span id="L40" class="LineNr"> 40 </span>
<span id="L41" class="LineNr"> 41 </span><span class="Constant">$read-byte:<a href='501draw-text.mu.html#L481'>abort</a></span>:
<span id="L42" class="LineNr"> 42 </span>    (<a href='501draw-text.mu.html#L258'>draw-text-wrapping-right-then-down-from-cursor-over-full-screen</a> 0 <span class="Constant">&quot;read-byte: empty stream&quot;</span> 3 0)  <span class="subxComment"># 3=cyan</span>
<span id="L43" class="LineNr"> 43 </span>    {
<span id="L44" class="LineNr"> 44 </span>      eb/jump <span class="Constant">loop</span>/disp8
<span id="L45" class="LineNr"> 45 </span>    }
<span id="L46" class="LineNr"> 46 </span>    <span class="subxComment"># never gets here</span>
<span id="L47" class="LineNr"> 47 </span>
<span id="L48" class="LineNr"> 48 </span>== data
<span id="L49" class="LineNr"> 49 </span>
<span id="L50" class="LineNr"> 50 </span><span class="subxMinorFunction">_test-input-stream</span>:  <span class="subxComment"># (stream byte)</span>
<span id="L51" class="LineNr"> 51 </span>    <span class="subxComment"># current write index</span>
<span id="L52" class="LineNr"> 52 </span>    0/imm32
<span id="L53" class="LineNr"> 53 </span>    <span class="subxComment"># current read index</span>
<span id="L54" class="LineNr"> 54 </span>    0/imm32
<span id="L55" class="LineNr"> 55 </span>    <span class="subxComment"># size</span>
<span id="L56" class="LineNr"> 56 </span>    0x400/imm32  <span class="subxComment"># 1024 bytes</span>
<span id="L57" class="LineNr"> 57 </span>    <span class="subxComment"># data (64 lines x 16 bytes/line)</span>
<span id="L58" class="LineNr"> 58 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L59" class="LineNr"> 59 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L60" class="LineNr"> 60 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L61" class="LineNr"> 61 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L62" class="LineNr"> 62 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L63" class="LineNr"> 63 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L64" class="LineNr"> 64 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L65" class="LineNr"> 65 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L66" class="LineNr"> 66 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L67" class="LineNr"> 67 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L68" class="LineNr"> 68 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L69" class="LineNr"> 69 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L70" class="LineNr"> 70 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L71" class="LineNr"> 71 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L72" class="LineNr"> 72 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L73" class="LineNr"> 73 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L74" class="LineNr"> 74 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L75" class="LineNr"> 75 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L76" class="LineNr"> 76 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L77" class="LineNr"> 77 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L78" class="LineNr"> 78 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L79" class="LineNr"> 79 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L80" class="LineNr"> 80 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L81" class="LineNr"> 81 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L82" class="LineNr"> 82 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L83" class="LineNr"> 83 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L84" class="LineNr"> 84 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L85" class="LineNr"> 85 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L86" class="LineNr"> 86 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L87" class="LineNr"> 87 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L88" class="LineNr"> 88 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L89" class="LineNr"> 89 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L90" class="LineNr"> 90 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L91" class="LineNr"> 91 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L92" class="LineNr"> 92 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L93" class="LineNr"> 93 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L94" class="LineNr"> 94 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L95" class="LineNr"> 95 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L96" class="LineNr"> 96 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L97" class="LineNr"> 97 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L98" class="LineNr"> 98 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L99" class="LineNr"> 99 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L100" class="LineNr">100 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L101" class="LineNr">101 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L102" class="LineNr">102 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L103" class="LineNr">103 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L104" class="LineNr">104 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L105" class="LineNr">105 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L106" class="LineNr">106 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L107" class="LineNr">107 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L108" class="LineNr">108 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L109" class="LineNr">109 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L110" class="LineNr">110 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L111" class="LineNr">111 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L112" class="LineNr">112 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L113" class="LineNr">113 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L114" class="LineNr">114 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L115" class="LineNr">115 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L116" class="LineNr">116 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L117" class="LineNr">117 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L118" class="LineNr">118 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L119" class="LineNr">119 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L120" class="LineNr">120 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L121" class="LineNr">121 </span>    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
<span id="L122" class="LineNr">122 </span>
<span id="L123" class="LineNr">123 </span><span class="subxS2Comment"># . . vim&#0058;nowrap:textwidth=0</span>
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
n class="subxComment"># var curr/ecx: (addr byte) = s->start 807 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx 808 # var max/esi: (addr byte) = s->end 809 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi 810 # edi = out 811 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi 812 # edx = out->size 813 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # copy *(edi+8) to edx 814 # ebx = out->write 815 8b/copy 0/mod/indirect 7/rm32/edi . . . 3/r32/ebx . . # copy *edi to ebx 816 $write-slice:loop: 817 # if (curr >= max) break 818 39/compare 3/mod/direct 1/rm32/ecx . . . 6/r32/esi . . # compare ecx with esi 819 73/jump-if-addr>= $write-slice:loop-end/disp8 820 # if (out->write >= out->size) abort 821 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx with edx 822 7d/jump-if->= $write-slice:abort/disp8 823 # out->data[out->write] = *in 824 # . AL = *in 825 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 826 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL 827 # . out->data[out->write] = AL 828 88/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 3/index/ebx . 0/r32/AL 0xc/disp8 . # copy AL to *(edi+ebx+12) 829 # ++out->write 830 43/increment-ebx 831 # ++in 832 41/increment-ecx 833 eb/jump $write-slice:loop/disp8 834 $write-slice:loop-end: 835 # persist out->write 836 89/copy 0/mod/indirect 7/rm32/edi . . . 3/r32/ebx . . # copy ebx to *edi 837 $write-slice:end: 838 # . restore registers 839 5f/pop-to-edi 840 5e/pop-to-esi 841 5b/pop-to-ebx 842 5a/pop-to-edx 843 59/pop-to-ecx 844 58/pop-to-eax 845 # . epilogue 846 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 847 5d/pop-to-ebp 848 c3/return 849 850 $write-slice:abort: 851 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "write-slice: out of space" 3 0) # 3=cyan 852 { 853 eb/jump loop/disp8 854 } 855 # never gets here 856 857 test-write-slice: 858 # . prologue 859 55/push-ebp 860 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 861 # setup 862 # . clear-stream(_test-stream) 863 # . . push args 864 68/push _test-stream/imm32 865 # . . call 866 e8/call clear-stream/disp32 867 # . . discard args 868 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 869 # (eax..ecx) = "Abc" 870 b8/copy-to-eax "Abc"/imm32 871 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 872 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 873 05/add-to-eax 4/imm32 874 # var slice/ecx: slice = {eax, ecx} 875 51/push-ecx 876 50/push-eax 877 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 878 # write-slice(_test-stream, slice) 879 # . . push args 880 51/push-ecx 881 68/push _test-stream/imm32 882 # . . call 883 e8/call write-slice/disp32 884 # . . discard args 885 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 886 # check-stream-equal(_test-stream, "Abc", msg) 887 # . . push args 888 68/push "F - test-write-slice"/imm32 889 68/push "Abc"/imm32 890 68/push _test-stream/imm32 891 # . . call 892 e8/call check-stream-equal/disp32 893 # . . discard args 894 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 895 # . epilogue 896 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 897 5d/pop-to-ebp 898 c3/return 899 900 # copy a slice into a new (dynamically allocated) string 901 slice-to-string: # ad: (addr allocation-descriptor), in: (addr slice), out: (addr handle array byte) 902 # . prologue 903 55/push-ebp 904 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 905 # . save registers 906 50/push-eax 907 51/push-ecx 908 52/push-edx 909 53/push-ebx 910 56/push-esi 911 # esi = in 912 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi 913 # var curr/edx: (addr byte) = in->start 914 8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx 915 # var max/ebx: (addr byte) = in->end 916 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 3/r32/ebx 4/disp8 . # copy *(esi+4) to ebx 917 # var size/ecx: int = max - curr + 4 # total size of output string (including the initial 'size' field) 918 89/copy 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # copy ebx to ecx 919 29/subtract 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # subtract edx from ecx 920 81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx 921 # allocate(ad, size, out) 922 # . . push args 923 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16) 924 51/push-ecx 925 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8) 926 # . . call 927 e8/call allocate/disp32 928 # . . discard args 929 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 930 # eax = out->payload 931 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0x10/disp8 . # copy *(ebp+16) to eax 932 8b/copy 1/mod/*+disp8 0/rm32/eax . . . 0/r32/eax 4/disp8 . # copy *(eax+4) to eax 933 # skip payload->allocid 934 05/add-to-eax 4/imm32 935 # if (eax == 0) abort 936 3d/compare-eax-and 0/imm32 937 74/jump-if-= $slice-to-string:abort/disp8 938 # out->size = size-4 939 89/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to *eax 940 81 5/subop/subtract 0/mod/indirect 0/rm32/eax . . . . . 4/imm32 # subtract 4 from *eax 941 # save out 942 50/push-eax 943 $slice-to-string:initialize: 944 # eax = _append-4(eax+4, eax+size, curr, max) # clobbering ecx 945 # . . push args 946 53/push-ebx 947 52/push-edx 948 # . . push eax+size (clobbering ecx) 949 01/add 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # add eax to ecx 950 51/push-ecx 951 # . . push eax+4 (clobbering eax) 952 81 0/subop/add 3/mod/direct 0/rm32/eax . . . . . 4/imm32 # add to eax 953 50/push-eax 954 # . . call 955 e8/call _append-4/disp32 956 # . . discard args 957 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp 958 # restore out (assumes _append-4 can't error) 959 58/pop-to-eax 960 $slice-to-string:end: 961 # . restore registers 962 5e/pop-to-esi 963 5b/pop-to-ebx 964 5a/pop-to-edx 965 59/pop-to-ecx 966 58/pop-to-eax 967 # . epilogue 968 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 969 5d/pop-to-ebp 970 c3/return 971 972 $slice-to-string:abort: 973 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "slice-to-string: out of space\n" 3 0) # 3=cyan 974 { 975 eb/jump loop/disp8 976 } 977 # never gets here 978 979 test-slice-to-string: 980 # . prologue 981 55/push-ebp 982 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 983 # var ad/edx: allocation-descriptor containing 16 bytes 984 # . var end/ecx: (addr byte) 985 89/<- %ecx 4/r32/esp 986 81 5/subop/subtract %esp 0x10/imm32 987 # . var start/edx: (addr byte) = end - 0x10 988 89/<- %edx 4/r32/esp 989 # . ad = {start, end} 990 51/push-ecx 991 52/push-edx 992 89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx 993 # (eax..ecx) = "Abc" 994 b8/copy-to-eax "Abc"/imm32 995 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx 996 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 997 05/add-to-eax 4/imm32 998 # var slice/ecx: slice = {eax, ecx} 999 51/push-ecx 1000 50/push-eax 1001 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 1002 # var h/ebx: (handle array byte) 1003 68/push 0/imm32 1004 68/push 0/imm32 1005 89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx 1006 # slice-to-string(ad, slice, h) 1007 # . . push args 1008 53/push-ebx 1009 51/push-ecx 1010 52/push-edx 1011 # . . call 1012 e8/call slice-to-string/disp32 1013 # . . discard args 1014 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1015 # eax = h->payload 1016 8b/copy 1/mod/*+disp8 3/rm32/ebx . . . 0/r32/eax 4/disp8 . # copy *(ebx+4) to eax 1017 # skip payload->allocid 1018 05/add-to-eax 4/imm32 1019 +-- 26 lines: #? # dump eax --------------------------------------------------------------------------------------------------------------------------------------------------------- 1045 # eax = string-equal?(eax, "Abc") 1046 # . . push args 1047 68/push "Abc"/imm32 1048 50/push-eax 1049 # . . call 1050 e8/call string-equal?/disp32 1051 # . . discard args 1052 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 1053 # check-ints-equal(eax, 1, msg) 1054 # . . push args 1055 68/push "F - test-slice-to-string"/imm32 1056 68/push 1/imm32/true 1057 50/push-eax 1058 # . . call 1059 e8/call check-ints-equal/disp32 1060 # . . discard args 1061 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 1062 # . reclaim locals 1063 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x18/imm32 # add to esp 1064 # . epilogue 1065 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 1066 5d/pop-to-ebp 1067 c3/return 1068 1069 # . . vim:nowrap:textwidth=0