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