https://github.com/akkartik/mu/blob/main/linux/306files.subx

      1 # Methods for constructing buffered-file objects.
      2 #
      3 # HACK: buffered-file stores naked addrs. This is safe because buffered-file
      4 # objects are opaque. But still sub-optimal; they'll be harder to reclaim when
      5 # we get around to that.
      6
      7 == code
      8
      9 open:  # filename: (addr array byte), write?: boolean, out: (addr handle buffered-file)
     10     # . prologue
     11     55/push-ebp
     12     89/<- %ebp 4/r32/esp
     13     # . save registers
     14     50/push-eax
     15     51/push-ecx
     16     # var new-fd/ecx: fd
     17     (open-fd *(ebp+8) *(ebp+0xc))  # => eax
     18     89/<- %ecx 0/r32/eax
     19     # if fd < 0 return
     20     3d/compare-eax-with 0/imm32
     21     7c/jump-if-< $open:end/disp8
     22     # allocate a buffered-file
     23     (allocate Heap 0x1010 *(ebp+0x10))  # file-buffer-size + 16 for other fields
     24     # var out-addr/eax: (addr buffered-file)
     25     8b/-> *(ebp+0x10) 0/r32/eax
     26     (lookup *eax *(eax+4))  # => eax
     27     # out-addr->size = 4KB
     28     c7 0/subop/copy *(eax+0xc) 0x1000/imm32/file-buffer-size  # Stream-size + 4 for fd
     29     # out-addr->fd = fd
     30     89/<- *eax 1/r32/ecx
     31 $open:end:
     32     # . restore registers
     33     59/pop-to-ecx
     34     58/pop-to-eax
     35     # . epilogue
     36     89/<- %esp 5/r32/ebp
     37     5d/pop-to-ebp
     38     c3/return
     39
     40 open-fd:  # filename: (addr array byte), write?: boolean -> result/eax: fd
     41     # . prologue
     42     55/push-ebp
     43     89/<- %ebp 4/r32/esp
     44     # . save registers
     45     51/push-ecx
     46     52/push-edx
     47     53/push-ebx
     48     56/push-esi
     49     # ecx = filename
     50     8b/-> *(ebp+8) 1/r32/ecx
     51     # var size/edx: int = filename->length + 1 for the trailing null character
     52     8b/-> *ecx 2/r32/edx
     53     42/increment-edx
     54     # var s/esi: (stream size)
     55     29/subtract-from %esp 2/r32/edx
     56     52/push-edx  # size
     57     68/push 0/imm32/read
     58     68/push 0/imm32/write
     59     89/<- %esi 4/r32/esp
     60     # copy filename and a final null character
     61     (clear-stream %esi)
     62     (write %esi %ecx)
     63     # spill edx
     64     52/push-edx
     65     # var fd/eax: fd = open(filename)
     66     8d/copy-address *(esi+0xc) 3/r32/ebx
     67     8b/-> *(ebp+0xc) 1/r32/ecx/flags
     68     ba/copy-to-edx 0x180/imm32/permissions
     69     e8/call syscall_open/disp32
     70     # restore edx
     71     5a/pop-to-edx
     72 $open-fd:end:
     73     # . reclaim locals
     74     01/add-to %esp 2/r32/edx
     75     81 0/subop/add %esp 0xc/imm32
     76     # . restore registers
     77     5e/pop-to-esi
     78     5b/pop-to-ebx
     79     5a/pop-to-edx
     80     59/pop-to-ecx
     81     # . epilogue
     82     89/<- %esp 5/r32/ebp
     83     5d/pop-to-ebp
     84     c3/return
     85
     86 populate-buffered-file-containing:  # contents: (addr array byte), out: (addr handle buffered-file)
     87     # . prologue
     88     55/push-ebp
     89     89/<- %ebp 4/r32/esp
     90     # . save registers
     91     50/push-eax
     92     51/push-ecx
     93     56/push-esi
     94     57/push-edi
     95     # esi = contents
     96     8b/-> *(ebp+8) 6/r32/esi
     97     # var n/ecx: int = len(contents)
     98     8b/-> *esi 1/r32/ecx
     99     # var stream/edi: (handle stream byte)
    100     68/push 0/imm32
    101     68/push 0/imm32
    102     89/<- %edi 4/r32/esp
    103     # allocate stream
    104     (new-stream Heap %ecx 1 %edi)
    105     # var stream-addr/edi: (addr stream byte) = lookup(stream)
    106     (lookup *edi *(edi+4))  # => eax
    107     89/<- %edi 0/r32/eax
    108     # write contents to stream
    109     (write %edi %esi)
    110     # allocate buffered-file
    111     (allocate Heap 0x110 *(ebp+0xc))
    112     # var out-addr/eax: (addr buffered-file)
    113     8b/-> *(ebp+0xc) 0/r32/eax
    114     (lookup *eax *(eax+4))  # => eax
    115     # out-addr->size = 256 bytes
    116     c7 0/subop/copy *(eax+0xc) 0x100/imm32/file-buffer-size
    117     # out-addr->fd = stream
    118     89/<- *eax 7/r32/edi
    119 $populate-buffered-file-containing:end:
    120     # . reclaim locals
    121     81 0/subop/add %esp 8/imm32
    122     # . restore registers
    123     5f/pop-to-edi
    124     5e/pop-to-esi
    125     59/pop-to-ecx
    126     58/pop-to-eax
    127     # . epilogue
    128     89/<- %esp 5/r32/ebp
    129     5d/pop-to-ebp
    130     c3/return
    131
    132 # TODO: hard-coded parameter
    133 new-buffered-file:  # out: (addr handle buffered-file)
    134     # . prologue
    135     55/push-ebp
    136     89/<- %ebp 4/r32/esp
    137     # . save registers
    138     50/push-eax
    139     51/push-ecx
    140     # var stream/ecx: (handle stream byte)
    141     68/push 0/imm32
    142     68/push 0/imm32
    143     89/<- %ecx 4/r32/esp
    144     # allocate stream
    145     (new-stream Heap 0x100 1 %ecx)
    146     # var stream-addr/ecx: (addr stream byte) = lookup(stream)
    147     (lookup *ecx *(ecx+4))  # => eax
    148     89/<- %ecx 0/r32/eax
    149     # allocate buffered-file
    150     (allocate Heap 0x110 *(ebp+8))
    151     # var out-addr/eax: (addr buffered-file)
    152     8b/-> *(ebp+8) 0/r32/eax
    153     (lookup *eax *(eax+4))  # => eax
    154     # out-addr->size = 256 bytes
    155     c7 0/subop/copy *(eax+0xc) 0x100/imm32/file-buffer-size
    156     # out-addr->fd = stream
    157     89/<- *eax 1/r32/ecx
    158 $new-buffered-file:end:
    159     # . reclaim locals
    160     81 0/subop/add %esp 8/imm32
    161     # . restore registers
    162     59/pop-to-ecx
    163     58/pop-to-eax
    164     # . epilogue
    165     89/<- %esp 5/r32/ebp
    166     5d/pop-to-ebp
    167     c3/return