as0 works
This commit is contained in:
parent
2f7282577a
commit
4690b3c7ec
|
|
@ -8,8 +8,11 @@ as0.o: as0.asm
|
|||
test: test.bin
|
||||
./test.bin
|
||||
|
||||
as0: as0.o
|
||||
ld -m elf_x86_64 -e _entry_as0 -o as0 as0.o
|
||||
|
||||
print_table: as0.o
|
||||
ld -m elf_x86_64 -e _entry_print_table -o print_table as0.o
|
||||
|
||||
clean:
|
||||
rm -f as0.o test.bin
|
||||
rm -f as0.o test.bin as0 print_table
|
||||
|
|
|
|||
|
|
@ -2,16 +2,8 @@
|
|||
;; It's also the first stage in this bootstrapping experiment that will
|
||||
;; consume proper mnemonic assembly, rather than hex input.
|
||||
|
||||
struc OFile
|
||||
.fd resd 1
|
||||
.offset resd 1
|
||||
endstruc
|
||||
|
||||
section .bss
|
||||
global buf
|
||||
ifile resb 0x20
|
||||
ofile resb 0x20
|
||||
buf resb 0x100
|
||||
heap resq 1
|
||||
|
||||
section .data
|
||||
|
|
@ -49,8 +41,8 @@ mnemonics:
|
|||
mnemonics_table:
|
||||
MN_MOV db "mov", 0
|
||||
MN_TEST db "test", 0
|
||||
MN_XOR db "xor", 0
|
||||
MN_OR db "or", 0
|
||||
MN_XOR db "xor", 0
|
||||
MN_AND db "and", 0
|
||||
MN_SHL db "shl", 0
|
||||
MN_SHR db "shr", 0
|
||||
|
|
@ -406,7 +398,6 @@ op_table_end:
|
|||
section .text
|
||||
|
||||
panic_abort:
|
||||
mov rdi, 1
|
||||
mov rax, 60
|
||||
syscall
|
||||
|
||||
|
|
@ -867,6 +858,9 @@ print_op_table:
|
|||
pop rbx
|
||||
ret
|
||||
|
||||
|
||||
;; Common Library Functions
|
||||
|
||||
;; rdi: *u8
|
||||
strlen:
|
||||
xor rax, rax
|
||||
|
|
@ -1036,6 +1030,7 @@ to_digit:
|
|||
ret
|
||||
|
||||
exit:
|
||||
xor edi, edi
|
||||
mov rax, 60
|
||||
syscall
|
||||
|
||||
|
|
@ -1305,6 +1300,8 @@ try_parse_num:
|
|||
|
||||
skip_whitespace_rbx:
|
||||
mov al, byte [rbx]
|
||||
test al, al
|
||||
jz .done
|
||||
cmp al, ' '
|
||||
ja .done
|
||||
inc rbx
|
||||
|
|
@ -1349,14 +1346,14 @@ try_parse_mem:
|
|||
mov edi, dword [rbx]
|
||||
|
||||
xor eax, eax
|
||||
mov dword [r12 + operand.size], 2 ; 16-bit
|
||||
mov dword [r12 + operand.size], 2 ; 32-bit
|
||||
cmp dl, 'q'
|
||||
sete al
|
||||
cmp dl, 'd'
|
||||
sete dl
|
||||
or al, dl
|
||||
or dl, al
|
||||
jz .not_mem
|
||||
add dword [r12 + operand.size], eax ; 32-bit?
|
||||
add dword [r12 + operand.size], eax ; 64-bit?
|
||||
|
||||
cmp edi, 'word'
|
||||
jne .not_mem
|
||||
|
|
@ -1512,6 +1509,8 @@ try_parse_operand:
|
|||
mov dword [r12 + operand.disp], 0
|
||||
|
||||
mov al, byte [rbx]
|
||||
test al, al
|
||||
jz .done
|
||||
cmp al, '['
|
||||
je .mem
|
||||
cmp al, `'`
|
||||
|
|
@ -1533,10 +1532,10 @@ try_parse_operand:
|
|||
bsr rcx, rdx ; # of bits required to represent the immediate
|
||||
mov edx, ecx
|
||||
|
||||
cmp edx, 1
|
||||
adc edx, -1 ; saturating sub
|
||||
shr edx, 3 ; divide by 8 to get the number of bytes required
|
||||
jz .done
|
||||
|
||||
bsr edx, edx ; log2 of the (# of bits - 1) + 1
|
||||
bsr edx, edx ; log2 of the (# of bytes) + 1
|
||||
inc edx
|
||||
|
||||
cmp ecx, 2
|
||||
|
|
@ -1614,6 +1613,7 @@ try_parse_label:
|
|||
pop rbx
|
||||
ret
|
||||
|
||||
;; Instruction
|
||||
|
||||
struc Instruction
|
||||
.mnemonic_offs resd 1
|
||||
|
|
@ -1633,6 +1633,8 @@ try_parse_inst:
|
|||
|
||||
mov dword [r13 + Instruction.num_operands], 0
|
||||
mov dword [r13 + Instruction.mnemonic_offs], 0
|
||||
mov qword [r13 + Instruction.operand1], 0
|
||||
mov qword [r13 + Instruction.operand2], 0
|
||||
|
||||
call skip_whitespace_rbx
|
||||
mov rdi, rbx
|
||||
|
|
@ -1697,7 +1699,6 @@ try_parse_inst:
|
|||
ret
|
||||
|
||||
|
||||
|
||||
;; find the op_table entry returning the pointer to the entry in $rax, or 0 if not found.
|
||||
;; inputs:
|
||||
;; $edi: mnemonic offset
|
||||
|
|
@ -1728,10 +1729,15 @@ find_op_table_entry:
|
|||
jne .next
|
||||
|
||||
mov r8d, dword [rax + 16] ; encoding
|
||||
cmp r8d, esi
|
||||
je .found
|
||||
mov r9d, esi
|
||||
test r8d, 0xff00
|
||||
jz .enc1
|
||||
and r9d, 0xff00
|
||||
and r9d, r8d
|
||||
jz .next
|
||||
.enc1:
|
||||
mov r9d, esi
|
||||
and r9d, 0xff
|
||||
and r9d, r8d
|
||||
|
|
@ -1754,7 +1760,7 @@ encode_inst:
|
|||
push r12
|
||||
push r13
|
||||
|
||||
xor ebx, ebx ; bytes written
|
||||
mov rbx, rsi ; bytes written
|
||||
mov r12, rdi ; inst ptr
|
||||
|
||||
; calculate the encoding
|
||||
|
|
@ -1766,7 +1772,7 @@ encode_inst:
|
|||
|
||||
; calculate size mask of op2.
|
||||
; for reg and mem operands, this is 1 << .size.
|
||||
; for imm operands, this is !(!0 << .size)
|
||||
; for imm operands, this is (!0 << .size) && 0xff
|
||||
mov ecx, dword [r12 + Instruction.operand2 + operand.size]
|
||||
mov eax, 1
|
||||
shl eax, cl
|
||||
|
|
@ -1774,9 +1780,9 @@ encode_inst:
|
|||
cmp dword [r12 + Instruction.operand2 + operand.type], KIND_IMM
|
||||
jne .size_done_op2
|
||||
xor eax, eax
|
||||
lea ecx, [ecx - 1]
|
||||
sub eax, 1
|
||||
shl eax, cl
|
||||
and eax, 0xf
|
||||
|
||||
.size_done_op2:
|
||||
shl eax, 8
|
||||
|
|
@ -1802,16 +1808,16 @@ encode_inst:
|
|||
|
||||
; calculate size mask of op1.
|
||||
; for reg and mem operands, this is 1 << .size.
|
||||
; for imm operands, this is !(!0 << .size)
|
||||
; for imm operands, this is (!0 << .size) & 0xf
|
||||
mov ecx, dword [r12 + Instruction.operand1 + operand.size]
|
||||
mov edx, 1
|
||||
shl edx, cl
|
||||
cmp dword [r12 + Instruction.operand1 + operand.type], KIND_IMM
|
||||
jne .size_done
|
||||
xor edx, edx
|
||||
lea ecx, [ecx - 1]
|
||||
sub edx, 1
|
||||
shl edx, cl
|
||||
and edx, 0xf
|
||||
.size_done:
|
||||
xor edx, eax
|
||||
|
||||
|
|
@ -1822,8 +1828,13 @@ encode_inst:
|
|||
jz .done
|
||||
mov r13, rax ; pointer to the op_table entry
|
||||
|
||||
mov eax, dword [r13 + OpEntry.op1_size]
|
||||
mov dword [r12 + Instruction.operand1 + operand.size], eax
|
||||
mov eax, dword [r13 + OpEntry.op2_size]
|
||||
mov dword [r12 + Instruction.operand2 + operand.size], eax
|
||||
|
||||
; write the prefix, if any
|
||||
cmp dword [r13 + 24], 0
|
||||
cmp dword [r13 + OpEntry.prefix], 0
|
||||
je .rex
|
||||
|
||||
movzx edi, byte [r13 + 24]
|
||||
|
|
@ -1868,6 +1879,9 @@ encode_inst:
|
|||
mov edi, dword [r13 + OpEntry.opcode]
|
||||
call write_opcode_with_bits
|
||||
|
||||
cmp dword [r13 + OpEntry.num_operands], 0
|
||||
jz .ref
|
||||
|
||||
test dword [r13 + OpEntry.encoding], ENC_O_SIGNAL_BITS | ENC_O_SIGNAL_BITS << 8
|
||||
jnz .imm
|
||||
|
||||
|
|
@ -1884,48 +1898,68 @@ encode_inst:
|
|||
call write_non_zero_bytes
|
||||
|
||||
pop rax
|
||||
|
||||
mov cl, al
|
||||
and cl, 0b11000111
|
||||
cmp cl, 0b00000101 ; if modRM.mod == 00b and modRM.rm == 101b, then we have a disp32
|
||||
jne .disp
|
||||
|
||||
xor edi, edi
|
||||
mov esi, 4
|
||||
call write_bytes
|
||||
jmp .imm
|
||||
|
||||
.disp:
|
||||
shr eax, 6
|
||||
dec eax
|
||||
cmp eax, 2
|
||||
jge .imm
|
||||
jae .imm
|
||||
mov rdi, qword [rsp + 8]
|
||||
mov edi, dword [rdi + operand.disp]
|
||||
call write_disp
|
||||
|
||||
mov rdi, qword [rsp + 8]
|
||||
test dword [rdi + operand.type], KIND_LABEL_FLAG
|
||||
jz .imm
|
||||
|
||||
mov edi, dword [rdi + operand.disp]
|
||||
lea rsi, [rbx - 4]
|
||||
call push_lbl_ref_by_hash
|
||||
|
||||
.imm:
|
||||
xor eax, eax ; clear return
|
||||
mov rdi, qword [rsp]
|
||||
mov rsi, qword [rsp + 8]
|
||||
add rsp, 16
|
||||
; write immediate, if any
|
||||
cmp dword [rsi + operand.type], KIND_IMM
|
||||
je .imm1
|
||||
test dword [rsi + operand.type], KIND_IMM
|
||||
jnz .imm1
|
||||
mov rsi, rdi
|
||||
cmp dword [rsi + operand.type], KIND_IMM
|
||||
jne .done
|
||||
test dword [rsi + operand.type], KIND_IMM
|
||||
jz .ref
|
||||
|
||||
.imm1:
|
||||
push rsi
|
||||
test dword [rsi + operand.type], KIND_LABEL_FLAG
|
||||
jz .imm2
|
||||
|
||||
mov edi, dword [rsi + operand.disp]
|
||||
mov rsi, rbx
|
||||
mov edi, dword [rsi + operand_imm.imm] ; hash
|
||||
mov rsi, rbx ; write offset
|
||||
lea rdx, [rbx + 4] ; disp offset (after the imm32 is written)
|
||||
call push_lbl_ref_by_hash
|
||||
|
||||
.imm2:
|
||||
pop rsi
|
||||
mov rdi, qword [rsi + operand_imm.imm]
|
||||
mov esi, dword [r13 + OpEntry.op2_size]
|
||||
mov esi, dword [rsi + operand.size]
|
||||
call write_imm
|
||||
|
||||
.ref:
|
||||
mov rdi, qword [rsp + 8]
|
||||
add rsp, 16
|
||||
|
||||
test dword [rdi + operand.type], KIND_LABEL_FLAG
|
||||
jz .done
|
||||
test dword [rdi + operand.type], KIND_MEM
|
||||
jz .done
|
||||
|
||||
lea rsi, [rbx - 4]
|
||||
sub rsi, rax ; write offset (before the immediate)
|
||||
mov rdx, rbx ; disp offset
|
||||
mov edi, dword [rdi + operand.disp]
|
||||
call push_lbl_ref_by_hash
|
||||
|
||||
.done:
|
||||
mov rax, rbx ; bytes written
|
||||
pop r13
|
||||
|
|
@ -1945,19 +1979,27 @@ write_disp:
|
|||
jmp write_bytes
|
||||
|
||||
write_bytes:
|
||||
call print_u8s_le
|
||||
push rdi
|
||||
lea rdi, [rsp]
|
||||
call ofile_write_bytes
|
||||
add rbx, rax
|
||||
pop rdi
|
||||
ret
|
||||
|
||||
write_opcode_with_bits:
|
||||
call swap_bytes_and_shift_in_place
|
||||
or rdi, rsi
|
||||
call swap_bytes_and_shift_in_place
|
||||
jmp write_non_zero_bytes
|
||||
|
||||
;; writes the contents of the $rdi register until the first zero byte.
|
||||
write_non_zero_bytes:
|
||||
call print_non_zero_u8s_le
|
||||
push rdi
|
||||
lea rdi, [rsp]
|
||||
call strlen
|
||||
mov esi, eax
|
||||
call ofile_write_bytes
|
||||
add rbx, rax
|
||||
pop rdi
|
||||
ret
|
||||
|
||||
;; compute the modRM and SIB bytes for the operands $rdi and $rsi, in reg-mem order, with the $rdx reg-bits
|
||||
|
|
@ -1986,14 +2028,23 @@ compute_modrm_sib:
|
|||
je .done_mem
|
||||
and eax, 0x37 ; clear mod bits, mod = 00b
|
||||
|
||||
; rip-relative is mod = 00b, r/m = 101b, and no SIB byte, even though disp32
|
||||
cmp dword [rsi + operand.type], KIND_MEM_LABEL
|
||||
je .done_mem
|
||||
|
||||
test dword [rsi + operand.type], KIND_MEM
|
||||
jz .done_mem
|
||||
|
||||
cmp dword [rsi + operand.disp], 0
|
||||
jne .sib ; mod = 01b or 10b
|
||||
; if mod == 0 && r/m & 111 == 101 (rbp or r13), then we need a displacement, even if its 0
|
||||
|
||||
mov ecx, eax
|
||||
and ecx, 7
|
||||
; if mod == 0 and r/m == 100b (RSP or R12), then we need a SIB byte, but no displacement
|
||||
cmp ecx, 4
|
||||
je .sib_no_disp
|
||||
|
||||
; if mod == 0 && r/m & 111 == 101 (rbp or r13), then we need a displacement, even if its 0
|
||||
cmp ecx, 5
|
||||
jne .done_mem
|
||||
|
||||
|
|
@ -2005,16 +2056,16 @@ compute_modrm_sib:
|
|||
shl edx, 6 ; mod = 01b or 10b
|
||||
or eax, edx
|
||||
|
||||
.sib_no_disp:
|
||||
xor edx, edx ; sib
|
||||
; copy r/m bits to SIB base bits
|
||||
mov edx, eax
|
||||
shr edx, 3
|
||||
and edx, 7
|
||||
|
||||
and eax, 0b11000111 ; clear the r/m bits
|
||||
or eax, 0b00100000 ; set the r/m bits to 100b (SIB follows)
|
||||
and eax, 0b11111000 ; clear the r/m bits
|
||||
or eax, 0b00000100 ; set the r/m bits to 100b (SIB follows)
|
||||
|
||||
mov edx, 0b00100000 ; index = 100b (no index)
|
||||
or edx, 0b00100000 ; index = 100b (no index)
|
||||
|
||||
mov ecx, dword [rsi + operand.scale]
|
||||
and ecx, 3
|
||||
|
|
@ -2032,8 +2083,6 @@ compute_modrm_sib:
|
|||
.done_mem:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
;; compute the rex bits for the operands $rdi and $rsi, in reg-mem order
|
||||
compute_rex:
|
||||
|
|
@ -2048,7 +2097,7 @@ compute_rex:
|
|||
shl dl, 2 ; REX.R
|
||||
or al, dl
|
||||
|
||||
cmp dword [rdi + operand.size], 3
|
||||
cmp dword [rdi + operand.size], 8 ; this is no longer in log2 form
|
||||
setnb dl
|
||||
shl dl, 3 ; REX.W
|
||||
or al, dl
|
||||
|
|
@ -2063,7 +2112,7 @@ compute_rex:
|
|||
setne dl
|
||||
or al, dl ; REX.B
|
||||
|
||||
cmp dword [rsi + operand.size], 3
|
||||
cmp dword [rsi + operand.size], 8 ; this is no longer in log2 form
|
||||
setnb dl
|
||||
shl dl, 3 ; REX.W
|
||||
or al, dl
|
||||
|
|
@ -2088,9 +2137,195 @@ compute_rex:
|
|||
ret
|
||||
|
||||
|
||||
;; Input and Output
|
||||
|
||||
struc OFile
|
||||
.fd resd 1
|
||||
.offset resd 1
|
||||
endstruc
|
||||
|
||||
struc IFile
|
||||
.fd resd 1
|
||||
.peeked_byte resb 1
|
||||
.peeked_flags resb 1
|
||||
.pad resb 2
|
||||
.buffer resq 1
|
||||
.buffer_len resq 1
|
||||
.buffer_cursor resq 1
|
||||
endstruc
|
||||
%define DID_PEEK 1
|
||||
%define DID_PEEK_SOME 2
|
||||
%define DID_PEEK_AND_SOME 3
|
||||
|
||||
section .bss
|
||||
ifile resb 0x20
|
||||
ofile resb 0x20
|
||||
buf resb 0x100
|
||||
|
||||
section .text
|
||||
|
||||
;; seek to offset $rsi in file $rdi
|
||||
fseek:
|
||||
mov rax, 8 ; syscall: lseek
|
||||
mov rdx, 0 ; SEEK_SET
|
||||
syscall
|
||||
ret
|
||||
|
||||
;; write $rsi bytes from buffer $rdi to file $rdx, returning the number of bytes written in $rax
|
||||
fwrite_bytes:
|
||||
mov rax, 1 ; syscall: write
|
||||
mov rcx, rdx ; fd
|
||||
mov rdx, rsi ; count
|
||||
mov rsi, rdi ; buffer
|
||||
mov rdi, rcx ; fd
|
||||
syscall
|
||||
ret
|
||||
|
||||
ofile_write_bytes:
|
||||
lea rdx, [rel ofile]
|
||||
mov edx, dword [rdx + OFile.fd]
|
||||
jmp fwrite_bytes
|
||||
|
||||
;; open file $rdi with flags $rsi and mode $rdx, returning the file descriptor in $rax, or -1 on error.
|
||||
fopen:
|
||||
mov rax, 2 ; syscall: open
|
||||
syscall
|
||||
ret
|
||||
|
||||
close:
|
||||
mov rax, 3 ; syscall: close
|
||||
syscall
|
||||
ret
|
||||
|
||||
init_ifile_with_fd:
|
||||
mov eax, edi
|
||||
jmp init_ifile.with_fd
|
||||
;; open the input file $rdi and initialise the ifile structure.
|
||||
init_ifile:
|
||||
xor esi, esi
|
||||
xor edx, edx
|
||||
call fopen
|
||||
.with_fd:
|
||||
lea rdi, [rel ifile]
|
||||
mov dword [rdi + IFile.fd], eax
|
||||
mov byte [rdi + IFile.peeked_flags], 0
|
||||
|
||||
mov edi, 0x1000
|
||||
mov esi, 0x8
|
||||
call heap_alloc
|
||||
lea rdi, [rel ifile]
|
||||
mov qword [rdi + IFile.buffer], rax
|
||||
mov qword [rdi + IFile.buffer_len], 0x1000
|
||||
mov qword [rdi + IFile.buffer_cursor], 0
|
||||
ret
|
||||
|
||||
getc_inner:
|
||||
lea rax, [rel ifile]
|
||||
mov cl, byte [rax + IFile.peeked_flags] ; peeked
|
||||
test cl, DID_PEEK
|
||||
jz .iter_next
|
||||
test cl, DID_PEEK_SOME ; peeked_some
|
||||
setnz dl
|
||||
and edx, 1
|
||||
mov al, byte [rax + IFile.peeked_byte]
|
||||
ret
|
||||
.iter_next:
|
||||
mov rdi, qword [rax + IFile.buffer_cursor] ; buf_cur
|
||||
cmp rdi, qword [rax + IFile.buffer_len] ; buf_len
|
||||
jae .read
|
||||
inc qword [rax + IFile.buffer_cursor] ; buf_cur++
|
||||
mov rsi, qword [rax + IFile.buffer] ; buf
|
||||
mov al, byte [rsi + rdi]
|
||||
mov edx, 1 ; peeked_some = true
|
||||
ret
|
||||
.read:
|
||||
mov rdi, qword [rax + IFile.fd] ; fd
|
||||
mov rsi, qword [rax + IFile.buffer] ; buf
|
||||
mov rdx, 0x1000 ; read 0x1000 bytes
|
||||
push rax
|
||||
mov rax, 0 ; syscall: read
|
||||
syscall
|
||||
cmp rax, 0
|
||||
jle .eof
|
||||
mov rdi, rax ; number of bytes read
|
||||
pop rax
|
||||
mov qword [rax + IFile.buffer_len], rdi ; buf_len = bytes read
|
||||
mov qword [rax + IFile.buffer_cursor], 0 ; buf_cur = 0
|
||||
jmp .iter_next
|
||||
.eof:
|
||||
pop rax
|
||||
xor dl, dl ; peeked_some = false
|
||||
ret
|
||||
|
||||
;; returns the next byte from the input without advancing the cursor. returns 1 or 0 in dl depending on EOF
|
||||
peekc:
|
||||
call getc_inner
|
||||
lea rdi, [rel ifile]
|
||||
movzx ecx, dl
|
||||
shl ecx, 1
|
||||
inc ecx
|
||||
mov byte [rdi + IFile.peeked_byte], al ; peeked_byte = c
|
||||
mov byte [rdi + IFile.peeked_flags], cl ; peeked = true, peeked_some = dl
|
||||
ret
|
||||
|
||||
;; returns the next byte from the input. returns 1 or 0 in dl depending on EOF
|
||||
getc:
|
||||
call getc_inner
|
||||
lea rdi, [rel ifile]
|
||||
mov word [rdi + IFile.peeked_flags], 0
|
||||
and eax, 0xff
|
||||
ret
|
||||
|
||||
ifile_skip_whitespaces:
|
||||
call peekc
|
||||
cmp al, ' '
|
||||
ja .done
|
||||
call getc
|
||||
jmp ifile_skip_whitespaces
|
||||
.done:
|
||||
ret
|
||||
|
||||
ifile_skip_comment:
|
||||
call peekc
|
||||
cmp al, `;`
|
||||
jne .done
|
||||
.loop:
|
||||
call getc
|
||||
cmp al, 10
|
||||
jne .loop
|
||||
call ifile_skip_whitespaces
|
||||
jmp ifile_skip_comment
|
||||
.done:
|
||||
ret
|
||||
|
||||
;; read a line from the input file into `buf`
|
||||
read_line:
|
||||
push rbx
|
||||
|
||||
; skip whitespaces, empty lines and comments
|
||||
call ifile_skip_whitespaces
|
||||
; guaranteed to be at the start of a token or EOF
|
||||
|
||||
lea rbx, [rel buf]
|
||||
.loop:
|
||||
call getc
|
||||
test dl, dl
|
||||
jz .done
|
||||
test al, al
|
||||
jz .done
|
||||
|
||||
cmp al, 10
|
||||
je .done
|
||||
mov byte [rbx], al
|
||||
inc rbx
|
||||
jmp .loop
|
||||
.done:
|
||||
mov byte [rbx], 0
|
||||
lea rax, [rel buf]
|
||||
sub rbx, rax
|
||||
mov rax, rbx
|
||||
pop rbx
|
||||
ret
|
||||
|
||||
;; parse buffer $rdi, bytes written in $rsi, return updated bytes written.
|
||||
parse_line:
|
||||
|
|
@ -2107,14 +2342,15 @@ parse_line:
|
|||
|
||||
mov rdi, rbx
|
||||
sub rsp, 72
|
||||
mov rsi, rsp
|
||||
lea rsi, [rsp]
|
||||
call try_parse_inst
|
||||
test eax, eax
|
||||
jz .done_inst
|
||||
|
||||
lea rdi, [rsp]
|
||||
mov rsi, r12
|
||||
call encode_inst
|
||||
add r12, rax
|
||||
mov r12, rax
|
||||
|
||||
.done_inst:
|
||||
add rsp, 72
|
||||
|
|
@ -2142,22 +2378,80 @@ parse_line:
|
|||
|
||||
;; Labels
|
||||
|
||||
struc Vec
|
||||
.data resq 1 ; pointer to elements
|
||||
.size resd 1 ; size in element count
|
||||
.cap resd 1 ; cap in element count
|
||||
.ele_size resd 1 ; size of each element in bytes
|
||||
.ele_align resd 1 ; alignment of each element in bytes
|
||||
endstruc
|
||||
|
||||
struc Label
|
||||
.name_hash resd 1
|
||||
.offset resd 1
|
||||
endstruc
|
||||
|
||||
struc LabelTable
|
||||
.size resd 1
|
||||
.cap resd 1
|
||||
.labels resq 1
|
||||
struc LabelRef
|
||||
.name_hash resd 1
|
||||
.write_offset resd 1
|
||||
.disp_offset resd 1
|
||||
endstruc
|
||||
|
||||
section .data
|
||||
labels dq 0, 0
|
||||
label_refs dq 0, 0
|
||||
labels dq 0, 0, 0
|
||||
label_refs dq 0, 0, 0
|
||||
|
||||
section .text
|
||||
|
||||
vec_get_nth:
|
||||
mov rax, rsi
|
||||
mov ecx, dword [rdi + Vec.ele_size]
|
||||
mul ecx
|
||||
add rax, qword [rdi + Vec.data]
|
||||
ret
|
||||
|
||||
;; reserve space for $rsi additional entries in vec $rdi.
|
||||
vec_reserve:
|
||||
sub rsp, 16
|
||||
|
||||
mov edx, dword [rdi + Vec.ele_size]
|
||||
mov ecx, dword [rdi + Vec.ele_align]
|
||||
mov dword [rsp], edx ; obj-size
|
||||
mov dword [rsp + 4], ecx ; alignment
|
||||
mov qword [rsp + 8], rdi ; table pointer
|
||||
|
||||
mov eax, dword [rdi + Vec.size]
|
||||
add eax, esi
|
||||
cmp eax, dword [rdi + Vec.cap]
|
||||
jl .done
|
||||
|
||||
mov eax, esi
|
||||
add eax, dword [rdi + Vec.size]
|
||||
mov ecx, dword [rdi + Vec.cap]
|
||||
mov edx, ecx
|
||||
shl edx, 1
|
||||
cmp eax, edx
|
||||
cmovl eax, edx
|
||||
; new cap
|
||||
mul dword [rsp] ; obj-size
|
||||
|
||||
; old cap
|
||||
xchg eax, ecx
|
||||
mul dword [rsp] ; obj-size
|
||||
|
||||
mov rdi, qword [rdi + Vec.data] ; old pointer
|
||||
mov esi, eax ; old size
|
||||
mov edx, ecx ; new size
|
||||
mov ecx, dword [rsp + 4] ; alignment
|
||||
call heap_realloc
|
||||
mov rdi, qword [rsp + 8] ; table pointer
|
||||
mov qword [rdi + Vec.data], rax
|
||||
|
||||
.done:
|
||||
add rsp, 16
|
||||
ret
|
||||
|
||||
|
||||
section .text
|
||||
;; calculates the hash of a byte sequence in $rdi of length $rsi, returning it in $eax
|
||||
global fasthash
|
||||
fasthash:
|
||||
|
|
@ -2177,80 +2471,112 @@ fasthash:
|
|||
global init_label_tables
|
||||
init_label_tables:
|
||||
mov edi, 0x100
|
||||
mov esi, 8
|
||||
mov esi, 4
|
||||
call heap_alloc
|
||||
lea rdi, [rel labels]
|
||||
mov dword [rdi + LabelTable.size], 0
|
||||
mov dword [rdi + LabelTable.cap], 0x100 / 8
|
||||
mov qword [rdi + LabelTable.labels], rax
|
||||
mov dword [rdi + Vec.size], 0
|
||||
mov dword [rdi + Vec.cap], 0x100 / Label_size
|
||||
mov dword [rdi + Vec.ele_size], Label_size
|
||||
mov dword [rdi + Vec.ele_align], 4
|
||||
mov qword [rdi + Vec.data], rax
|
||||
|
||||
mov edi, 0x100
|
||||
mov esi, 8
|
||||
mov edi, 0x180
|
||||
mov esi, 4
|
||||
call heap_alloc
|
||||
lea rdi, [rel label_refs]
|
||||
mov dword [rdi + LabelTable.size], 0
|
||||
mov dword [rdi + LabelTable.cap], 0x100 / 8
|
||||
mov qword [rdi + LabelTable.labels], rax
|
||||
mov dword [rdi + Vec.size], 0
|
||||
mov dword [rdi + Vec.cap], 0x180 / LabelRef_size
|
||||
mov dword [rdi + Vec.ele_size], LabelRef_size
|
||||
mov dword [rdi + Vec.ele_align], 4
|
||||
mov qword [rdi + Vec.data], rax
|
||||
|
||||
ret
|
||||
|
||||
;; push label hash $edi with offset $esi into the label ref table.
|
||||
;; push label hash $edi with write offset $esi and disp offset $edx into the label ref table.
|
||||
push_lbl_ref_by_hash:
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
|
||||
lea rbx, [rel label_refs]
|
||||
mov r13d, esi ; label offset
|
||||
mov r13d, esi ; label write offset
|
||||
mov r12d, edi ; label hash
|
||||
jmp push_lbl_common.hash_in_r12d
|
||||
mov r14d, edx ; label disp offset
|
||||
jmp push_lbl_ref.hash_in_r12d
|
||||
|
||||
;; push label $rdi with length $rsi and offset $rdx into the label ref table
|
||||
;; push label $rdi with length $rsi, write offset $edx and disp offset $ecx into the label ref table.
|
||||
push_lbl_ref:
|
||||
lea rcx, [rel label_refs]
|
||||
jmp push_lbl_common
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
|
||||
lea rbx, [rel label_refs]
|
||||
mov r13d, edx ; label write offset
|
||||
mov r14d, ecx ; label disp offset
|
||||
|
||||
call fasthash
|
||||
mov r12d, eax ; hash
|
||||
|
||||
.hash_in_r12d:
|
||||
mov rdi, rbx
|
||||
mov rsi, 1
|
||||
call vec_reserve
|
||||
|
||||
mov rdi, rbx
|
||||
mov esi, dword [rbx + Vec.size]
|
||||
call vec_get_nth
|
||||
|
||||
mov dword [rax + LabelRef.name_hash], r12d
|
||||
mov dword [rax + LabelRef.write_offset], r13d
|
||||
mov dword [rax + LabelRef.disp_offset], r14d
|
||||
inc dword [rbx + Vec.size]
|
||||
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
ret
|
||||
|
||||
;; push label $rdi with length $rsi and offset $edx into the label table
|
||||
push_lbl:
|
||||
lea rcx, [rel labels]
|
||||
push_lbl_common:
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
|
||||
mov rbx, rcx
|
||||
lea rbx, [rel labels]
|
||||
mov r13d, edx ; label offset
|
||||
|
||||
call fasthash
|
||||
mov r12d, eax ; store the hash in r12d
|
||||
.hash_in_r12d:
|
||||
mov r12d, eax ; hash
|
||||
|
||||
mov eax, dword [rbx + LabelTable.size]
|
||||
cmp eax, dword [rbx + LabelTable.cap]
|
||||
jl .has_space
|
||||
mov rdi, rbx
|
||||
mov rsi, 1
|
||||
call vec_reserve
|
||||
|
||||
mov rdi, qword [rbx + LabelTable.labels]
|
||||
mov esi, dword [rbx + LabelTable.cap]
|
||||
mov edx, 8
|
||||
mov ecx, esi
|
||||
shl ecx, 1
|
||||
call heap_realloc
|
||||
mov qword [rbx + LabelTable.labels], rax
|
||||
shl dword [rbx + LabelTable.cap], 1
|
||||
mov rdi, rbx
|
||||
mov esi, dword [rbx + Vec.size]
|
||||
call vec_get_nth
|
||||
|
||||
.has_space:
|
||||
mov rax, qword [rbx + LabelTable.labels]
|
||||
mov edi, dword [rbx + LabelTable.size]
|
||||
lea rax, [rax + rdi * 8]
|
||||
mov dword [rax + Label.name_hash], r12d
|
||||
mov dword [rax + Label.offset], r13d
|
||||
inc dword [rbx + LabelTable.size]
|
||||
inc dword [rbx + Vec.size]
|
||||
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
ret
|
||||
|
||||
find_lbl_by_hash:
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
|
||||
lea rbx, [rel labels]
|
||||
mov r12d, edi ; label hash
|
||||
jmp find_lbl.by_hash
|
||||
|
||||
find_lbl:
|
||||
push rbx
|
||||
push r12
|
||||
|
|
@ -2261,12 +2587,13 @@ find_lbl:
|
|||
call fasthash
|
||||
mov r12d, eax ; store the hash in r12d
|
||||
|
||||
.by_hash:
|
||||
xor r13d, r13d
|
||||
.loop:
|
||||
cmp r13d, dword [rbx + LabelTable.size]
|
||||
cmp r13d, dword [rbx + Vec.size]
|
||||
jge .not_found
|
||||
|
||||
mov rax, qword [rbx + LabelTable.labels]
|
||||
mov rax, qword [rbx + Vec.data]
|
||||
lea rax, [rax + r13 * 8]
|
||||
cmp dword [rax + Label.name_hash], r12d
|
||||
je .found
|
||||
|
|
@ -2276,14 +2603,121 @@ find_lbl:
|
|||
mov eax, dword [rax + Label.offset]
|
||||
jmp .done
|
||||
.not_found:
|
||||
xor rax, rax
|
||||
mov rax, -1
|
||||
.done:
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
ret
|
||||
|
||||
fixup_lbl_refs:
|
||||
push rbx ; label ref table
|
||||
push r12 ; index
|
||||
push r13 ; ref offset
|
||||
push r14
|
||||
|
||||
xor r12d, r12d
|
||||
.loop:
|
||||
lea rbx, [rel label_refs]
|
||||
cmp r12d, dword [rbx + Vec.size]
|
||||
jge .done
|
||||
|
||||
mov rax, qword [rbx + Vec.data]
|
||||
lea rcx, [r12 + r12 * 2]
|
||||
shl rcx, 2 ; multiply by 12
|
||||
add rax, rcx
|
||||
inc r12d
|
||||
mov edi, dword [rax + LabelRef.name_hash]
|
||||
mov r13d, dword [rax + LabelRef.write_offset]
|
||||
mov r14d, dword [rax + LabelRef.disp_offset]
|
||||
call find_lbl_by_hash
|
||||
cmp rax, -1
|
||||
je .loop
|
||||
|
||||
mov esi, eax ; label source offset
|
||||
sub eax, r14d ; displacement
|
||||
mov r14d, eax
|
||||
|
||||
lea rdi, [rel ofile]
|
||||
mov edi, dword [rdi + OFile.fd] ; fd
|
||||
mov esi, r13d ; write offset
|
||||
call fseek
|
||||
|
||||
mov edi, r14d ; displacement
|
||||
mov esi, 4 ; size
|
||||
call write_bytes
|
||||
|
||||
jmp .loop
|
||||
.done:
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
ret
|
||||
|
||||
global _entry_print_table
|
||||
_entry_print_table:
|
||||
call print_op_table
|
||||
call exit
|
||||
|
||||
a.out: db "a.out", 0
|
||||
global _entry_as0
|
||||
;; /as0 <input file>? <output file>
|
||||
_entry_as0:
|
||||
mov eax, dword [rsp]
|
||||
lea rcx, [rsp + 8]
|
||||
|
||||
sub rsp, 24
|
||||
mov qword [rsp], rcx ; argv
|
||||
mov qword [rsp + 8], rax ; argc
|
||||
mov rdi, [rcx + 8] ; argv[1] (input file)
|
||||
mov qword [rsp + 16], rdi ; output file
|
||||
|
||||
mov edi, 0 ; stdin
|
||||
cmp eax, 2 ; check if we have an input file
|
||||
jl .init_ifile
|
||||
mov rdi, [rcx + 16] ; argv[2] (output file)
|
||||
mov qword [rsp + 16], rdi ; output file
|
||||
|
||||
mov rdi, [rcx + 8] ; argv[1]
|
||||
xor esi, esi ; O_RDONLY
|
||||
xor edx, edx ; mode = 0
|
||||
call fopen
|
||||
mov edi, eax ; fd
|
||||
.init_ifile:
|
||||
call init_ifile_with_fd
|
||||
|
||||
;; mov rdi, qword [rsp + 16] ; output file
|
||||
lea rdi, [rel a.out] ; default output file
|
||||
mov esi, 0x241 ; O_WRONLY | O_CREAT | O_TRUNC
|
||||
mov edx, 0x1b6 ; mode = 0666
|
||||
call fopen
|
||||
xor edi, edi
|
||||
sub edi, eax
|
||||
jg panic_abort
|
||||
lea rdi, [rel ofile]
|
||||
mov dword [rdi + OFile.fd], eax
|
||||
mov dword [rdi + OFile.offset], 0
|
||||
|
||||
call init_label_tables
|
||||
|
||||
xor ebx, ebx ; bytes written
|
||||
.loop:
|
||||
call read_line
|
||||
test rax, rax
|
||||
jz .done
|
||||
|
||||
lea rdi, [rel buf]
|
||||
mov rsi, rbx ; bytes written
|
||||
call parse_line
|
||||
mov rbx, rax ; update bytes written
|
||||
jmp .loop
|
||||
|
||||
.done:
|
||||
call fixup_lbl_refs
|
||||
|
||||
lea rdi, [rel ofile]
|
||||
mov edi, dword [rdi + OFile.fd]
|
||||
call close
|
||||
|
||||
call exit
|
||||
|
|
|
|||
16
stages/as0/tests/helloworld.as0
Normal file
16
stages/as0/tests/helloworld.as0
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
@_start:
|
||||
mov rdi, 0xa21444C52
|
||||
push rdi
|
||||
mov rdi, 0x4F57204F
|
||||
shl rdi, 32
|
||||
mov rsi, 0x4C4C4548
|
||||
or rdi, rsi
|
||||
push rdi
|
||||
@init:
|
||||
lea rsi, qword [rsp]
|
||||
mov edx, 13
|
||||
mov eax, 1
|
||||
mov edi, 1
|
||||
syscall
|
||||
jmp 'init
|
||||
jmp '_start
|
||||
Loading…
Reference in a new issue