diff --git a/stages/as0/Makefile b/stages/as0/Makefile
index 6a886ce..5c63031 100644
--- a/stages/as0/Makefile
+++ b/stages/as0/Makefile
@@ -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
diff --git a/stages/as0/as0.asm b/stages/as0/as0.asm
index bccb612..ccbed13 100644
--- a/stages/as0/as0.asm
+++ b/stages/as0/as0.asm
@@ -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 ?