https://github.com/akkartik/mu/blob/main/linux/132slurp.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 # read all bytes from 'f' and store them into 's'
      7 # abort if 's' is too small
      8 slurp:  # f: (addr buffered-file), s: (addr stream byte)
      9     # pseudocode:
     10     #   while true
     11     #     if (s->write >= s->size) abort
     12     #     if (f->read >= f->write) populate stream from file
     13     #     if (f->write == 0) break
     14     #     AL = f->data[f->read]
     15     #     s->data[s->write] = AL
     16     #     ++f->read
     17     #     ++s->write
     18     # . prologue
     19     55/push-ebp
     20     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
     21     # . save registers
     22     50/push-eax
     23     51/push-ecx
     24     52/push-edx
     25     56/push-esi
     26     57/push-edi
     27     # esi = f
     28     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
     29     # ecx = f->read
     30     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(esi+8) to ecx
     31     # edi = s
     32     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
     33     # edx = s->write
     34     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # copy *edi to edx
     35 $slurp:loop:
     36     # if (s->write >= s->size) abort
     37     3b/compare                      1/mod/*+disp8   7/rm32/edi    .           .             .           2/r32/edx   8/disp8         .                 # compare edx with *(edi+8)
     38     7d/jump-if->=  $slurp:abort/disp8
     39     # if (f->read >= f->write) populate stream from file
     40     3b/compare                      1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # compare ecx with *(esi+4)
     41     7c/jump-if-<  $slurp:from-stream/disp8
     42     # . clear-stream(stream = f+4)
     43     # . . push args
     44     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy esi+4 to eax
     45     50/push-eax
     46     # . . call
     47     e8/call  clear-stream/disp32
     48     # . . discard args
     49     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
     50     # . f->read must now be 0; update its cache at ecx
     51     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
     52     # . eax = read(f->fd, stream = f+4)
     53     # . . push args
     54     50/push-eax
     55     ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
     56     # . . call
     57     e8/call  read/disp32
     58     # . . discard args
     59     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
     60     # if (f->write == 0) break
     61     # since f->read was initially 0, eax is the same as f->write
     62     # . if (eax == 0) return true
     63     3d/compare-eax-and  0/imm32
     64     74/jump-if-=  $slurp:end/disp8
     65 $slurp:from-stream:
     66     # var c/eax: byte = f->data[f->read]
     67     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
     68     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0x10/disp8      .                 # copy byte at *(esi+ecx+16) to AL
     69     # s->data[s->write] = c
     70     88/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           0/r32/AL    0xc/disp8       .                 # copy AL to *(edi+edx+12)
     71     # ++f->read
     72     41/increment-ecx
     73     # ++s->write
     74     42/increment-edx
     75     eb/jump  $slurp:loop/disp8
     76 $slurp:end:
     77     # save f->read
     78     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   8/disp8         .                 # copy ecx to *(esi+8)
     79     # save s->write
     80     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # copy edx to *edi
     81     # . restore registers
     82     5f/pop-to-edi
     83     5e/pop-to-esi
     84     5a/pop-to-edx
     85     59/pop-to-ecx
     86     58/pop-to-eax
     87     # . epilogue
     88     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
     89     5d/pop-to-ebp
     90     c3/return
     91
     92 $slurp:abort:
     93     # . _write(2/stderr, error)
     94     # . . push args
     95     68/push  "slurp: destination too small\n"/imm32
     96     68/push  2/imm32/stderr
     97     # . . call
     98     e8/call  _write/disp32
     99     # . . discard args
    100     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    101     # . syscall(exit, 1)
    102     bb/copy-to-ebx  1/imm32
    103     e8/call  syscall_exit/disp32
    104     # never gets here
    105
    106 test-slurp:
    107     # setup
    108     # . clear-stream(_test-stream)
    109     # . . push args
    110     68/push  _test-stream/imm32
    111     # . . call
    112     e8/call  clear-stream/disp32
    113     # . . discard args
    114     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    115     # . clear-stream($_test-buffered-file->buffer)
    116     # . . push args
    117     68/push  $_test-buffered-file->buffer/imm32
    118     # . . call
    119     e8/call  clear-stream/disp32
    120     # . . discard args
    121     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    122     # . clear-stream(_test-tmp-stream)
    123     # . . push args
    124     68/push  _test-tmp-stream/imm32
    125     # . . call
    126     e8/call  clear-stream/disp32
    127     # . . discard args
    128     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    129     # write(_test-stream, "ab\ncd")
    130     # . . push args
    131     68/push  "ab\ncd"/imm32
    132     68/push  _test-stream/imm32
    133     # . . call
    134     e8/call  write/disp32
    135     # . . discard args
    136     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    137     # read a line from _test-stream (buffered by _test-buffered-file) into _test-tmp-stream
    138     # . eax = slurp(_test-buffered-file, _test-tmp-stream)
    139     # . . push args
    140     68/push  _test-tmp-stream/imm32
    141     68/push  _test-buffered-file/imm32
    142     # . . call
    143     e8/call  slurp/disp32
    144     # . . discard args
    145     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    146     # check-stream-equal(_test-tmp-stream, "ab\ncd", msg)
    147     # . . push args
    148     68/push  "F - test-slurp"/imm32
    149     68/push  "ab\ncd"/imm32
    150     68/push  _test-tmp-stream/imm32
    151     # . . call
    152     e8/call  check-stream-equal/disp32
    153     # . . discard args
    154     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    155     # end
    156     c3/return
    157
    158 # . . vim:nowrap:textwidth=0