4736
We'll use a common stream data structure for input and output streams. Having separate types makes more sense in a more high-level language, where we have type checking and where functions for handling the different types are more concise. But in machine code the sweet spot is more toward fewer types.
This commit is contained in:
parent
3d94e2db0e
commit
f94442fe2d
|
@ -1,26 +1,29 @@
|
||||||
# write: like _write, but also support in-memory output streams (`ostream`s)
|
# write: like _write, but also support in-memory streams in addition to file
|
||||||
# in addition to file descriptors.
|
# descriptors.
|
||||||
#
|
#
|
||||||
# Our first dependency-injected and testable primitive. We can pass it either
|
# Our first dependency-injected and testable primitive. We can pass it either
|
||||||
# a file descriptor or an address to an ostream. If a file descriptor is
|
# a file descriptor or an address to a stream. If a file descriptor is passed
|
||||||
# passed in, we _write to it using the right syscall. If a 'fake file descriptor'
|
# in, we _write to it using the right syscall. If a 'fake file descriptor' or
|
||||||
# or ostream is passed in, we append to the ostream. This lets us redirect
|
# stream is passed in, we append to the stream. This lets us redirect output
|
||||||
# output in tests and check it later.
|
# in tests and check it later.
|
||||||
#
|
#
|
||||||
# We assume our data segment will never begin at an address shorter than
|
# We assume our data segment will never begin at an address shorter than
|
||||||
# 0x08000000, so any smaller arguments are assumed to be real file descriptors.
|
# 0x08000000, so any smaller arguments are assumed to be real file descriptors.
|
||||||
#
|
#
|
||||||
# An ostream looks like this:
|
# A stream looks like this:
|
||||||
|
# read: int # index at which to read next
|
||||||
# write: int # index at which writes go
|
# write: int # index at which writes go
|
||||||
# data: (array byte) # prefixed by length as usual
|
# data: (array byte) # prefixed by length as usual
|
||||||
|
|
||||||
== data
|
== data
|
||||||
|
|
||||||
# In-memory ostream for tests to write() to.
|
# In-memory stream for tests to write() to.
|
||||||
# Also illustrates the layout of ostreams.
|
# Also illustrates the layout of streams.
|
||||||
Test-ostream:
|
Test-stream:
|
||||||
# current write index
|
# current write index
|
||||||
00 00 00 00
|
00 00 00 00
|
||||||
|
# current read index
|
||||||
|
00 00 00 00
|
||||||
# length (= 8)
|
# length (= 8)
|
||||||
08 00 00 00
|
08 00 00 00
|
||||||
# data
|
# data
|
||||||
|
@ -39,7 +42,7 @@ Test-ostream:
|
||||||
b8/copy-to-EAX 1/imm32
|
b8/copy-to-EAX 1/imm32
|
||||||
cd/syscall 0x80/imm8
|
cd/syscall 0x80/imm8
|
||||||
|
|
||||||
write: # f : fd or (address ostream), s : (address array byte) -> <void>
|
write: # f : fd or (address stream), s : (address array byte) -> <void>
|
||||||
# prolog
|
# prolog
|
||||||
55/push-EBP
|
55/push-EBP
|
||||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||||
|
@ -55,7 +58,7 @@ write: # f : fd or (address ostream), s : (address array byte) -> <void>
|
||||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||||
eb/jump $write:end/disp8
|
eb/jump $write:end/disp8
|
||||||
$write:fake:
|
$write:fake:
|
||||||
# otherwise, treat 'f' as an ostream to append to
|
# otherwise, treat 'f' as an stream to append to
|
||||||
# save registers
|
# save registers
|
||||||
50/push-EAX
|
50/push-EAX
|
||||||
51/push-ECX
|
51/push-ECX
|
||||||
|
@ -66,15 +69,15 @@ $write:fake:
|
||||||
# EDX = f.write
|
# EDX = f.write
|
||||||
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 2/r32/EDX . . # copy *ECX to EDX
|
||||||
# EBX = f.length
|
# EBX = f.length
|
||||||
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 4/disp8 . # copy *(ECX+4) to EBX
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 3/r32/EBX 8/disp8 . # copy *(ECX+8) to EBX
|
||||||
# EAX = _append(&f.data[f.write], &f.data[f.length], s)
|
# EAX = _append(&f.data[f.write], &f.data[f.length], s)
|
||||||
# push s
|
# push s
|
||||||
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
ff 6/subop/push 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . . 0xc/disp8 . # push *(EBP+12)
|
||||||
# push &f.data[f.length]
|
# push &f.data[f.length]
|
||||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 8/disp8 . # copy ECX+EBX+8 to EBX
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 3/index/EBX . 3/r32/EBX 0xc/disp8 . # copy ECX+EBX+12 to EBX
|
||||||
53/push-EBX
|
53/push-EBX
|
||||||
# push &f.data[f.write]
|
# push &f.data[f.write]
|
||||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 8/disp8 . # copy ECX+EBX+8 to EBX
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ECX 2/index/EDX . 3/r32/EBX 0xc/disp8 . # copy ECX+EDX+12 to EBX
|
||||||
53/push-EBX
|
53/push-EBX
|
||||||
# call
|
# call
|
||||||
e8/call _append/disp32
|
e8/call _append/disp32
|
||||||
|
@ -93,7 +96,7 @@ $write:end:
|
||||||
5d/pop-to-EBP
|
5d/pop-to-EBP
|
||||||
c3/return
|
c3/return
|
||||||
|
|
||||||
clear-ostream: # f : (address ostream)
|
clear-stream: # f : (address stream)
|
||||||
# prolog
|
# prolog
|
||||||
55/push-EBP
|
55/push-EBP
|
||||||
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
||||||
|
@ -103,24 +106,26 @@ clear-ostream: # f : (address ostream)
|
||||||
# EAX = f
|
# EAX = f
|
||||||
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none 0/r32/EAX 8/disp8 . # copy *(EBP+8) to EAX
|
||||||
# ECX = f.length
|
# ECX = f.length
|
||||||
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy *(EAX+4) to ECX
|
8b/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 8/disp8 . # copy *(EAX+8) to ECX
|
||||||
# ECX = &f.data[f.length]
|
# ECX = &f.data[f.length]
|
||||||
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 8/disp8 . # copy EAX+ECX+8 to ECX
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/EAX 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy EAX+ECX+12 to ECX
|
||||||
# f.write = 0
|
# f.write = 0
|
||||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||||
|
# f.read = 0
|
||||||
|
c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 4/disp8 0/imm32 # copy to *(EAX+4)
|
||||||
# EAX = f.data
|
# EAX = f.data
|
||||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 8/imm32 # add to EAX
|
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 0xc/imm32 # add to EAX
|
||||||
# while (true)
|
# while (true)
|
||||||
$clear-ostream:loop:
|
$clear-stream:loop:
|
||||||
# if EAX >= ECX break
|
# if EAX >= ECX break
|
||||||
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
39/compare 3/mod/direct 0/rm32/EAX . . . 1/r32/ECX . . # compare EAX with ECX
|
||||||
7d/jump-if-greater-or-equal $clear-ostream:end/disp8
|
7d/jump-if-greater-or-equal $clear-stream:end/disp8
|
||||||
# *EAX = 0
|
# *EAX = 0
|
||||||
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
c7/copy 0/mod/direct 0/rm32/EAX . . . . . 0/imm32 # copy to *EAX
|
||||||
# EAX += 4
|
# EAX += 4
|
||||||
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
|
81 0/subop/add 3/mod/direct 0/rm32/EAX . . . . . 4/imm32 # add to EAX
|
||||||
eb/jump $clear-ostream:loop/disp8
|
eb/jump $clear-stream:loop/disp8
|
||||||
$clear-ostream:end:
|
$clear-stream:end:
|
||||||
# restore registers
|
# restore registers
|
||||||
59/pop-to-ECX
|
59/pop-to-ECX
|
||||||
58/pop-to-EAX
|
58/pop-to-EAX
|
||||||
|
@ -130,28 +135,28 @@ $clear-ostream:end:
|
||||||
c3/return
|
c3/return
|
||||||
|
|
||||||
test-write-single:
|
test-write-single:
|
||||||
# clear-ostream(Test-ostream)
|
# clear-stream(Test-stream)
|
||||||
# push args
|
# push args
|
||||||
68/push Test-ostream/imm32
|
68/push Test-stream/imm32
|
||||||
# call
|
# call
|
||||||
e8/call clear-ostream/disp32
|
e8/call clear-stream/disp32
|
||||||
# discard args
|
# discard args
|
||||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||||
# write(Test-ostream, "Ab")
|
# write(Test-stream, "Ab")
|
||||||
# push args
|
# push args
|
||||||
68/push "Ab"/imm32
|
68/push "Ab"/imm32
|
||||||
68/push Test-ostream/imm32
|
68/push Test-stream/imm32
|
||||||
# call
|
# call
|
||||||
e8/call write/disp32
|
e8/call write/disp32
|
||||||
# discard args
|
# discard args
|
||||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||||
# check-ints-equal(*Test-ostream.data, 41/A 62/b 00 00, msg)
|
# check-ints-equal(*Test-stream.data, 41/A 62/b 00 00, msg)
|
||||||
# push args
|
# push args
|
||||||
68/push "F - test-write-single"/imm32
|
68/push "F - test-write-single"/imm32
|
||||||
68/push 0x006241/imm32/Ab
|
68/push 0x006241/imm32/Ab
|
||||||
# push *Test-ostream.data
|
# push *Test-stream.data
|
||||||
b8/copy-to-EAX Test-ostream/imm32
|
b8/copy-to-EAX Test-stream/imm32
|
||||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8)
|
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||||
# call
|
# call
|
||||||
e8/call check-ints-equal/disp32
|
e8/call check-ints-equal/disp32
|
||||||
# discard args
|
# discard args
|
||||||
|
@ -160,36 +165,36 @@ test-write-single:
|
||||||
c3/return
|
c3/return
|
||||||
|
|
||||||
test-write-appends:
|
test-write-appends:
|
||||||
# clear-ostream(Test-ostream)
|
# clear-stream(Test-stream)
|
||||||
# push args
|
# push args
|
||||||
68/push Test-ostream/imm32
|
68/push Test-stream/imm32
|
||||||
# call
|
# call
|
||||||
e8/call clear-ostream/disp32
|
e8/call clear-stream/disp32
|
||||||
# discard args
|
# discard args
|
||||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
||||||
# write(Test-ostream, "C")
|
# write(Test-stream, "C")
|
||||||
# push args
|
# push args
|
||||||
68/push "C"/imm32
|
68/push "C"/imm32
|
||||||
68/push Test-ostream/imm32
|
68/push Test-stream/imm32
|
||||||
# call
|
# call
|
||||||
e8/call write/disp32
|
e8/call write/disp32
|
||||||
# discard args
|
# discard args
|
||||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||||
# write(Test-ostream, "D")
|
# write(Test-stream, "D")
|
||||||
# push args
|
# push args
|
||||||
68/push "D"/imm32
|
68/push "D"/imm32
|
||||||
68/push Test-ostream/imm32
|
68/push Test-stream/imm32
|
||||||
# call
|
# call
|
||||||
e8/call write/disp32
|
e8/call write/disp32
|
||||||
# discard args
|
# discard args
|
||||||
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
||||||
# check-ints-equal(*Test-ostream.data, 43/C 44/D 00 00, msg)
|
# check-ints-equal(*Test-stream.data, 43/C 44/D 00 00, msg)
|
||||||
# push args
|
# push args
|
||||||
68/push "F - test-write-appends"/imm32
|
68/push "F - test-write-appends"/imm32
|
||||||
68/push 0x00004443/imm32/C-D
|
68/push 0x00004443/imm32/C-D
|
||||||
# push *Test-ostream.data
|
# push *Test-stream.data
|
||||||
b8/copy-to-EAX Test-ostream/imm32
|
b8/copy-to-EAX Test-stream/imm32
|
||||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 . # push *(EAX+8)
|
ff 6/subop/push 1/mod/*+disp8 0/rm32/EAX . . . . 0xc/disp8 . # push *(EAX+12)
|
||||||
# call
|
# call
|
||||||
e8/call check-ints-equal/disp32
|
e8/call check-ints-equal/disp32
|
||||||
# discard args
|
# discard args
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user