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