So far it's unclear how to do this in a series of small commits. Still nibbling around the edges. In this commit we standardize some terminology: The length of an array or stream is denominated in the high-level elements. The _size_ is denominated in bytes. The thing we encode into the type is always the size, not the length. There's still an open question of what to do about the Mu `length` operator. I'd like to modify it to provide the length. Currently it provides the size. If I can't fix that I'll rename it.
256 lines
12 KiB
Plaintext
256 lines
12 KiB
Plaintext
# write-stream: like write, but write streams rather than strings
|
|
|
|
== code
|
|
# instruction effective address register displacement immediate
|
|
# . op subop mod rm32 base index scale r32
|
|
# . 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
|
|
|
|
#? Entry: # manual test
|
|
#? # write-stream(stdout, _test-stream2)
|
|
#? 68/push _test-stream2/imm32
|
|
#? 68/push 1/imm32/stdout
|
|
#? e8/call write-stream/disp32
|
|
#? # syscall(exit, Num-test-failures)
|
|
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx
|
|
#? b8/copy-to-eax 1/imm32/exit
|
|
#? cd/syscall 0x80/imm8
|
|
|
|
write-stream: # f: fd or (addr stream byte), s: (addr stream byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# if (f < 0x08000000) _write-stream(f, s), return # f can't be a user-mode address, so treat it as a kernel file descriptor
|
|
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 0x08000000/imm32 # compare *(ebp+8)
|
|
73/jump-if-addr>= $write-stream:fake/disp8
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call _write-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
eb/jump $write-stream:end/disp8
|
|
$write-stream:fake:
|
|
# otherwise, treat 'f' as a stream to append to
|
|
# . save registers
|
|
50/push-eax
|
|
56/push-esi
|
|
57/push-edi
|
|
# edi = f
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi
|
|
# esi = s
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
|
|
# eax = _append-4(&f->data[f->write], &f->data[f->size], &s->data[s->read], &s->data[s->write])
|
|
# . . push &s->data[s->write]
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # copy *esi to eax
|
|
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
|
|
50/push-eax
|
|
# . . push &s->data[s->read]
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax
|
|
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
|
|
50/push-eax
|
|
# . . push &f->data[f->size]
|
|
8b/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 8/disp8 . # copy *(edi+8) to eax
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy edi+eax+12 to eax
|
|
50/push-eax
|
|
# . . push &f->data[f->write]
|
|
8b/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy *edi to eax
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 7/base/edi 0/index/eax . 0/r32/eax 0xc/disp8 . # copy edi+eax+12 to eax
|
|
50/push-eax
|
|
# . . call
|
|
e8/call _append-4/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# f->write += eax
|
|
01/add 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # add eax to *edi
|
|
# s->read += eax
|
|
01/add 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # add eax to *(esi+4)
|
|
# . restore registers
|
|
5f/pop-to-edi
|
|
5e/pop-to-esi
|
|
58/pop-to-eax
|
|
$write-stream:end:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
_write-stream: # fd: int, s: (addr stream byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
57/push-edi
|
|
# esi = s
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
|
|
# edi = s->read
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 7/r32/edi 4/disp8 . # copy *(esi+4) to edi
|
|
# edx = s->write
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx
|
|
# syscall(write, fd, &s->data[s->read], s->write - s->read)
|
|
# . . fd: ebx
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 8/disp8 . # copy *(ebp+8) to ebx
|
|
# . . data: ecx = &s->data[s->read]
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 7/index/edi . 1/r32/ecx 0xc/disp8 . # copy esi+edi+12 to ecx
|
|
# . . size: edx = s->write - s->read
|
|
29/subtract 3/mod/direct 2/rm32/edx . . . 7/r32/edi . . # subtract edi from edx
|
|
# . . syscall
|
|
b8/copy-to-eax 4/imm32/write
|
|
cd/syscall 0x80/imm8
|
|
# if (eax < 0) abort
|
|
3d/compare-eax-with 0/imm32
|
|
0f 8c/jump-if-< $_write-stream:abort/disp32
|
|
# s->read += eax
|
|
01/add 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # add eax to *(esi+4)
|
|
# . restore registers
|
|
5f/pop-to-edi
|
|
5e/pop-to-esi
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
$_write-stream:abort:
|
|
# . _write(2/stderr, error)
|
|
# . . push args
|
|
68/push "_write-stream: failed to write to file\n"/imm32
|
|
68/push 2/imm32/stderr
|
|
# . . call
|
|
e8/call _write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . syscall(exit, 1)
|
|
bb/copy-to-ebx 1/imm32
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
# never gets here
|
|
|
|
test-write-stream-single:
|
|
# setup
|
|
# . clear-stream(_test-stream)
|
|
# . . push args
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream(_test-stream2)
|
|
# . . push args
|
|
68/push _test-stream2/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . write(_test-stream2, "Ab")
|
|
# . . push args
|
|
68/push "Ab"/imm32
|
|
68/push _test-stream2/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# write-stream(_test-stream, _test-stream2)
|
|
# . . push args
|
|
68/push _test-stream2/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-stream-equal(_test-stream, "Ab", msg)
|
|
# . . push args
|
|
68/push "F - test-write-stream-single"/imm32
|
|
68/push "Ab"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . end
|
|
c3/return
|
|
|
|
test-write-stream-appends:
|
|
# setup
|
|
# . clear-stream(_test-stream)
|
|
# . . push args
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream(_test-stream2)
|
|
# . . push args
|
|
68/push _test-stream2/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . write(_test-stream2, "C")
|
|
# . . push args
|
|
68/push "C"/imm32
|
|
68/push _test-stream2/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# first write
|
|
# . write-stream(_test-stream, _test-stream2)
|
|
# . . push args
|
|
68/push _test-stream2/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# second write
|
|
# . write(_test-stream2, "D")
|
|
# . . push args
|
|
68/push "D"/imm32
|
|
68/push _test-stream2/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write-stream(_test-stream, _test-stream2)
|
|
# . . push args
|
|
68/push _test-stream2/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call write-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-stream-equal(_test-stream, "CD", msg)
|
|
# . . push args
|
|
68/push "F - test-write-stream-appends"/imm32
|
|
68/push "CD"/imm32
|
|
68/push _test-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . end
|
|
c3/return
|
|
|
|
== data
|
|
|
|
_test-stream2: # (stream byte)
|
|
# current write index
|
|
4/imm32
|
|
# current read index
|
|
1/imm32
|
|
# size
|
|
8/imm32
|
|
# data
|
|
41/A 42/B 43/C 44/D 00 00 00 00 # 8 bytes
|
|
|
|
# . . vim:nowrap:textwidth=0
|