https://github.com/akkartik/mu/blob/main/310copy-bytes.subx

      1 # Some helpers for copying non-overlapping regions of memory.
      2 # Really only intended to be called from code generated by mu.subx.
      3
      4 == code
      5
      6 copy-bytes:  # src: (addr byte), dest: (addr byte), size: int
      7     # pseudocode:
      8     #   curr-src/esi = src
      9     #   curr-dest/edi = dest
     10     #   i/ecx = 0
     11     #   while true
     12     #     if (i >= size) break
     13     #     *curr-dest = *curr-src
     14     #     ++curr-src
     15     #     ++curr-dest
     16     #     ++i
     17     #
     18     # . prologue
     19     55/push-ebp
     20     89/<- %ebp 4/r32/esp
     21     # . save registers
     22     50/push-eax
     23     51/push-ecx
     24     52/push-edx
     25     56/push-esi
     26     57/push-edi
     27     # curr-src/esi = src
     28     8b/-> *(ebp+8) 6/r32/esi
     29     # curr-dest/edi = dest
     30     8b/-> *(ebp+0xc) 7/r32/edi
     31     # var i/ecx: int = 0
     32     b9/copy-to-ecx 0/imm32
     33     # edx = size
     34     8b/-> *(ebp+0x10) 2/r32/edx
     35     {
     36       # if (i >= size) break
     37       39/compare %ecx 2/r32/edx
     38       7d/jump-if->=  break/disp8
     39       # *curr-dest = *curr-src
     40       8a/byte-> *esi 0/r32/AL
     41       88/byte<- *edi 0/r32/AL
     42       # update
     43       46/increment-esi
     44       47/increment-edi
     45       41/increment-ecx
     46       eb/jump loop/disp8
     47     }
     48 $copy-bytes:end:
     49     # . restore registers
     50     5f/pop-to-edi
     51     5e/pop-to-esi
     52     5a/pop-to-edx
     53     59/pop-to-ecx
     54     58/pop-to-eax
     55     # . epilogue
     56     89/<- %esp 5/r32/ebp
     57     5d/pop-to-ebp
     58     c3/return
     59
     60 stream-to-array:  # in: (addr stream _), out: (addr handle array _)
     61     # . prologue
     62     55/push-ebp
     63     89/<- %ebp 4/r32/esp
     64     # . save registers
     65     50/push-eax
     66     51/push-ecx
     67     52/push-edx
     68     56/push-esi
     69     # esi = s
     70     8b/-> *(ebp+8) 6/r32/esi
     71     # var len/ecx: int = s->write - s->read
     72     8b/-> *esi 1/r32/ecx
     73     2b/subtract *(esi+4) 1/r32/ecx
     74     # allocate
     75     (allocate-array Heap %ecx *(ebp+0xc))
     76     # var in/edx: (addr byte) = s->data + s->read
     77     8b/-> *(esi+4) 2/r32/edx
     78     8d/copy-address *(esi+edx+0xc) 2/r32/edx
     79     # var dest/eax: (addr byte) = data for out
     80     8b/-> *(ebp+0xc) 0/r32/eax
     81     (lookup *eax *(eax+4))  # => eax
     82     8d/copy-address *(eax+4) 0/r32/eax
     83     #
     84     (copy-bytes %edx %eax %ecx)
     85 $stream-to-array:end:
     86     # . restore registers
     87     5e/pop-to-esi
     88     5a/pop-to-edx
     89     59/pop-to-ecx
     90     58/pop-to-eax
     91     # . epilogue
     92     89/<- %esp 5/r32/ebp
     93     5d/pop-to-ebp
     94     c3/return
     95
     96 test-stream-to-array:
     97     # . prologue
     98     55/push-ebp
     99     89/<- %ebp 4/r32/esp
    100     # setup
    101     (clear-stream _test-input-stream)
    102     (write _test-input-stream "abc")
    103     # skip something
    104     (read-byte _test-input-stream)  # => eax
    105     # var out/ecx: (handle array byte)
    106     68/push 0/imm32
    107     68/push 0/imm32
    108     89/<- %ecx 4/r32/esp
    109     #
    110     (stream-to-array _test-input-stream %ecx)
    111     (lookup *ecx *(ecx+4))  # => eax
    112     (check-strings-equal %eax "bc")
    113     # . epilogue
    114     89/<- %esp 5/r32/ebp
    115     5d/pop-to-ebp
    116     c3/return
    117
    118 # like stream-to-array but ignore surrounding quotes
    119 # we might do other stuff here later
    120 unquote-stream-to-array:  # in: (addr stream _), out: (addr handle array _)
    121     # . prologue
    122     55/push-ebp
    123     89/<- %ebp 4/r32/esp
    124     # . save registers
    125     50/push-eax
    126     51/push-ecx
    127     52/push-edx
    128     56/push-esi
    129     # esi = s
    130     8b/-> *(ebp+8) 6/r32/esi
    131     # var len/ecx: int = s->write - s->read - 2
    132     8b/-> *esi 1/r32/ecx
    133     2b/subtract *(esi+4) 1/r32/ecx
    134     81 7/subop/compare %ecx 2/imm32
    135     7c/jump-if-< $unquote-stream-to-array:end/disp8
    136     81 5/subop/subtract %ecx 2/imm32
    137     # allocate
    138     (allocate-array Heap %ecx *(ebp+0xc))
    139     # var in/edx: (addr byte) = s->data + s->read + 1
    140     8b/-> *(esi+4) 2/r32/edx
    141     8d/copy-address *(esi+edx+0xd) 2/r32/edx  # Stream-data + 1
    142     # var dest/eax: (addr byte) = data for out
    143     8b/-> *(ebp+0xc) 0/r32/eax
    144     (lookup *eax *(eax+4))  # => eax
    145     8d/copy-address *(eax+4) 0/r32/eax
    146     #
    147     (copy-bytes %edx %eax %ecx)
    148 $unquote-stream-to-array:end:
    149     # . restore registers
    150     5e/pop-to-esi
    151     5a/pop-to-edx
    152     59/pop-to-ecx
    153     58/pop-to-eax
    154     # . epilogue
    155     89/<- %esp 5/r32/ebp
    156     5d/pop-to-ebp
    157     c3/return