as0 works

This commit is contained in:
janis 2026-07-13 23:33:07 +02:00
parent 2f7282577a
commit 4690b3c7ec
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
3 changed files with 554 additions and 101 deletions

View file

@ -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

View file

@ -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

View 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