mu/050_write.subx

81 lines
3.8 KiB
Plaintext

# _write: write to a file descriptor (fd)
== 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: # just exit; can't test _write just yet
# . syscall(exit, 0)
bb/copy-to-ebx 0/imm32
b8/copy-to-eax 1/imm32/exit
cd/syscall 0x80/imm8
# Since this is the first file of SubX code, a note about type comments.
# Eventually we'll build a slightly higher-level safe language atop SubX.
# Even though we don't have the safe language yet, we'll start thinking in
# terms of the higher-level types in comments.
#
# Mu will have two kinds of addresses:
# - 'ref' which is used to point to a unique element, because machine
# code can't store large types in registers.
# - 'handle' which can point to a heap allocation, different heap allocations
# at different times, or even at times nothing at all. (Later on handles
# will turn into fat pointers to enable safe reclamation. But in unsafe
# levels we'll just never reclaim them, and handles will be word-sized just
# like refs.)
#
# The type 'address' can be obtained from either a ref or handle, but it can
# only be stored on the stack (say to pass objects by reference).
# Conversely, a ref can't be copied into another ref, only to an address (which
# by construction has a shorter lifetime).
#
# Beginnings of a lattice of types:
# You can convert a ref or handle to an address, but not the other way around.
# You can convert addresses to ints, but not the other way around.
_write: # fd : int, s : (addr array 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
# syscall(write, fd, (data) s+4, (size) *s)
# . fd : ebx
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 8/disp8 . # copy *(ebp+8) to ebx
# . data : ecx = s+4
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx
81 0/subop/add 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # add to ecx
# . size : edx = *s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to 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-lesser $_write:abort/disp32
$_write:end:
# . restore registers
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:abort:
# can't write a message here for risk of an infinite loop, so we'll use a special exit code instead
# . syscall(exit, 255)
bb/copy-to-ebx 0xff/imm32
b8/copy-to-eax 1/imm32/exit
cd/syscall 0x80/imm8
# never gets here
# . . vim:nowrap:textwidth=0