https://github.com/akkartik/mu/blob/main/linux/125write-stream-data.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 an entire stream's contents to a buffered-file
      7 # ways to do this:
      8 #   - construct a 'maximal slice' and pass it to write-slice-buffered
      9 #   - flush the buffered-file and pass the stream directly to its fd (disabling buffering)
     10 # we'll go with the first way for now
     11 write-stream-data:  # f: (addr buffered-file), s: (addr stream byte)
     12     # . prologue
     13     55/push-ebp
     14     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     15     # . save registers
     16     50/push-eax
     17     51/push-ecx
     18     56/push-esi
     19     # esi = s
     20     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
     21     # var slice/ecx: slice = {s->data, &s->data[s->write]}
     22     # . push &s->data[s->write]
     23     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
     24     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
     25     50/push-eax
     26     # . push s->data
     27     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   0xc/disp8       .                 # copy esi+12 to eax
     28     50/push-eax
     29     # . ecx = esp
     30     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
     31     # write-slice-buffered(f, slice)
     32     # . . push args
     33     51/push-ecx
     34     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
     35     # . . call
     36     e8/call  write-slice-buffered/disp32
     37     # . . discard args
     38     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     39 $write-stream-data:end:
     40     # . restore locals
     41     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     42     # . restore registers
     43     5e/pop-to-esi
     44     59/pop-to-ecx
     45     58/pop-to-eax
     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 test-write-stream-data:
     52     # . prologue
     53     55/push-ebp
     54     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     55     # setup
     56     # . clear-stream(_test-output-stream)
     57     # . . push args
     58     68/push  _test-output-stream/imm32
     59     # . . call
     60     e8/call  clear-stream/disp32
     61     # . . discard args
     62     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     63     # . clear-stream($_test-output-buffered-file->buffer)
     64     # . . push args
     65     68/push  $_test-output-buffered-file->buffer/imm32
     66     # . . call
     67     e8/call  clear-stream/disp32
     68     # . . discard args
     69     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     70     # . clear-stream(_test-input-stream)
     71     # . . push args
     72     68/push  _test-input-stream/imm32
     73     # . . call
     74     e8/call  clear-stream/disp32
     75     # . . discard args
     76     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     77     # initialize input
     78     # . write(_test-input-stream, "abcd")
     79     # . . push args
     80     68/push  "abcd"/imm32
     81     68/push  _test-input-stream/imm32
     82     # . . call
     83     e8/call  write/disp32
     84     # . . discard args
     85     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     86     # write-stream-data(_test-output-buffered-file, _test-input-stream)
     87     # . . push args
     88     68/push  _test-input-stream/imm32
     89     68/push  _test-output-buffered-file/imm32
     90     # . . call
     91     e8/call  write-stream-data/disp32
     92     # . . discard args
     93     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     94     # check that the write happened as expected
     95     # . flush(_test-output-buffered-file)
     96     # . . push args
     97     68/push  _test-output-buffered-file/imm32
     98     # . . call
     99     e8/call  flush/disp32
    100     # . . discard args
    101     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    102     # . check-stream-equal(_test-output-stream, "abcd", msg)
    103     # . . push args
    104     68/push  "F - test-write-stream-data"/imm32
    105     68/push  "abcd"/imm32
    106     68/push  _test-output-stream/imm32
    107     # . . call
    108     e8/call  check-stream-equal/disp32
    109     # . . discard args
    110     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    111     # . epilogue
    112     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    113     5d/pop-to-ebp
    114     c3/return