https://github.com/akkartik/mu/blob/main/baremetal/108write.subx
  1 == code
  2 #   instruction                     effective address                                                   register    displacement    immediate
  3 # . op          subop               mod             rm32          base        index         scale       r32
  4 # . 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
  5 
  6 write:  # f: (addr stream byte), s: (addr array byte)
  7     # . prologue
  8     55/push-ebp
  9     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 10     # if (s == 0) return
 11     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       0/imm32           # compare *(ebp+12)
 12     74/jump-if-=  $write:end/disp8
 13     # TODO: write to file
 14     # otherwise, treat 'f' as a stream to append to
 15     # . save registers
 16     50/push-eax
 17     51/push-ecx
 18     52/push-edx
 19     53/push-ebx
 20     # ecx = f
 21     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
 22     # edx = f->write
 23     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # copy *ecx to edx
 24     # ebx = f->size
 25     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           3/r32/ebx   8/disp8         .                 # copy *(ecx+8) to ebx
 26     # eax = _append-3(&f->data[f->write], &f->data[f->size], s)
 27     # . . push s
 28     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
 29     # . . push &f->data[f->size]
 30     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ecx  3/index/ebx   .           3/r32/ebx   0xc/disp8       .                 # copy ecx+ebx+12 to ebx
 31     53/push-ebx
 32     # . . push &f->data[f->write]
 33     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ecx  2/index/edx   .           3/r32/ebx   0xc/disp8       .                 # copy ecx+edx+12 to ebx
 34     53/push-ebx
 35     # . . call
 36     e8/call  _append-3/disp32
 37     # . . discard args
 38     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
 39     # f->write += eax
 40     01/add                          0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # add eax to *ecx
 41     # . restore registers
 42     5b/pop-to-ebx
 43     5a/pop-to-edx
 44     59/pop-to-ecx
 45     58/pop-to-eax
 46 $write:end:
 47     # . epilogue
 48     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 49     5d/pop-to-ebp
 50     c3/return
 51 
 52 # TODO: bring in tests once we have check-ints-equal
 53 
 54 # 3-argument variant of _append
 55 _append-3:  # out: (addr byte), outend: (addr byte), s: (addr array byte) -> num_bytes_appended/eax
 56     # . prologue
 57     55/push-ebp
 58     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 59     # . save registers
 60     51/push-ecx
 61     # eax = _append-4(out, outend, &s->data[0], &s->data[s->size])
 62     # . . push &s->data[s->size]
 63     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         0/r32/eax   0x10/disp8      .                 # copy *(ebp+16) to eax
 64     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
 65     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
 66     51/push-ecx
 67     # . . push &s->data[0]
 68     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           1/r32/ecx   4/disp8         .                 # copy eax+4 to ecx
 69     51/push-ecx
 70     # . . push outend
 71     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
 72     # . . push out
 73     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
 74     # . . call
 75     e8/call  _append-4/disp32
 76     # . . discard args
 77     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
 78 $_append-3:end:
 79     # . restore registers
 80     59/pop-to-ecx
 81     # . epilogue
 82     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 83     5d/pop-to-ebp
 84     c3/return
 85 
 86 # 4-argument variant of _append
 87 _append-4:  # out: (addr byte), outend: (addr byte), in: (addr byte), inend: (addr byte) -> num_bytes_appended/eax: int
 88     # . prologue
 89     55/push-ebp
 90     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 91     # . save registers
 92     51/push-ecx
 93     52/push-edx
 94     53/push-ebx
 95     56/push-esi
 96     57/push-edi
 97     # num_bytes_appended = 0
 98     b8/copy-to-eax  0/imm32
 99     # edi = out
100     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
101     # edx = outend
102     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
103     # esi = in
104     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0x10/disp8      .                 # copy *(ebp+16) to esi
105     # ecx = inend
106     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0x14/disp8      .                 # copy *(ebp+20) to ecx
107 $_append-4:loop:
108     # if (in >= inend) break
109     39/compare                      3/mod/direct    6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare esi with ecx
110     73/jump-if-addr>=  $_append-4:end/disp8
111     # if (out >= outend) abort  # just to catch test failures fast
112     39/compare                      3/mod/direct    7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edi with edx
113     73/jump-if-addr>=  $_append-4:end/disp8  # TODO: abort
114     # *out = *in
115     8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           3/r32/BL    .               .                 # copy byte at *esi to BL
116     88/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           3/r32/BL    .               .                 # copy byte at BL to *edi
117     # ++num_bytes_appended
118     40/increment-eax
119     # ++in
120     46/increment-esi
121     # ++out
122     47/increment-edi
123     eb/jump  $_append-4:loop/disp8
124 $_append-4:end:
125     # . restore registers
126     5f/pop-to-edi
127     5e/pop-to-esi
128     5b/pop-to-ebx
129     5a/pop-to-edx
130     59/pop-to-ecx
131     # . epilogue
132     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
133     5d/pop-to-ebp
134     c3/return
135 
136 # . . vim:nowrap:textwidth=0