https://github.com/akkartik/mu/blob/master/subx/apps/subx-common.subx

      1 # some common helpers shared by phases of the SubX converter
      2
      3 == code
      4 #   instruction                     effective address                                                   register    displacement    immediate
      5 # . op          subop               mod             rm32          base        index         scale       r32
      6 # . 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
      7
      8 # write an entire stream's contents to a buffered-file
      9 # ways to do this:
     10 #   - construct a 'maximal slice' and pass it to write-slice
     11 #   - flush the buffered-file and pass the stream directly to its fd (disabling buffering)
     12 # we'll go with the first way for now
     13 write-stream-data:  # f : (address buffered-file), s : (address stream) -> <void>
     14     # . prolog
     15     55/push-EBP
     16     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     17     # . save registers
     18     50/push-EAX
     19     51/push-ECX
     20     56/push-ESI
     21     # ESI = s
     22     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
     23     # var slice/ECX = {s->data, s->data + s->write}
     24     # . push s->data + s->write
     25     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
     26     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
     27     50/push-EAX
     28     # . push s->data
     29     8d/copy-address                 1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   0xc/disp8       .                 # copy ESI+12 to EAX
     30     50/push-EAX
     31     # . ECX = ESP
     32     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
     33     # write-slice(f, slice)
     34     # . . push args
     35     51/push-ECX
     36     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
     37     # . . call
     38     e8/call  write-slice/disp32
     39     # . . discard args
     40     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     41 $write-stream-data:end:
     42     # . restore locals
     43     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     44     # . restore registers
     45     5e/pop-to-ESI
     46     59/pop-to-ECX
     47     58/pop-to-EAX
     48     # . epilog
     49     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     50     5d/pop-to-EBP
     51     c3/return
     52
     53 test-write-stream-data:
     54     # . prolog
     55     55/push-EBP
     56     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     57     # setup
     58     # . clear-stream(_test-output-stream)
     59     # . . push args
     60     68/push  _test-output-stream/imm32
     61     # . . call
     62     e8/call  clear-stream/disp32
     63     # . . discard args
     64     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     65     # . clear-stream(_test-output-buffered-file+4)
     66     # . . push args
     67     b8/copy-to-EAX  _test-output-buffered-file/imm32
     68     05/add-to-EAX  4/imm32
     69     50/push-EAX
     70     # . . call
     71     e8/call  clear-stream/disp32
     72     # . . discard args
     73     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     74     # . clear-stream(_test-input-stream)
     75     # . . push args
     76     68/push  _test-input-stream/imm32
     77     # . . call
     78     e8/call  clear-stream/disp32
     79     # . . discard args
     80     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
     81     # initialize input
     82     # . write(_test-input-stream, "abcd")
     83     # . . push args
     84     68/push  "abcd"/imm32
     85     68/push  _test-input-stream/imm32
     86     # . . call
     87     e8/call  write/disp32
     88     # . . discard args
     89     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     90     # write-stream-data(_test-output-buffered-file, _test-input-stream)
     91     # . . push args
     92     68/push  _test-input-stream/imm32
     93     68/push  _test-output-buffered-file/imm32
     94     # . . call
     95     e8/call  write-stream-data/disp32
     96     # . . discard args
     97     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     98     # check that the write happened as expected
     99     # . flush(_test-output-buffered-file)
    100     # . . push args
    101     68/push  _test-output-buffered-file/imm32
    102     # . . call
    103     e8/call  flush/disp32
    104     # . . discard args
    105     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    106     # . check-stream-equal(_test-output-stream, "abcd", msg)
    107     # . . push args
    108     68/push  "F - test-write-stream-data"/imm32
    109     68/push  "abcd"/imm32
    110     68/push  _test-output-stream/imm32
    111     # . . call
    112     e8/call  check-stream-equal/disp32
    113     # . . discard args
    114     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    115     # . epilog
    116     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    117     5d/pop-to-EBP
    118     c3/return
    119
    120 == data
    121
    122 _test-input-stream:
    123     # current write index
    124     0/imm32
    125     # current read index
    126     0/imm32
    127     # length
    128     0x100/imm32  # 256 bytes
    129     # data (16 lines x 16 bytes/line)
    130     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    131     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    132     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    133     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    134     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    135     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    136     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    137     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    138     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    139     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    140     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    141     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    142     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    143     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    144     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    145     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    146
    147 # a test buffered file for _test-input-stream
    148 _test-input-buffered-file:
    149     # file descriptor or (address stream)
    150     _test-input-stream/imm32
    151     # current write index
    152     0/imm32
    153     # current read index
    154     0/imm32
    155     # length
    156     6/imm32
    157     # data
    158     00 00 00 00 00 00  # 6 bytes
    159
    160 _test-output-stream:
    161     # current write index
    162     0/imm32
    163     # current read index
    164     0/imm32
    165     # length
    166     0x100/imm32  # 256 bytes
    167     # data (16 lines x 16 bytes/line)
    168     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    169     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    170     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    171     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    172     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    173     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    174     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    175     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    176     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    177     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    178     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    179     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    180     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    181     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    182     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    183     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    184
    185 # a test buffered file for _test-output-stream
    186 _test-output-buffered-file:
    187     # file descriptor or (address stream)
    188     _test-output-stream/imm32
    189     # current write index
    190     0/imm32
    191     # current read index
    192     0/imm32
    193     # length
    194     6/imm32
    195     # data
    196     00 00 00 00 00 00  # 6 bytes
    197
    198 # . . vim:nowrap:textwidth=0