as0 works
This commit is contained in:
parent
2f7282577a
commit
4690b3c7ec
|
|
@ -8,8 +8,11 @@ as0.o: as0.asm
|
||||||
test: test.bin
|
test: test.bin
|
||||||
./test.bin
|
./test.bin
|
||||||
|
|
||||||
|
as0: as0.o
|
||||||
|
ld -m elf_x86_64 -e _entry_as0 -o as0 as0.o
|
||||||
|
|
||||||
print_table: as0.o
|
print_table: as0.o
|
||||||
ld -m elf_x86_64 -e _entry_print_table -o print_table as0.o
|
ld -m elf_x86_64 -e _entry_print_table -o print_table as0.o
|
||||||
|
|
||||||
clean:
|
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
|
;; It's also the first stage in this bootstrapping experiment that will
|
||||||
;; consume proper mnemonic assembly, rather than hex input.
|
;; consume proper mnemonic assembly, rather than hex input.
|
||||||
|
|
||||||
struc OFile
|
|
||||||
.fd resd 1
|
|
||||||
.offset resd 1
|
|
||||||
endstruc
|
|
||||||
|
|
||||||
section .bss
|
section .bss
|
||||||
global buf
|
global buf
|
||||||
ifile resb 0x20
|
|
||||||
ofile resb 0x20
|
|
||||||
buf resb 0x100
|
|
||||||
heap resq 1
|
heap resq 1
|
||||||
|
|
||||||
section .data
|
section .data
|
||||||
|
|
@ -49,8 +41,8 @@ mnemonics:
|
||||||
mnemonics_table:
|
mnemonics_table:
|
||||||
MN_MOV db "mov", 0
|
MN_MOV db "mov", 0
|
||||||
MN_TEST db "test", 0
|
MN_TEST db "test", 0
|
||||||
MN_XOR db "xor", 0
|
|
||||||
MN_OR db "or", 0
|
MN_OR db "or", 0
|
||||||
|
MN_XOR db "xor", 0
|
||||||
MN_AND db "and", 0
|
MN_AND db "and", 0
|
||||||
MN_SHL db "shl", 0
|
MN_SHL db "shl", 0
|
||||||
MN_SHR db "shr", 0
|
MN_SHR db "shr", 0
|
||||||
|
|
@ -406,7 +398,6 @@ op_table_end:
|
||||||
section .text
|
section .text
|
||||||
|
|
||||||
panic_abort:
|
panic_abort:
|
||||||
mov rdi, 1
|
|
||||||
mov rax, 60
|
mov rax, 60
|
||||||
syscall
|
syscall
|
||||||
|
|
||||||
|
|
@ -867,6 +858,9 @@ print_op_table:
|
||||||
pop rbx
|
pop rbx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;; Common Library Functions
|
||||||
|
|
||||||
;; rdi: *u8
|
;; rdi: *u8
|
||||||
strlen:
|
strlen:
|
||||||
xor rax, rax
|
xor rax, rax
|
||||||
|
|
@ -1036,6 +1030,7 @@ to_digit:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
xor edi, edi
|
||||||
mov rax, 60
|
mov rax, 60
|
||||||
syscall
|
syscall
|
||||||
|
|
||||||
|
|
@ -1305,6 +1300,8 @@ try_parse_num:
|
||||||
|
|
||||||
skip_whitespace_rbx:
|
skip_whitespace_rbx:
|
||||||
mov al, byte [rbx]
|
mov al, byte [rbx]
|
||||||
|
test al, al
|
||||||
|
jz .done
|
||||||
cmp al, ' '
|
cmp al, ' '
|
||||||
ja .done
|
ja .done
|
||||||
inc rbx
|
inc rbx
|
||||||
|
|
@ -1349,14 +1346,14 @@ try_parse_mem:
|
||||||
mov edi, dword [rbx]
|
mov edi, dword [rbx]
|
||||||
|
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
mov dword [r12 + operand.size], 2 ; 16-bit
|
mov dword [r12 + operand.size], 2 ; 32-bit
|
||||||
cmp dl, 'q'
|
cmp dl, 'q'
|
||||||
sete al
|
sete al
|
||||||
cmp dl, 'd'
|
cmp dl, 'd'
|
||||||
sete dl
|
sete dl
|
||||||
or al, dl
|
or dl, al
|
||||||
jz .not_mem
|
jz .not_mem
|
||||||
add dword [r12 + operand.size], eax ; 32-bit?
|
add dword [r12 + operand.size], eax ; 64-bit?
|
||||||
|
|
||||||
cmp edi, 'word'
|
cmp edi, 'word'
|
||||||
jne .not_mem
|
jne .not_mem
|
||||||
|
|
@ -1512,6 +1509,8 @@ try_parse_operand:
|
||||||
mov dword [r12 + operand.disp], 0
|
mov dword [r12 + operand.disp], 0
|
||||||
|
|
||||||
mov al, byte [rbx]
|
mov al, byte [rbx]
|
||||||
|
test al, al
|
||||||
|
jz .done
|
||||||
cmp al, '['
|
cmp al, '['
|
||||||
je .mem
|
je .mem
|
||||||
cmp al, `'`
|
cmp al, `'`
|
||||||
|
|
@ -1533,10 +1532,10 @@ try_parse_operand:
|
||||||
bsr rcx, rdx ; # of bits required to represent the immediate
|
bsr rcx, rdx ; # of bits required to represent the immediate
|
||||||
mov edx, ecx
|
mov edx, ecx
|
||||||
|
|
||||||
cmp edx, 1
|
shr edx, 3 ; divide by 8 to get the number of bytes required
|
||||||
adc edx, -1 ; saturating sub
|
jz .done
|
||||||
|
|
||||||
bsr edx, edx ; log2 of the (# of bits - 1) + 1
|
bsr edx, edx ; log2 of the (# of bytes) + 1
|
||||||
inc edx
|
inc edx
|
||||||
|
|
||||||
cmp ecx, 2
|
cmp ecx, 2
|
||||||
|
|
@ -1614,6 +1613,7 @@ try_parse_label:
|
||||||
pop rbx
|
pop rbx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; Instruction
|
||||||
|
|
||||||
struc Instruction
|
struc Instruction
|
||||||
.mnemonic_offs resd 1
|
.mnemonic_offs resd 1
|
||||||
|
|
@ -1633,6 +1633,8 @@ try_parse_inst:
|
||||||
|
|
||||||
mov dword [r13 + Instruction.num_operands], 0
|
mov dword [r13 + Instruction.num_operands], 0
|
||||||
mov dword [r13 + Instruction.mnemonic_offs], 0
|
mov dword [r13 + Instruction.mnemonic_offs], 0
|
||||||
|
mov qword [r13 + Instruction.operand1], 0
|
||||||
|
mov qword [r13 + Instruction.operand2], 0
|
||||||
|
|
||||||
call skip_whitespace_rbx
|
call skip_whitespace_rbx
|
||||||
mov rdi, rbx
|
mov rdi, rbx
|
||||||
|
|
@ -1697,7 +1699,6 @@ try_parse_inst:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; find the op_table entry returning the pointer to the entry in $rax, or 0 if not found.
|
;; find the op_table entry returning the pointer to the entry in $rax, or 0 if not found.
|
||||||
;; inputs:
|
;; inputs:
|
||||||
;; $edi: mnemonic offset
|
;; $edi: mnemonic offset
|
||||||
|
|
@ -1728,10 +1729,15 @@ find_op_table_entry:
|
||||||
jne .next
|
jne .next
|
||||||
|
|
||||||
mov r8d, dword [rax + 16] ; encoding
|
mov r8d, dword [rax + 16] ; encoding
|
||||||
|
cmp r8d, esi
|
||||||
|
je .found
|
||||||
mov r9d, esi
|
mov r9d, esi
|
||||||
|
test r8d, 0xff00
|
||||||
|
jz .enc1
|
||||||
and r9d, 0xff00
|
and r9d, 0xff00
|
||||||
and r9d, r8d
|
and r9d, r8d
|
||||||
jz .next
|
jz .next
|
||||||
|
.enc1:
|
||||||
mov r9d, esi
|
mov r9d, esi
|
||||||
and r9d, 0xff
|
and r9d, 0xff
|
||||||
and r9d, r8d
|
and r9d, r8d
|
||||||
|
|
@ -1754,7 +1760,7 @@ encode_inst:
|
||||||
push r12
|
push r12
|
||||||
push r13
|
push r13
|
||||||
|
|
||||||
xor ebx, ebx ; bytes written
|
mov rbx, rsi ; bytes written
|
||||||
mov r12, rdi ; inst ptr
|
mov r12, rdi ; inst ptr
|
||||||
|
|
||||||
; calculate the encoding
|
; calculate the encoding
|
||||||
|
|
@ -1766,7 +1772,7 @@ encode_inst:
|
||||||
|
|
||||||
; calculate size mask of op2.
|
; calculate size mask of op2.
|
||||||
; for reg and mem operands, this is 1 << .size.
|
; 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 ecx, dword [r12 + Instruction.operand2 + operand.size]
|
||||||
mov eax, 1
|
mov eax, 1
|
||||||
shl eax, cl
|
shl eax, cl
|
||||||
|
|
@ -1774,9 +1780,9 @@ encode_inst:
|
||||||
cmp dword [r12 + Instruction.operand2 + operand.type], KIND_IMM
|
cmp dword [r12 + Instruction.operand2 + operand.type], KIND_IMM
|
||||||
jne .size_done_op2
|
jne .size_done_op2
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
lea ecx, [ecx - 1]
|
|
||||||
sub eax, 1
|
sub eax, 1
|
||||||
shl eax, cl
|
shl eax, cl
|
||||||
|
and eax, 0xf
|
||||||
|
|
||||||
.size_done_op2:
|
.size_done_op2:
|
||||||
shl eax, 8
|
shl eax, 8
|
||||||
|
|
@ -1802,16 +1808,16 @@ encode_inst:
|
||||||
|
|
||||||
; calculate size mask of op1.
|
; calculate size mask of op1.
|
||||||
; for reg and mem operands, this is 1 << .size.
|
; 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 ecx, dword [r12 + Instruction.operand1 + operand.size]
|
||||||
mov edx, 1
|
mov edx, 1
|
||||||
shl edx, cl
|
shl edx, cl
|
||||||
cmp dword [r12 + Instruction.operand1 + operand.type], KIND_IMM
|
cmp dword [r12 + Instruction.operand1 + operand.type], KIND_IMM
|
||||||
jne .size_done
|
jne .size_done
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
lea ecx, [ecx - 1]
|
|
||||||
sub edx, 1
|
sub edx, 1
|
||||||
shl edx, cl
|
shl edx, cl
|
||||||
|
and edx, 0xf
|
||||||
.size_done:
|
.size_done:
|
||||||
xor edx, eax
|
xor edx, eax
|
||||||
|
|
||||||
|
|
@ -1822,8 +1828,13 @@ encode_inst:
|
||||||
jz .done
|
jz .done
|
||||||
mov r13, rax ; pointer to the op_table entry
|
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
|
; write the prefix, if any
|
||||||
cmp dword [r13 + 24], 0
|
cmp dword [r13 + OpEntry.prefix], 0
|
||||||
je .rex
|
je .rex
|
||||||
|
|
||||||
movzx edi, byte [r13 + 24]
|
movzx edi, byte [r13 + 24]
|
||||||
|
|
@ -1868,6 +1879,9 @@ encode_inst:
|
||||||
mov edi, dword [r13 + OpEntry.opcode]
|
mov edi, dword [r13 + OpEntry.opcode]
|
||||||
call write_opcode_with_bits
|
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
|
test dword [r13 + OpEntry.encoding], ENC_O_SIGNAL_BITS | ENC_O_SIGNAL_BITS << 8
|
||||||
jnz .imm
|
jnz .imm
|
||||||
|
|
||||||
|
|
@ -1884,48 +1898,68 @@ encode_inst:
|
||||||
call write_non_zero_bytes
|
call write_non_zero_bytes
|
||||||
|
|
||||||
pop rax
|
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
|
shr eax, 6
|
||||||
dec eax
|
dec eax
|
||||||
cmp eax, 2
|
cmp eax, 2
|
||||||
jge .imm
|
jae .imm
|
||||||
mov rdi, qword [rsp + 8]
|
mov rdi, qword [rsp + 8]
|
||||||
mov edi, dword [rdi + operand.disp]
|
mov edi, dword [rdi + operand.disp]
|
||||||
call write_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:
|
.imm:
|
||||||
|
xor eax, eax ; clear return
|
||||||
mov rdi, qword [rsp]
|
mov rdi, qword [rsp]
|
||||||
mov rsi, qword [rsp + 8]
|
mov rsi, qword [rsp + 8]
|
||||||
add rsp, 16
|
|
||||||
; write immediate, if any
|
; write immediate, if any
|
||||||
cmp dword [rsi + operand.type], KIND_IMM
|
test dword [rsi + operand.type], KIND_IMM
|
||||||
je .imm1
|
jnz .imm1
|
||||||
mov rsi, rdi
|
mov rsi, rdi
|
||||||
cmp dword [rsi + operand.type], KIND_IMM
|
test dword [rsi + operand.type], KIND_IMM
|
||||||
jne .done
|
jz .ref
|
||||||
|
|
||||||
.imm1:
|
.imm1:
|
||||||
push rsi
|
push rsi
|
||||||
test dword [rsi + operand.type], KIND_LABEL_FLAG
|
test dword [rsi + operand.type], KIND_LABEL_FLAG
|
||||||
jz .imm2
|
jz .imm2
|
||||||
|
|
||||||
mov edi, dword [rsi + operand.disp]
|
mov edi, dword [rsi + operand_imm.imm] ; hash
|
||||||
mov rsi, rbx
|
mov rsi, rbx ; write offset
|
||||||
|
lea rdx, [rbx + 4] ; disp offset (after the imm32 is written)
|
||||||
call push_lbl_ref_by_hash
|
call push_lbl_ref_by_hash
|
||||||
|
|
||||||
.imm2:
|
.imm2:
|
||||||
pop rsi
|
pop rsi
|
||||||
mov rdi, qword [rsi + operand_imm.imm]
|
mov rdi, qword [rsi + operand_imm.imm]
|
||||||
mov esi, dword [r13 + OpEntry.op2_size]
|
mov esi, dword [rsi + operand.size]
|
||||||
call write_imm
|
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:
|
.done:
|
||||||
mov rax, rbx ; bytes written
|
mov rax, rbx ; bytes written
|
||||||
pop r13
|
pop r13
|
||||||
|
|
@ -1945,19 +1979,27 @@ write_disp:
|
||||||
jmp write_bytes
|
jmp write_bytes
|
||||||
|
|
||||||
write_bytes:
|
write_bytes:
|
||||||
call print_u8s_le
|
push rdi
|
||||||
|
lea rdi, [rsp]
|
||||||
|
call ofile_write_bytes
|
||||||
add rbx, rax
|
add rbx, rax
|
||||||
|
pop rdi
|
||||||
ret
|
ret
|
||||||
|
|
||||||
write_opcode_with_bits:
|
write_opcode_with_bits:
|
||||||
call swap_bytes_and_shift_in_place
|
|
||||||
or rdi, rsi
|
or rdi, rsi
|
||||||
|
call swap_bytes_and_shift_in_place
|
||||||
jmp write_non_zero_bytes
|
jmp write_non_zero_bytes
|
||||||
|
|
||||||
;; writes the contents of the $rdi register until the first zero byte.
|
;; writes the contents of the $rdi register until the first zero byte.
|
||||||
write_non_zero_bytes:
|
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
|
add rbx, rax
|
||||||
|
pop rdi
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;; compute the modRM and SIB bytes for the operands $rdi and $rsi, in reg-mem order, with the $rdx reg-bits
|
;; 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
|
je .done_mem
|
||||||
and eax, 0x37 ; clear mod bits, mod = 00b
|
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
|
test dword [rsi + operand.type], KIND_MEM
|
||||||
jz .done_mem
|
jz .done_mem
|
||||||
|
|
||||||
cmp dword [rsi + operand.disp], 0
|
cmp dword [rsi + operand.disp], 0
|
||||||
jne .sib ; mod = 01b or 10b
|
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
|
mov ecx, eax
|
||||||
and ecx, 7
|
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
|
cmp ecx, 5
|
||||||
jne .done_mem
|
jne .done_mem
|
||||||
|
|
||||||
|
|
@ -2005,16 +2056,16 @@ compute_modrm_sib:
|
||||||
shl edx, 6 ; mod = 01b or 10b
|
shl edx, 6 ; mod = 01b or 10b
|
||||||
or eax, edx
|
or eax, edx
|
||||||
|
|
||||||
|
.sib_no_disp:
|
||||||
xor edx, edx ; sib
|
xor edx, edx ; sib
|
||||||
; copy r/m bits to SIB base bits
|
; copy r/m bits to SIB base bits
|
||||||
mov edx, eax
|
mov edx, eax
|
||||||
shr edx, 3
|
|
||||||
and edx, 7
|
and edx, 7
|
||||||
|
|
||||||
and eax, 0b11000111 ; clear the r/m bits
|
and eax, 0b11111000 ; clear the r/m bits
|
||||||
or eax, 0b00100000 ; set the r/m bits to 100b (SIB follows)
|
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]
|
mov ecx, dword [rsi + operand.scale]
|
||||||
and ecx, 3
|
and ecx, 3
|
||||||
|
|
@ -2032,8 +2083,6 @@ compute_modrm_sib:
|
||||||
.done_mem:
|
.done_mem:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; compute the rex bits for the operands $rdi and $rsi, in reg-mem order
|
;; compute the rex bits for the operands $rdi and $rsi, in reg-mem order
|
||||||
compute_rex:
|
compute_rex:
|
||||||
|
|
@ -2048,7 +2097,7 @@ compute_rex:
|
||||||
shl dl, 2 ; REX.R
|
shl dl, 2 ; REX.R
|
||||||
or al, dl
|
or al, dl
|
||||||
|
|
||||||
cmp dword [rdi + operand.size], 3
|
cmp dword [rdi + operand.size], 8 ; this is no longer in log2 form
|
||||||
setnb dl
|
setnb dl
|
||||||
shl dl, 3 ; REX.W
|
shl dl, 3 ; REX.W
|
||||||
or al, dl
|
or al, dl
|
||||||
|
|
@ -2063,7 +2112,7 @@ compute_rex:
|
||||||
setne dl
|
setne dl
|
||||||
or al, dl ; REX.B
|
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
|
setnb dl
|
||||||
shl dl, 3 ; REX.W
|
shl dl, 3 ; REX.W
|
||||||
or al, dl
|
or al, dl
|
||||||
|
|
@ -2088,9 +2137,195 @@ compute_rex:
|
||||||
ret
|
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 buffer $rdi, bytes written in $rsi, return updated bytes written.
|
||||||
parse_line:
|
parse_line:
|
||||||
|
|
@ -2107,14 +2342,15 @@ parse_line:
|
||||||
|
|
||||||
mov rdi, rbx
|
mov rdi, rbx
|
||||||
sub rsp, 72
|
sub rsp, 72
|
||||||
mov rsi, rsp
|
lea rsi, [rsp]
|
||||||
call try_parse_inst
|
call try_parse_inst
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz .done_inst
|
jz .done_inst
|
||||||
|
|
||||||
lea rdi, [rsp]
|
lea rdi, [rsp]
|
||||||
|
mov rsi, r12
|
||||||
call encode_inst
|
call encode_inst
|
||||||
add r12, rax
|
mov r12, rax
|
||||||
|
|
||||||
.done_inst:
|
.done_inst:
|
||||||
add rsp, 72
|
add rsp, 72
|
||||||
|
|
@ -2142,22 +2378,80 @@ parse_line:
|
||||||
|
|
||||||
;; Labels
|
;; 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
|
struc Label
|
||||||
.name_hash resd 1
|
.name_hash resd 1
|
||||||
.offset resd 1
|
.offset resd 1
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
struc LabelTable
|
struc LabelRef
|
||||||
.size resd 1
|
.name_hash resd 1
|
||||||
.cap resd 1
|
.write_offset resd 1
|
||||||
.labels resq 1
|
.disp_offset resd 1
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
section .data
|
section .data
|
||||||
labels dq 0, 0
|
labels dq 0, 0, 0
|
||||||
label_refs dq 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
|
;; calculates the hash of a byte sequence in $rdi of length $rsi, returning it in $eax
|
||||||
global fasthash
|
global fasthash
|
||||||
fasthash:
|
fasthash:
|
||||||
|
|
@ -2177,80 +2471,112 @@ fasthash:
|
||||||
global init_label_tables
|
global init_label_tables
|
||||||
init_label_tables:
|
init_label_tables:
|
||||||
mov edi, 0x100
|
mov edi, 0x100
|
||||||
mov esi, 8
|
mov esi, 4
|
||||||
call heap_alloc
|
call heap_alloc
|
||||||
lea rdi, [rel labels]
|
lea rdi, [rel labels]
|
||||||
mov dword [rdi + LabelTable.size], 0
|
mov dword [rdi + Vec.size], 0
|
||||||
mov dword [rdi + LabelTable.cap], 0x100 / 8
|
mov dword [rdi + Vec.cap], 0x100 / Label_size
|
||||||
mov qword [rdi + LabelTable.labels], rax
|
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 edi, 0x180
|
||||||
mov esi, 8
|
mov esi, 4
|
||||||
call heap_alloc
|
call heap_alloc
|
||||||
lea rdi, [rel label_refs]
|
lea rdi, [rel label_refs]
|
||||||
mov dword [rdi + LabelTable.size], 0
|
mov dword [rdi + Vec.size], 0
|
||||||
mov dword [rdi + LabelTable.cap], 0x100 / 8
|
mov dword [rdi + Vec.cap], 0x180 / LabelRef_size
|
||||||
mov qword [rdi + LabelTable.labels], rax
|
mov dword [rdi + Vec.ele_size], LabelRef_size
|
||||||
|
mov dword [rdi + Vec.ele_align], 4
|
||||||
|
mov qword [rdi + Vec.data], rax
|
||||||
|
|
||||||
ret
|
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_lbl_ref_by_hash:
|
||||||
push rbx
|
push rbx
|
||||||
push r12
|
push r12
|
||||||
push r13
|
push r13
|
||||||
|
push r14
|
||||||
|
|
||||||
lea rbx, [rel label_refs]
|
lea rbx, [rel label_refs]
|
||||||
mov r13d, esi ; label offset
|
mov r13d, esi ; label write offset
|
||||||
mov r12d, edi ; label hash
|
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:
|
push_lbl_ref:
|
||||||
lea rcx, [rel label_refs]
|
push rbx
|
||||||
jmp push_lbl_common
|
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 label $rdi with length $rsi and offset $edx into the label table
|
||||||
push_lbl:
|
push_lbl:
|
||||||
lea rcx, [rel labels]
|
|
||||||
push_lbl_common:
|
|
||||||
push rbx
|
push rbx
|
||||||
push r12
|
push r12
|
||||||
push r13
|
push r13
|
||||||
|
|
||||||
mov rbx, rcx
|
lea rbx, [rel labels]
|
||||||
mov r13d, edx ; label offset
|
mov r13d, edx ; label offset
|
||||||
|
|
||||||
call fasthash
|
call fasthash
|
||||||
mov r12d, eax ; store the hash in r12d
|
mov r12d, eax ; hash
|
||||||
.hash_in_r12d:
|
|
||||||
|
|
||||||
mov eax, dword [rbx + LabelTable.size]
|
mov rdi, rbx
|
||||||
cmp eax, dword [rbx + LabelTable.cap]
|
mov rsi, 1
|
||||||
jl .has_space
|
call vec_reserve
|
||||||
|
|
||||||
mov rdi, qword [rbx + LabelTable.labels]
|
mov rdi, rbx
|
||||||
mov esi, dword [rbx + LabelTable.cap]
|
mov esi, dword [rbx + Vec.size]
|
||||||
mov edx, 8
|
call vec_get_nth
|
||||||
mov ecx, esi
|
|
||||||
shl ecx, 1
|
|
||||||
call heap_realloc
|
|
||||||
mov qword [rbx + LabelTable.labels], rax
|
|
||||||
shl dword [rbx + LabelTable.cap], 1
|
|
||||||
|
|
||||||
.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.name_hash], r12d
|
||||||
mov dword [rax + Label.offset], r13d
|
mov dword [rax + Label.offset], r13d
|
||||||
inc dword [rbx + LabelTable.size]
|
inc dword [rbx + Vec.size]
|
||||||
|
|
||||||
pop r13
|
pop r13
|
||||||
pop r12
|
pop r12
|
||||||
pop rbx
|
pop rbx
|
||||||
ret
|
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:
|
find_lbl:
|
||||||
push rbx
|
push rbx
|
||||||
push r12
|
push r12
|
||||||
|
|
@ -2261,12 +2587,13 @@ find_lbl:
|
||||||
call fasthash
|
call fasthash
|
||||||
mov r12d, eax ; store the hash in r12d
|
mov r12d, eax ; store the hash in r12d
|
||||||
|
|
||||||
|
.by_hash:
|
||||||
xor r13d, r13d
|
xor r13d, r13d
|
||||||
.loop:
|
.loop:
|
||||||
cmp r13d, dword [rbx + LabelTable.size]
|
cmp r13d, dword [rbx + Vec.size]
|
||||||
jge .not_found
|
jge .not_found
|
||||||
|
|
||||||
mov rax, qword [rbx + LabelTable.labels]
|
mov rax, qword [rbx + Vec.data]
|
||||||
lea rax, [rax + r13 * 8]
|
lea rax, [rax + r13 * 8]
|
||||||
cmp dword [rax + Label.name_hash], r12d
|
cmp dword [rax + Label.name_hash], r12d
|
||||||
je .found
|
je .found
|
||||||
|
|
@ -2276,14 +2603,121 @@ find_lbl:
|
||||||
mov eax, dword [rax + Label.offset]
|
mov eax, dword [rax + Label.offset]
|
||||||
jmp .done
|
jmp .done
|
||||||
.not_found:
|
.not_found:
|
||||||
xor rax, rax
|
mov rax, -1
|
||||||
.done:
|
.done:
|
||||||
pop r13
|
pop r13
|
||||||
pop r12
|
pop r12
|
||||||
pop rbx
|
pop rbx
|
||||||
ret
|
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
|
global _entry_print_table
|
||||||
_entry_print_table:
|
_entry_print_table:
|
||||||
call print_op_table
|
call print_op_table
|
||||||
call exit
|
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