|
|
|
|
@ -2,8 +2,16 @@
|
|
|
|
|
;; 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
|
|
|
|
|
@ -41,8 +49,8 @@ mnemonics:
|
|
|
|
|
mnemonics_table:
|
|
|
|
|
MN_MOV db "mov", 0
|
|
|
|
|
MN_TEST db "test", 0
|
|
|
|
|
MN_OR db "or", 0
|
|
|
|
|
MN_XOR db "xor", 0
|
|
|
|
|
MN_OR db "or", 0
|
|
|
|
|
MN_AND db "and", 0
|
|
|
|
|
MN_SHL db "shl", 0
|
|
|
|
|
MN_SHR db "shr", 0
|
|
|
|
|
@ -398,6 +406,7 @@ op_table_end:
|
|
|
|
|
section .text
|
|
|
|
|
|
|
|
|
|
panic_abort:
|
|
|
|
|
mov rdi, 1
|
|
|
|
|
mov rax, 60
|
|
|
|
|
syscall
|
|
|
|
|
|
|
|
|
|
@ -858,9 +867,6 @@ print_op_table:
|
|
|
|
|
pop rbx
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Common Library Functions
|
|
|
|
|
|
|
|
|
|
;; rdi: *u8
|
|
|
|
|
strlen:
|
|
|
|
|
xor rax, rax
|
|
|
|
|
@ -1030,7 +1036,6 @@ to_digit:
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
exit:
|
|
|
|
|
xor edi, edi
|
|
|
|
|
mov rax, 60
|
|
|
|
|
syscall
|
|
|
|
|
|
|
|
|
|
@ -1300,8 +1305,6 @@ try_parse_num:
|
|
|
|
|
|
|
|
|
|
skip_whitespace_rbx:
|
|
|
|
|
mov al, byte [rbx]
|
|
|
|
|
test al, al
|
|
|
|
|
jz .done
|
|
|
|
|
cmp al, ' '
|
|
|
|
|
ja .done
|
|
|
|
|
inc rbx
|
|
|
|
|
@ -1346,14 +1349,14 @@ try_parse_mem:
|
|
|
|
|
mov edi, dword [rbx]
|
|
|
|
|
|
|
|
|
|
xor eax, eax
|
|
|
|
|
mov dword [r12 + operand.size], 2 ; 32-bit
|
|
|
|
|
mov dword [r12 + operand.size], 2 ; 16-bit
|
|
|
|
|
cmp dl, 'q'
|
|
|
|
|
sete al
|
|
|
|
|
cmp dl, 'd'
|
|
|
|
|
sete dl
|
|
|
|
|
or dl, al
|
|
|
|
|
or al, dl
|
|
|
|
|
jz .not_mem
|
|
|
|
|
add dword [r12 + operand.size], eax ; 64-bit?
|
|
|
|
|
add dword [r12 + operand.size], eax ; 32-bit?
|
|
|
|
|
|
|
|
|
|
cmp edi, 'word'
|
|
|
|
|
jne .not_mem
|
|
|
|
|
@ -1509,8 +1512,6 @@ try_parse_operand:
|
|
|
|
|
mov dword [r12 + operand.disp], 0
|
|
|
|
|
|
|
|
|
|
mov al, byte [rbx]
|
|
|
|
|
test al, al
|
|
|
|
|
jz .done
|
|
|
|
|
cmp al, '['
|
|
|
|
|
je .mem
|
|
|
|
|
cmp al, `'`
|
|
|
|
|
@ -1532,10 +1533,10 @@ try_parse_operand:
|
|
|
|
|
bsr rcx, rdx ; # of bits required to represent the immediate
|
|
|
|
|
mov edx, ecx
|
|
|
|
|
|
|
|
|
|
shr edx, 3 ; divide by 8 to get the number of bytes required
|
|
|
|
|
jz .done
|
|
|
|
|
cmp edx, 1
|
|
|
|
|
adc edx, -1 ; saturating sub
|
|
|
|
|
|
|
|
|
|
bsr edx, edx ; log2 of the (# of bytes) + 1
|
|
|
|
|
bsr edx, edx ; log2 of the (# of bits - 1) + 1
|
|
|
|
|
inc edx
|
|
|
|
|
|
|
|
|
|
cmp ecx, 2
|
|
|
|
|
@ -1613,7 +1614,6 @@ try_parse_label:
|
|
|
|
|
pop rbx
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
;; Instruction
|
|
|
|
|
|
|
|
|
|
struc Instruction
|
|
|
|
|
.mnemonic_offs resd 1
|
|
|
|
|
@ -1633,8 +1633,6 @@ 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
|
|
|
|
|
@ -1699,6 +1697,7 @@ 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
|
|
|
|
|
@ -1729,15 +1728,10 @@ 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
|
|
|
|
|
@ -1760,7 +1754,7 @@ encode_inst:
|
|
|
|
|
push r12
|
|
|
|
|
push r13
|
|
|
|
|
|
|
|
|
|
mov rbx, rsi ; bytes written
|
|
|
|
|
xor ebx, ebx ; bytes written
|
|
|
|
|
mov r12, rdi ; inst ptr
|
|
|
|
|
|
|
|
|
|
; calculate the encoding
|
|
|
|
|
@ -1772,7 +1766,7 @@ encode_inst:
|
|
|
|
|
|
|
|
|
|
; calculate size mask of op2.
|
|
|
|
|
; for reg and mem operands, this is 1 << .size.
|
|
|
|
|
; for imm operands, this is (!0 << .size) && 0xff
|
|
|
|
|
; for imm operands, this is !(!0 << .size)
|
|
|
|
|
mov ecx, dword [r12 + Instruction.operand2 + operand.size]
|
|
|
|
|
mov eax, 1
|
|
|
|
|
shl eax, cl
|
|
|
|
|
@ -1780,9 +1774,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
|
|
|
|
|
@ -1808,16 +1802,16 @@ encode_inst:
|
|
|
|
|
|
|
|
|
|
; calculate size mask of op1.
|
|
|
|
|
; for reg and mem operands, this is 1 << .size.
|
|
|
|
|
; for imm operands, this is (!0 << .size) & 0xf
|
|
|
|
|
; for imm operands, this is !(!0 << .size)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
@ -1828,13 +1822,8 @@ 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 + OpEntry.prefix], 0
|
|
|
|
|
cmp dword [r13 + 24], 0
|
|
|
|
|
je .rex
|
|
|
|
|
|
|
|
|
|
movzx edi, byte [r13 + 24]
|
|
|
|
|
@ -1879,9 +1868,6 @@ 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
|
|
|
|
|
|
|
|
|
|
@ -1898,68 +1884,48 @@ 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
|
|
|
|
|
shl eax, 6
|
|
|
|
|
dec eax
|
|
|
|
|
cmp eax, 2
|
|
|
|
|
jae .imm
|
|
|
|
|
jge .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
|
|
|
|
|
test dword [rsi + operand.type], KIND_IMM
|
|
|
|
|
jnz .imm1
|
|
|
|
|
cmp dword [rsi + operand.type], KIND_IMM
|
|
|
|
|
je .imm1
|
|
|
|
|
mov rsi, rdi
|
|
|
|
|
test dword [rsi + operand.type], KIND_IMM
|
|
|
|
|
jz .ref
|
|
|
|
|
cmp dword [rsi + operand.type], KIND_IMM
|
|
|
|
|
jne .done
|
|
|
|
|
|
|
|
|
|
.imm1:
|
|
|
|
|
push rsi
|
|
|
|
|
test dword [rsi + operand.type], KIND_LABEL_FLAG
|
|
|
|
|
jz .imm2
|
|
|
|
|
|
|
|
|
|
mov edi, dword [rsi + operand_imm.imm] ; hash
|
|
|
|
|
mov rsi, rbx ; write offset
|
|
|
|
|
lea rdx, [rbx + 4] ; disp offset (after the imm32 is written)
|
|
|
|
|
mov edi, dword [rsi + operand.disp]
|
|
|
|
|
mov rsi, rbx
|
|
|
|
|
call push_lbl_ref_by_hash
|
|
|
|
|
|
|
|
|
|
.imm2:
|
|
|
|
|
pop rsi
|
|
|
|
|
mov rdi, qword [rsi + operand_imm.imm]
|
|
|
|
|
mov esi, dword [rsi + operand.size]
|
|
|
|
|
mov esi, dword [r13 + OpEntry.op2_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
|
|
|
|
|
@ -1971,35 +1937,27 @@ write_imm:
|
|
|
|
|
jmp write_bytes
|
|
|
|
|
|
|
|
|
|
write_disp:
|
|
|
|
|
cmp edi, 0xff ; if disp > 0xff, write 4 bytes, else write 1 byte
|
|
|
|
|
cmp edi, 0xff
|
|
|
|
|
seta sil
|
|
|
|
|
movzx esi, sil
|
|
|
|
|
lea esi, [rsi + rsi * 2]
|
|
|
|
|
inc esi
|
|
|
|
|
shl sil, 1
|
|
|
|
|
inc sil
|
|
|
|
|
movzx rsi, sil
|
|
|
|
|
jmp write_bytes
|
|
|
|
|
|
|
|
|
|
write_bytes:
|
|
|
|
|
push rdi
|
|
|
|
|
lea rdi, [rsp]
|
|
|
|
|
call ofile_write_bytes
|
|
|
|
|
call print_u8s_le
|
|
|
|
|
add rbx, rax
|
|
|
|
|
pop rdi
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
write_opcode_with_bits:
|
|
|
|
|
or rdi, rsi
|
|
|
|
|
call swap_bytes_and_shift_in_place
|
|
|
|
|
or rdi, rsi
|
|
|
|
|
jmp write_non_zero_bytes
|
|
|
|
|
|
|
|
|
|
;; writes the contents of the $rdi register until the first zero byte.
|
|
|
|
|
write_non_zero_bytes:
|
|
|
|
|
push rdi
|
|
|
|
|
lea rdi, [rsp]
|
|
|
|
|
call strlen
|
|
|
|
|
mov esi, eax
|
|
|
|
|
call ofile_write_bytes
|
|
|
|
|
call print_non_zero_u8s_le
|
|
|
|
|
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
|
|
|
|
|
@ -2028,23 +1986,14 @@ 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.type], KIND_MEM
|
|
|
|
|
jne .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
|
|
|
|
|
|
|
|
|
|
@ -2056,16 +2005,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, 0b11111000 ; clear the r/m bits
|
|
|
|
|
or eax, 0b00000100 ; set the r/m bits to 100b (SIB follows)
|
|
|
|
|
and eax, 0b11000111 ; clear the r/m bits
|
|
|
|
|
or eax, 0b00100000 ; set the r/m bits to 100b (SIB follows)
|
|
|
|
|
|
|
|
|
|
or edx, 0b00100000 ; index = 100b (no index)
|
|
|
|
|
mov edx, 0b00100000 ; index = 100b (no index)
|
|
|
|
|
|
|
|
|
|
mov ecx, dword [rsi + operand.scale]
|
|
|
|
|
and ecx, 3
|
|
|
|
|
@ -2074,7 +2023,7 @@ compute_modrm_sib:
|
|
|
|
|
|
|
|
|
|
mov ecx, dword [rsi + operand.index + register.num]
|
|
|
|
|
cmp ecx, -1
|
|
|
|
|
je .done_mem
|
|
|
|
|
jne .done_mem
|
|
|
|
|
|
|
|
|
|
and ecx, 7
|
|
|
|
|
shl ecx, 3 ; index bits
|
|
|
|
|
@ -2084,6 +2033,8 @@ compute_modrm_sib:
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; compute the rex bits for the operands $rdi and $rsi, in reg-mem order
|
|
|
|
|
compute_rex:
|
|
|
|
|
xor eax, eax
|
|
|
|
|
@ -2097,7 +2048,7 @@ compute_rex:
|
|
|
|
|
shl dl, 2 ; REX.R
|
|
|
|
|
or al, dl
|
|
|
|
|
|
|
|
|
|
cmp dword [rdi + operand.size], 8 ; this is no longer in log2 form
|
|
|
|
|
cmp dword [rdi + operand.size], 3
|
|
|
|
|
setnb dl
|
|
|
|
|
shl dl, 3 ; REX.W
|
|
|
|
|
or al, dl
|
|
|
|
|
@ -2112,7 +2063,7 @@ compute_rex:
|
|
|
|
|
setne dl
|
|
|
|
|
or al, dl ; REX.B
|
|
|
|
|
|
|
|
|
|
cmp dword [rsi + operand.size], 8 ; this is no longer in log2 form
|
|
|
|
|
cmp dword [rsi + operand.size], 3
|
|
|
|
|
setnb dl
|
|
|
|
|
shl dl, 3 ; REX.W
|
|
|
|
|
or al, dl
|
|
|
|
|
@ -2137,195 +2088,9 @@ 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:
|
|
|
|
|
@ -2342,15 +2107,14 @@ parse_line:
|
|
|
|
|
|
|
|
|
|
mov rdi, rbx
|
|
|
|
|
sub rsp, 72
|
|
|
|
|
lea rsi, [rsp]
|
|
|
|
|
mov rsi, rsp
|
|
|
|
|
call try_parse_inst
|
|
|
|
|
test eax, eax
|
|
|
|
|
jz .done_inst
|
|
|
|
|
|
|
|
|
|
lea rdi, [rsp]
|
|
|
|
|
mov rsi, r12
|
|
|
|
|
call encode_inst
|
|
|
|
|
mov r12, rax
|
|
|
|
|
add r12, rax
|
|
|
|
|
|
|
|
|
|
.done_inst:
|
|
|
|
|
add rsp, 72
|
|
|
|
|
@ -2378,80 +2142,22 @@ 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 LabelRef
|
|
|
|
|
.name_hash resd 1
|
|
|
|
|
.write_offset resd 1
|
|
|
|
|
.disp_offset resd 1
|
|
|
|
|
struc LabelTable
|
|
|
|
|
.size resd 1
|
|
|
|
|
.cap resd 1
|
|
|
|
|
.labels resq 1
|
|
|
|
|
endstruc
|
|
|
|
|
|
|
|
|
|
section .data
|
|
|
|
|
labels dq 0, 0, 0
|
|
|
|
|
label_refs dq 0, 0, 0
|
|
|
|
|
labels dq 0
|
|
|
|
|
label_refs dq 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; calculates the hash of a byte sequence in $rdi of length $rsi, returning it in $eax
|
|
|
|
|
global fasthash
|
|
|
|
|
fasthash:
|
|
|
|
|
@ -2468,132 +2174,98 @@ fasthash:
|
|
|
|
|
.done:
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
global init_label_tables
|
|
|
|
|
init_label_tables:
|
|
|
|
|
mov edi, 0x100
|
|
|
|
|
mov esi, 4
|
|
|
|
|
mov esi, 8
|
|
|
|
|
call heap_alloc
|
|
|
|
|
lea rdi, [rel labels]
|
|
|
|
|
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 dword [rdi + LabelTable.size], 0
|
|
|
|
|
mov dword [rdi + LabelTable.cap], 0x100 / 8
|
|
|
|
|
mov qword [rdi + LabelTable.labels], rax
|
|
|
|
|
|
|
|
|
|
mov edi, 0x180
|
|
|
|
|
mov esi, 4
|
|
|
|
|
mov edi, 0x100
|
|
|
|
|
mov esi, 8
|
|
|
|
|
call heap_alloc
|
|
|
|
|
lea rdi, [rel label_refs]
|
|
|
|
|
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
|
|
|
|
|
mov dword [rdi + LabelTable.size], 0
|
|
|
|
|
mov dword [rdi + LabelTable.cap], 0x100 / 8
|
|
|
|
|
mov qword [rdi + LabelTable.labels], rax
|
|
|
|
|
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
;; push label hash $edi with write offset $esi and disp offset $edx into the label ref table.
|
|
|
|
|
;; push label hash $edi with offset $esi 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 write offset
|
|
|
|
|
mov rbx, [rel label_refs]
|
|
|
|
|
mov r13d, esi ; label offset
|
|
|
|
|
mov r12d, edi ; label hash
|
|
|
|
|
mov r14d, edx ; label disp offset
|
|
|
|
|
jmp push_lbl_ref.hash_in_r12d
|
|
|
|
|
jmp push_lbl_common.hash_in_r12d
|
|
|
|
|
|
|
|
|
|
;; push label $rdi with length $rsi, write offset $edx and disp offset $ecx into the label ref table.
|
|
|
|
|
;; push label $rdi with length $rsi and offset $rdx into the label ref table
|
|
|
|
|
push_lbl_ref:
|
|
|
|
|
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
|
|
|
|
|
mov rcx, [rel label_refs]
|
|
|
|
|
jmp push_lbl_common
|
|
|
|
|
|
|
|
|
|
;; push label $rdi with length $rsi and offset $edx into the label table
|
|
|
|
|
push_lbl:
|
|
|
|
|
mov rcx, [rel labels]
|
|
|
|
|
push_lbl_common:
|
|
|
|
|
push rbx
|
|
|
|
|
push r12
|
|
|
|
|
push r13
|
|
|
|
|
|
|
|
|
|
lea rbx, [rel labels]
|
|
|
|
|
mov rbx, rcx
|
|
|
|
|
mov r13d, edx ; label offset
|
|
|
|
|
|
|
|
|
|
call fasthash
|
|
|
|
|
mov r12d, eax ; hash
|
|
|
|
|
mov r12d, eax ; store the hash in r12d
|
|
|
|
|
.hash_in_r12d:
|
|
|
|
|
|
|
|
|
|
mov rdi, rbx
|
|
|
|
|
mov rsi, 1
|
|
|
|
|
call vec_reserve
|
|
|
|
|
mov eax, dword [rbx + LabelTable.size]
|
|
|
|
|
cmp eax, dword [rbx + LabelTable.cap]
|
|
|
|
|
jl .has_space
|
|
|
|
|
|
|
|
|
|
mov rdi, rbx
|
|
|
|
|
mov esi, dword [rbx + Vec.size]
|
|
|
|
|
call vec_get_nth
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
.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 + Vec.size]
|
|
|
|
|
inc dword [rbx + LabelTable.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
|
|
|
|
|
push r13
|
|
|
|
|
|
|
|
|
|
lea rbx, [rel labels]
|
|
|
|
|
mov rbx, [rel labels]
|
|
|
|
|
|
|
|
|
|
call fasthash
|
|
|
|
|
mov r12d, eax ; store the hash in r12d
|
|
|
|
|
|
|
|
|
|
.by_hash:
|
|
|
|
|
xor r13d, r13d
|
|
|
|
|
.loop:
|
|
|
|
|
cmp r13d, dword [rbx + Vec.size]
|
|
|
|
|
cmp r13d, dword [rbx + LabelTable.size]
|
|
|
|
|
jge .not_found
|
|
|
|
|
|
|
|
|
|
mov rax, qword [rbx + Vec.data]
|
|
|
|
|
mov rax, qword [rbx + LabelTable.labels]
|
|
|
|
|
lea rax, [rax + r13 * 8]
|
|
|
|
|
cmp dword [rax + Label.name_hash], r12d
|
|
|
|
|
je .found
|
|
|
|
|
@ -2603,121 +2275,14 @@ find_lbl:
|
|
|
|
|
mov eax, dword [rax + Label.offset]
|
|
|
|
|
jmp .done
|
|
|
|
|
.not_found:
|
|
|
|
|
mov rax, -1
|
|
|
|
|
xor rax, rax
|
|
|
|
|
.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
|
|
|
|
|
|