diff --git a/stages/as0/Makefile b/stages/as0/Makefile index 279ee68..6a886ce 100644 --- a/stages/as0/Makefile +++ b/stages/as0/Makefile @@ -8,5 +8,8 @@ as0.o: as0.asm test: test.bin ./test.bin +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 diff --git a/stages/as0/as0.asm b/stages/as0/as0.asm index 9ead17c..ce50842 100644 --- a/stages/as0/as0.asm +++ b/stages/as0/as0.asm @@ -3,266 +3,558 @@ ;; consume proper mnemonic assembly, rather than hex input. section .bss +global buf buf resb 0x100 labels resb 0x1000 section .data _start_lbl db "_start", 0 -;; supported instructions: -;; mov -;; test -;; xor -;; and -;; shl -;; shr -;; inc -;; dec -;; neg -;; ret -;; not -;; add -;; sub -;; imul -;; cmp -;; lea -;; push, pop -;; cmovcc -;; xchg -;; bts -;; bsf -;; bt + ENC_RM equ 1 + ENC_MR equ 2 + ENC_MI equ 3 + ENC_OI equ 4 + ENC_M equ 5 + ENC_O equ 6 + ENC_I equ 7 + ENC_MC equ 8 ; memory with cl + ENC_M1 equ 9 ; memory with 1 -;; syscall -;; jcc rel32 -;; jmp rel32 -;; call rel32 + OPSIZE_8 equ 1 + OPSIZE_16 equ 2 + OPSIZE_32 equ 4 + OPSIZE_64 equ 8 + +mnt: +mnemonics: +mnemonics_table: + MN_MOV db "mov", 0 + MN_TEST db "test", 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 + MN_INC db "inc", 0 + MN_DEC db "dec", 0 + MN_NEG db "neg", 0 + MN_RET db "ret", 0 + MN_NOT db "not", 0 + MN_ADD db "add", 0 + MN_SUB db "sub", 0 + MN_IMUL db "imul", 0 + MN_IDIV db "idiv", 0 + MN_CMP db "cmp", 0 + MN_LEA db "lea", 0 + MN_PUSH db "push", 0 + MN_POP db "pop", 0 + MN_CMOVE db "cmovz", 0 + MN_CMOVNE db "cmovnz", 0 + MN_CMOVL db "cmovl", 0 + MN_CMOVLE db "cmovle", 0 + MN_CMOVG db "cmovg", 0 + MN_CMOVGE db "cmovge", 0 + MN_CMOVA db "cmova", 0 + MN_CMOVAE db "cmovae", 0 + MN_CMOVB db "cmovb", 0 + MN_CMOVBE db "cmovbe", 0 + MN_SETE db "sete", 0 + MN_SETNE db "setne", 0 + MN_SETL db "setl", 0 + MN_SETLE db "setle", 0 + MN_SETG db "setg", 0 + MN_SETGE db "setge", 0 + MN_SETA db "seta", 0 + MN_SETAE db "setae", 0 + MN_SETB db "setb", 0 + MN_SETBE db "setbe", 0 + MN_JE db "je", 0 + MN_JNE db "jne", 0 + MN_JL db "jl", 0 + MN_JLE db "jle", 0 + MN_JG db "jg", 0 + MN_JGE db "jge", 0 + MN_JA db "ja", 0 + MN_JAE db "jae", 0 + MN_JB db "jb", 0 + MN_JBE db "jbe", 0 + MN_JMP db "jmp", 0 + MN_CALL db "call", 0 + MN_XCHG db "xchg", 0 + MN_SYSCALL db "syscall", 0 + +;; Opcodes support up to 2 operands + +op_table: +;; MN_OFFS | NUM | SIZES | ENCOD | OPCODE | RM | PRE + dd mnt - MN_MOV, 2, 1, 1, ENC_MR, 88h, 00, 00h + dd mnt - MN_MOV, 2, 2, 2, ENC_MR, 89h, 00, 66h + dd mnt - MN_MOV, 2, 4, 4, ENC_MR, 89h, 00, 00h + dd mnt - MN_MOV, 2, 8, 8, ENC_MR, 89h, 00, 00h + dd mnt - MN_MOV, 2, 1, 1, ENC_RM, 8Ah, 00, 00h + dd mnt - MN_MOV, 2, 2, 2, ENC_RM, 8Bh, 00, 66h + dd mnt - MN_MOV, 2, 4, 4, ENC_RM, 8Bh, 00, 00h + dd mnt - MN_MOV, 2, 8, 8, ENC_RM, 8Bh, 00, 00h + dd mnt - MN_MOV, 2, 1, 1, ENC_OI, 0B0h, 00, 00h + dd mnt - MN_MOV, 2, 2, 2, ENC_OI, 0B8h, 00, 66h + dd mnt - MN_MOV, 2, 4, 4, ENC_OI, 0B8h, 00, 00h + dd mnt - MN_MOV, 2, 8, 8, ENC_OI, 0B8h, 00, 00h + dd mnt - MN_MOV, 2, 1, 1, ENC_MI, 0C6h, 00, 00h + dd mnt - MN_MOV, 2, 2, 2, ENC_MI, 0C7h, 00, 66h + dd mnt - MN_MOV, 2, 4, 4, ENC_MI, 0C7h, 00, 00h + dd mnt - MN_MOV, 2, 8, 4, ENC_MI, 0C7h, 00, 00h + + dd mnt - MN_TEST, 2, 1, 1, ENC_MR, 84h, 00, 00h + dd mnt - MN_TEST, 2, 2, 2, ENC_MR, 85h, 00, 66h + dd mnt - MN_TEST, 2, 4, 4, ENC_MR, 85h, 00, 00h + dd mnt - MN_TEST, 2, 8, 8, ENC_MR, 85h, 00, 00h + dd mnt - MN_TEST, 2, 1, 1, ENC_MI, 0F6h, 00, 00h + dd mnt - MN_TEST, 2, 2, 2, ENC_MI, 0F7h, 00, 66h + dd mnt - MN_TEST, 2, 4, 4, ENC_MI, 0F7h, 00, 00h + dd mnt - MN_TEST, 2, 8, 4, ENC_MI, 0F7h, 00, 00h + + dd mnt - MN_XOR, 2, 1, 1, ENC_MR, 30h, 00, 00h + dd mnt - MN_XOR, 2, 2, 2, ENC_MR, 31h, 00, 66h + dd mnt - MN_XOR, 2, 4, 4, ENC_MR, 31h, 00, 00h + dd mnt - MN_XOR, 2, 8, 8, ENC_MR, 31h, 00, 00h + dd mnt - MN_XOR, 2, 1, 1, ENC_RM, 32h, 00, 00h + dd mnt - MN_XOR, 2, 2, 2, ENC_RM, 33h, 00, 66h + dd mnt - MN_XOR, 2, 4, 4, ENC_RM, 33h, 00, 00h + dd mnt - MN_XOR, 2, 8, 8, ENC_RM, 33h, 00, 00h + dd mnt - MN_XOR, 2, 1, 1, ENC_MI, 80h, 06, 00h + dd mnt - MN_XOR, 2, 2, 2, ENC_MI, 81h, 06, 66h + dd mnt - MN_XOR, 2, 4, 4, ENC_MI, 81h, 06, 00h + dd mnt - MN_XOR, 2, 8, 4, ENC_MI, 81h, 06, 00h + + dd mnt - MN_AND, 2, 1, 1, ENC_MR, 20h, 00, 00h + dd mnt - MN_AND, 2, 2, 2, ENC_MR, 21h, 00, 66h + dd mnt - MN_AND, 2, 4, 4, ENC_MR, 21h, 00, 00h + dd mnt - MN_AND, 2, 8, 8, ENC_MR, 21h, 00, 00h + dd mnt - MN_AND, 2, 1, 1, ENC_RM, 22h, 00, 00h + dd mnt - MN_AND, 2, 2, 2, ENC_RM, 23h, 00, 66h + dd mnt - MN_AND, 2, 4, 4, ENC_RM, 23h, 00, 00h + dd mnt - MN_AND, 2, 8, 8, ENC_RM, 23h, 00, 00h + dd mnt - MN_AND, 2, 1, 1, ENC_MI, 80h, 04, 00h + dd mnt - MN_AND, 2, 2, 2, ENC_MI, 81h, 04, 66h + dd mnt - MN_AND, 2, 4, 4, ENC_MI, 81h, 04, 00h + dd mnt - MN_AND, 2, 8, 4, ENC_MI, 81h, 04, 00h + dd mnt - MN_AND, 2, 1, 1, ENC_MI, 83h, 04, 00h + dd mnt - MN_AND, 2, 2, 1, ENC_MI, 83h, 04, 66h + dd mnt - MN_AND, 2, 4, 1, ENC_MI, 83h, 04, 00h + dd mnt - MN_AND, 2, 8, 1, ENC_MI, 83h, 04, 00h + + dd mnt - MN_OR, 2, 1, 1, ENC_MR, 08h, 00, 00h + dd mnt - MN_OR, 2, 2, 2, ENC_MR, 09h, 00, 66h + dd mnt - MN_OR, 2, 4, 4, ENC_MR, 09h, 00, 00h + dd mnt - MN_OR, 2, 8, 8, ENC_MR, 09h, 00, 00h + dd mnt - MN_OR, 2, 1, 1, ENC_RM, 0Ah, 00, 00h + dd mnt - MN_OR, 2, 2, 2, ENC_RM, 0Bh, 00, 66h + dd mnt - MN_OR, 2, 4, 4, ENC_RM, 0Bh, 00, 00h + dd mnt - MN_OR, 2, 8, 8, ENC_RM, 0Bh, 00, 00h + dd mnt - MN_OR, 2, 1, 1, ENC_MI, 80h, 01, 00h + dd mnt - MN_OR, 2, 2, 2, ENC_MI, 81h, 01, 66h + dd mnt - MN_OR, 2, 4, 4, ENC_MI, 81h, 01, 00h + dd mnt - MN_OR, 2, 8, 4, ENC_MI, 81h, 01, 00h + dd mnt - MN_OR, 2, 1, 1, ENC_MI, 83h, 01, 00h + dd mnt - MN_OR, 2, 2, 1, ENC_MI, 83h, 01, 66h + dd mnt - MN_OR, 2, 4, 1, ENC_MI, 83h, 01, 00h + dd mnt - MN_OR, 2, 8, 1, ENC_MI, 83h, 01, 00h + + ; dd mnt - MN_SHL, 2, 1, 1, ENC_M1, 0D0h, 04, 00h + ; dd mnt - MN_SHL, 2, 2, 1, ENC_M1, 0D1h, 04, 66h + ; dd mnt - MN_SHL, 2, 4, 1, ENC_M1, 0D1h, 04, 00h + ; dd mnt - MN_SHL, 2, 8, 1, ENC_M1, 0D1h, 04, 00h + dd mnt - MN_SHL, 2, 1, 1, ENC_MC, 0D2h, 04, 00h + dd mnt - MN_SHL, 2, 2, 1, ENC_MC, 0D3h, 04, 66h + dd mnt - MN_SHL, 2, 4, 1, ENC_MC, 0D3h, 04, 00h + dd mnt - MN_SHL, 2, 8, 1, ENC_MC, 0D3h, 04, 00h + dd mnt - MN_SHL, 2, 1, 1, ENC_MI, 0C0h, 04, 00h + dd mnt - MN_SHL, 2, 2, 1, ENC_MI, 0C1h, 04, 66h + dd mnt - MN_SHL, 2, 4, 1, ENC_MI, 0C1h, 04, 00h + dd mnt - MN_SHL, 2, 8, 1, ENC_MI, 0C1h, 04, 00h + + dd mnt - MN_SHR, 2, 1, 1, ENC_MC, 0D2h, 05, 00h + dd mnt - MN_SHR, 2, 2, 1, ENC_MC, 0D3h, 05, 66h + dd mnt - MN_SHR, 2, 4, 1, ENC_MC, 0D3h, 05, 00h + dd mnt - MN_SHR, 2, 8, 1, ENC_MC, 0D3h, 05, 00h + dd mnt - MN_SHR, 2, 1, 1, ENC_MI, 0C0h, 05, 00h + dd mnt - MN_SHR, 2, 2, 1, ENC_MI, 0C1h, 05, 66h + dd mnt - MN_SHR, 2, 4, 1, ENC_MI, 0C1h, 05, 00h + dd mnt - MN_SHR, 2, 8, 1, ENC_MI, 0C1h, 05, 00h + + dd mnt - MN_INC, 1, 1, 0, ENC_M, 0FEh, 00, 00h + dd mnt - MN_INC, 1, 2, 0, ENC_M, 0FFh, 00, 66h + dd mnt - MN_INC, 1, 4, 0, ENC_M, 0FFh, 00, 00h + dd mnt - MN_INC, 1, 8, 0, ENC_M, 0FFh, 00, 00h + + dd mnt - MN_DEC, 1, 1, 0, ENC_M, 0FEh, 01, 00h + dd mnt - MN_DEC, 1, 2, 0, ENC_M, 0FFh, 01, 66h + dd mnt - MN_DEC, 1, 4, 0, ENC_M, 0FFh, 01, 00h + dd mnt - MN_DEC, 1, 8, 0, ENC_M, 0FFh, 01, 00h + + dd mnt - MN_NEG, 1, 1, 0, ENC_M, 0F6h, 03, 00h + dd mnt - MN_NEG, 1, 2, 0, ENC_M, 0F7h, 03, 66h + dd mnt - MN_NEG, 1, 4, 0, ENC_M, 0F7h, 03, 00h + dd mnt - MN_NEG, 1, 8, 0, ENC_M, 0F7h, 03, 00h + + dd mnt - MN_RET, 0, 0, 0, 0, 0C3h, 00, 00h + + dd mnt - MN_NOT, 1, 1, 0, ENC_M, 0F6h, 02, 00h + dd mnt - MN_NOT, 1, 2, 0, ENC_M, 0F7h, 02, 66h + dd mnt - MN_NOT, 1, 4, 0, ENC_M, 0F7h, 02, 00h + dd mnt - MN_NOT, 1, 8, 0, ENC_M, 0F7h, 02, 00h + + dd mnt - MN_ADD, 2, 1, 1, ENC_MR, 00h, 00, 00h + dd mnt - MN_ADD, 2, 2, 2, ENC_MR, 01h, 00, 66h + dd mnt - MN_ADD, 2, 4, 4, ENC_MR, 01h, 00, 00h + dd mnt - MN_ADD, 2, 8, 8, ENC_MR, 01h, 00, 00h + dd mnt - MN_ADD, 2, 1, 1, ENC_RM, 02h, 00, 00h + dd mnt - MN_ADD, 2, 2, 2, ENC_RM, 03h, 00, 66h + dd mnt - MN_ADD, 2, 4, 4, ENC_RM, 03h, 00, 00h + dd mnt - MN_ADD, 2, 8, 8, ENC_RM, 03h, 00, 00h + dd mnt - MN_ADD, 2, 1, 1, ENC_MI, 80h, 00, 00h + dd mnt - MN_ADD, 2, 2, 2, ENC_MI, 81h, 00, 66h + dd mnt - MN_ADD, 2, 4, 4, ENC_MI, 81h, 00, 00h + dd mnt - MN_ADD, 2, 8, 4, ENC_MI, 81h, 00, 00h + + dd mnt - MN_SUB, 2, 1, 1, ENC_MR, 28h, 00, 00h + dd mnt - MN_SUB, 2, 2, 2, ENC_MR, 29h, 00, 66h + dd mnt - MN_SUB, 2, 4, 4, ENC_MR, 29h, 00, 00h + dd mnt - MN_SUB, 2, 8, 8, ENC_MR, 29h, 00, 00h + dd mnt - MN_SUB, 2, 1, 1, ENC_RM, 2Ah, 00, 00h + dd mnt - MN_SUB, 2, 2, 2, ENC_RM, 2Bh, 00, 66h + dd mnt - MN_SUB, 2, 4, 4, ENC_RM, 2Bh, 00, 00h + dd mnt - MN_SUB, 2, 8, 8, ENC_RM, 2Bh, 00, 00h + dd mnt - MN_SUB, 2, 1, 1, ENC_MI, 80h, 05, 00h + dd mnt - MN_SUB, 2, 2, 2, ENC_MI, 81h, 05, 66h + dd mnt - MN_SUB, 2, 4, 4, ENC_MI, 81h, 05, 00h + dd mnt - MN_SUB, 2, 8, 4, ENC_MI, 81h, 05, 00h + + dd mnt - MN_IMUL, 1, 1, 0, ENC_M, 0F6h, 05, 00h + dd mnt - MN_IMUL, 1, 2, 0, ENC_M, 0F7h, 05, 66h + dd mnt - MN_IMUL, 1, 4, 0, ENC_M, 0F7h, 05, 00h + dd mnt - MN_IMUL, 1, 8, 0, ENC_M, 0F7h, 05, 00h + dd mnt - MN_IMUL, 2, 2, 1, ENC_RM, 0FAFh, 00, 66h + dd mnt - MN_IMUL, 2, 4, 1, ENC_RM, 0FAFh, 00, 00h + dd mnt - MN_IMUL, 2, 8, 1, ENC_RM, 0FAFh, 00, 00h + + dd mnt - MN_IDIV, 1, 1, 0, ENC_M, 0F6h, 07, 00h + dd mnt - MN_IDIV, 1, 2, 0, ENC_M, 0F7h, 07, 66h + dd mnt - MN_IDIV, 1, 4, 0, ENC_M, 0F7h, 07, 00h + dd mnt - MN_IDIV, 1, 8, 0, ENC_M, 0F7h, 07, 00h + + dd mnt - MN_CMP, 2, 1, 1, ENC_MR, 38h, 00, 00h + dd mnt - MN_CMP, 2, 2, 2, ENC_MR, 39h, 00, 66h + dd mnt - MN_CMP, 2, 4, 4, ENC_MR, 39h, 00, 00h + dd mnt - MN_CMP, 2, 8, 8, ENC_MR, 39h, 00, 00h + dd mnt - MN_CMP, 2, 1, 1, ENC_RM, 3Ah, 00, 00h + dd mnt - MN_CMP, 2, 2, 2, ENC_RM, 3Bh, 00, 66h + dd mnt - MN_CMP, 2, 4, 4, ENC_RM, 3Bh, 00, 00h + dd mnt - MN_CMP, 2, 8, 8, ENC_RM, 3Bh, 00, 00h + dd mnt - MN_CMP, 2, 1, 1, ENC_MI, 80h, 07, 00h + dd mnt - MN_CMP, 2, 2, 2, ENC_MI, 81h, 07, 66h + dd mnt - MN_CMP, 2, 4, 4, ENC_MI, 81h, 07, 00h + dd mnt - MN_CMP, 2, 8, 4, ENC_MI, 81h, 07, 00h + + dd mnt - MN_LEA, 2, 2, 4, ENC_RM, 8Dh, 00, 6667h + dd mnt - MN_LEA, 2, 2, 8, ENC_RM, 8Dh, 00, 66h + dd mnt - MN_LEA, 2, 4, 4, ENC_RM, 8Dh, 00, 67h + dd mnt - MN_LEA, 2, 4, 8, ENC_RM, 8Dh, 00, 00h + dd mnt - MN_LEA, 2, 8, 4, ENC_RM, 8Dh, 00, 67h + dd mnt - MN_LEA, 2, 8, 8, ENC_RM, 8Dh, 00, 00h + + dd mnt - MN_PUSH, 1, 2, 0, ENC_O, 50h, 00, 66h + dd mnt - MN_PUSH, 1, 8, 0, ENC_O, 50h, 00, 00h + dd mnt - MN_PUSH, 1, 2, 0, ENC_M, 0FFh, 06, 66h + dd mnt - MN_PUSH, 1, 8, 0, ENC_M, 0FFh, 06, 00h + dd mnt - MN_PUSH, 1, 1, 0, ENC_I, 06Ah, 00, 00h + dd mnt - MN_PUSH, 1, 2, 0, ENC_I, 06Ah, 00, 66h + dd mnt - MN_PUSH, 1, 4, 0, ENC_I, 06Ah, 00, 00h + + dd mnt - MN_POP, 1, 2, 0, ENC_O, 58h, 00, 66h + dd mnt - MN_POP, 1, 8, 0, ENC_O, 58h, 00, 00h + dd mnt - MN_POP, 1, 2, 0, ENC_M, 0FFh, 07, 66h + dd mnt - MN_POP, 1, 8, 0, ENC_M, 0FFh, 07, 00h + dd mnt - MN_POP, 1, 1, 0, ENC_I, 07Ah, 00, 00h + dd mnt - MN_POP, 1, 2, 0, ENC_I, 07Ah, 00, 66h + dd mnt - MN_POP, 1, 4, 0, ENC_I, 07Ah, 00, 00h + + dd mnt - MN_SYSCALL, 0, 0, 0, 0, 0F05h, 00, 00h + + dd mnt - MN_JMP, 1, 1, 0, ENC_I, 0EBh, 00, 00h + dd mnt - MN_JMP, 1, 4, 0, ENC_I, 0E9h, 00, 00h + dd mnt - MN_JMP, 1, 8, 0, ENC_M, 0FFh, 04, 00h + + dd mnt - MN_CALL, 1, 4, 0, ENC_I, 0E8h, 00, 00h + dd mnt - MN_CALL, 1, 8, 0, ENC_M, 0FFh, 02, 00h + + dd mnt - MN_XCHG, 2, 1, 1, ENC_MR, 86h, 00, 00h + dd mnt - MN_XCHG, 2, 2, 2, ENC_MR, 87h, 00, 66h + dd mnt - MN_XCHG, 2, 4, 4, ENC_MR, 87h, 00, 00h + dd mnt - MN_XCHG, 2, 8, 8, ENC_MR, 87h, 00, 00h + dd mnt - MN_XCHG, 2, 1, 1, ENC_RM, 86h, 00, 00h + dd mnt - MN_XCHG, 2, 2, 2, ENC_RM, 87h, 00, 66h + dd mnt - MN_XCHG, 2, 4, 4, ENC_RM, 87h, 00, 00h + dd mnt - MN_XCHG, 2, 8, 8, ENC_RM, 87h, 00, 00h + + + dd mnt - MN_CMOVE, 2, 2, 2, ENC_RM, 0F44h, 00, 66h + dd mnt - MN_CMOVE, 2, 4, 4, ENC_RM, 0F44h, 00, 00h + dd mnt - MN_CMOVE, 2, 8, 8, ENC_RM, 0F44h, 00, 00h + + dd mnt - MN_CMOVNE, 2, 2, 2, ENC_RM, 0F45h, 00, 66h + dd mnt - MN_CMOVNE, 2, 4, 4, ENC_RM, 0F45h, 00, 00h + dd mnt - MN_CMOVNE, 2, 8, 8, ENC_RM, 0F45h, 00, 00h + + dd mnt - MN_CMOVL, 2, 2, 2, ENC_RM, 0F4Ch, 00, 66h + dd mnt - MN_CMOVL, 2, 4, 4, ENC_RM, 0F4Ch, 00, 00h + dd mnt - MN_CMOVL, 2, 8, 8, ENC_RM, 0F4Ch, 00, 00h + + dd mnt - MN_CMOVLE, 2, 2, 2, ENC_RM, 0F4Eh, 00, 66h + dd mnt - MN_CMOVLE, 2, 4, 4, ENC_RM, 0F4Eh, 00, 00h + dd mnt - MN_CMOVLE, 2, 8, 8, ENC_RM, 0F4Eh, 00, 00h + + dd mnt - MN_CMOVG, 2, 2, 2, ENC_RM, 0F4Fh, 00, 66h + dd mnt - MN_CMOVG, 2, 4, 4, ENC_RM, 0F4Fh, 00, 00h + dd mnt - MN_CMOVG, 2, 8, 8, ENC_RM, 0F4Fh, 00, 00h + + dd mnt - MN_CMOVGE, 2, 2, 2, ENC_RM, 0F4Dh, 00, 66h + dd mnt - MN_CMOVGE, 2, 4, 4, ENC_RM, 0F4Dh, 00, 00h + dd mnt - MN_CMOVGE, 2, 8, 8, ENC_RM, 0F4Dh, 00, 00h + + dd mnt - MN_CMOVA, 2, 2, 2, ENC_RM, 0F47h, 00, 66h + dd mnt - MN_CMOVA, 2, 4, 4, ENC_RM, 0F47h, 00, 00h + dd mnt - MN_CMOVA, 2, 8, 8, ENC_RM, 0F47h, 00, 00h + + dd mnt - MN_CMOVAE, 2, 2, 2, ENC_RM, 0F43h, 00, 66h + dd mnt - MN_CMOVAE, 2, 4, 4, ENC_RM, 0F43h, 00, 00h + dd mnt - MN_CMOVAE, 2, 8, 8, ENC_RM, 0F43h, 00, 00h + + dd mnt - MN_CMOVB, 2, 2, 2, ENC_RM, 0F42h, 00, 66h + dd mnt - MN_CMOVB, 2, 4, 4, ENC_RM, 0F42h, 00, 00h + dd mnt - MN_CMOVB, 2, 8, 8, ENC_RM, 0F42h, 00, 00h + + dd mnt - MN_CMOVBE, 2, 2, 2, ENC_RM, 0F46h, 00, 66h + dd mnt - MN_CMOVBE, 2, 4, 4, ENC_RM, 0F46h, 00, 00h + dd mnt - MN_CMOVBE, 2, 8, 8, ENC_RM, 0F46h, 00, 00h + + dd mnt - MN_SETE, 1, 1, 0, ENC_M, 0F94h, 00, 00h + dd mnt - MN_SETNE, 1, 1, 0, ENC_M, 0F95h, 00, 00h + dd mnt - MN_SETL, 1, 1, 0, ENC_M, 0F9Ch, 00, 00h + dd mnt - MN_SETLE, 1, 1, 0, ENC_M, 0F9Eh, 00, 00h + dd mnt - MN_SETG, 1, 1, 0, ENC_M, 0F9Fh, 00, 00h + dd mnt - MN_SETGE, 1, 1, 0, ENC_M, 0F9Dh, 00, 00h + dd mnt - MN_SETA, 1, 1, 0, ENC_M, 0F97h, 00, 00h + dd mnt - MN_SETAE, 1, 1, 0, ENC_M, 0F93h, 00, 00h + dd mnt - MN_SETB, 1, 1, 0, ENC_M, 0F92h, 00, 00h + dd mnt - MN_SETBE, 1, 1, 0, ENC_M, 0F96h, 00, 00h + + dd mnt - MN_JE, 1, 1, 0, ENC_I, 74h, 00, 00h + dd mnt - MN_JNE, 1, 1, 0, ENC_I, 75h, 00, 00h + dd mnt - MN_JL, 1, 1, 0, ENC_I, 7Ch, 00, 00h + dd mnt - MN_JLE, 1, 1, 0, ENC_I, 7Eh, 00, 00h + dd mnt - MN_JG, 1, 1, 0, ENC_I, 7Fh, 00, 00h + dd mnt - MN_JGE, 1, 1, 0, ENC_I, 7Dh, 00, 00h + dd mnt - MN_JA, 1, 1, 0, ENC_I, 77h, 00, 00h + dd mnt - MN_JAE, 1, 1, 0, ENC_I, 73h, 00, 00h + dd mnt - MN_JB, 1, 1, 0, ENC_I, 72h, 00, 00h + dd mnt - MN_JBE, 1, 1, 0, ENC_I, 76h, 00, 00h + + dd mnt - MN_JE, 1, 4, 0, ENC_I, 0F84h, 00, 00h + dd mnt - MN_JNE, 1, 4, 0, ENC_I, 0F85h, 00, 00h + dd mnt - MN_JL, 1, 4, 0, ENC_I, 0F8Ch, 00, 00h + dd mnt - MN_JLE, 1, 4, 0, ENC_I, 0F8Eh, 00, 00h + dd mnt - MN_JG, 1, 4, 0, ENC_I, 0F8Fh, 00, 00h + dd mnt - MN_JGE, 1, 4, 0, ENC_I, 0F8Dh, 00, 00h + dd mnt - MN_JA, 1, 4, 0, ENC_I, 0F87h, 00, 00h + dd mnt - MN_JAE, 1, 4, 0, ENC_I, 0F83h, 00, 00h + dd mnt - MN_JB, 1, 4, 0, ENC_I, 0F82h, 00, 00h + dd mnt - MN_JBE, 1, 4, 0, ENC_I, 0F86h, 00, 00h +op_table_end: + dd 0 ; 231 entries section .text -instr_table: - ; mnemonic, num_operands, handler -_mov: - dq "mov" - db 2 - dq instr_table - _mov_handler - ;; calculates a quick hash of a byte sequence given by rdi (pointer) and rsi (length) -fasthash: - mov eax, 0x811c9dc5 ; FNV offset basis - .fashhash_loop: - test rsi, rsi - jz .fashhash_exit - movzx ecx, byte [rdi] ; get next byte - xor eax, ecx - imul eax, 0x1000193 ; FNV prime - inc rdi - dec rsi - jmp .fashhash_loop - - .fashhash_exit: + ;; format dil as hex u8 into $ax +format_u8: + xor ecx, ecx + ; take upper nibble >> 4 + movzx eax, dil + shr eax, 4 + ; add 0x30 + add eax, 0x30 + ; add (>= 0xA) * 0x7 + cmp eax, 0x39 + seta cl + lea eax, [eax + ecx * 8] + sub eax, ecx + and edi, 0x0F + add edi, 0x30 + cmp edi, 0x39 + seta cl + lea edi, [edi + ecx * 8] + sub edi, ecx + shl edi, 8 + or ax, di ret - ;; push the label pointed at by rdi with length rsi, and the current file offset onto the labels array. -push_lbl: - push r12 - lea r12, [rel labels] - mov rax, dword [r12 + 0x1000 - 4] ; get current label count - cmp rax, 341 - jge panic - lea rax, [rax + rax*2] - shl rax, 2 ; $rax = num_labels + size_of::() - add r12, rax - call fasthash - mov qword [r12], rax ; store hash in labels array - mov dword [r12 + 8], -1 ; initialize file offset to -1 (invalid) - inc dword [r12 + 0x1000 - 4] ; increment label count - pop r12 + ;; format $edi as hex into $rax +format_u32: + sub rsp, 16 + mov dword [rsp], edi + call format_u8 + mov word [rsp + 14], ax + mov dil, byte [rsp + 1] + call format_u8 + mov word [rsp + 12], ax + mov dil, byte [rsp + 2] + call format_u8 + mov word [rsp + 10], ax + mov dil, byte [rsp + 3] + call format_u8 + mov word [rsp + 8], ax + mov rax, qword [rsp + 8] + add rsp, 16 ret -;; searches for the offset of the label with the name pointed at by rdi with length rsi, and returns it in rax. If the label is not found, dies. -find_lbl_ptr: - call fasthash - lea rdx, [r15 + 0x5010] ; rdx = pointer to start of labels array - mov ebx, dword [r15 + 0x6000] -.find_lbl_loop: - test rbx, rbx - jz .find_lbl_not_found - dec rbx - cmp qword [rdx], rax - je .find_lbl_found - add rdx, 12 ; move to next label entry - jmp .find_lbl_loop - -push_or_find_lbl: - call fasthash - push rax - mov rdi, rax - call find_lbl_ptr - test rax, rax - jz .push - add rsp, 8 - ret -.push: - pop rdi - call push_lbl - ret - -.find_lbl_not_found: - xor rax, rax - ret -.find_lbl_found: - mov rax, rdx - ret - -find_lbl_offset: - call find_lbl_ptr - test rax, rax - jz .not_found - mov eax, dword [rax + 8] ; get file offset of label - ret -.not_found: - xor rdi, rdi - call panic_abort - -set_lbl_offset: - push rsi - call find_lbl_ptr - pop rsi - mov dword [rax + 8], esi ; set file offset of label - ret - -is_alpha: - movzx edi, dil - and edi, 2097119 - add edi, -65 - cmp edi, 26 - setb al - ret - -;; returns 1 if $dil is a valid identifier character (alphanumeric, '-' or '_'), and 0 otherwise. - ;; clobbers rdi, rax, rcx -is_id_cont: - movzx rdi, dil - lea eax, [rdi - 48] - cmp eax, 10 - setb al - mov ecx, edi - and ecx, 2097119 - add ecx, -65 - cmp ecx, 26 - setb cl - or al, cl - cmp edi, 45 ; '-' - sete cl - or al, cl - cmp edi, 95 ; '_' - sete cl - or al, cl - ret - -is_digit: - movzx edi, dil - add edi, -48 - cmp edi, 10 - setb al - ret - - ;; converts char $dil to a digit with radix $rsi, returning it in $edx. $al is set to 1 if the char is a valid digit, and 0 otherwise. -to_digit: - lea eax, [rsi - 2] - cmp eax, 35 - jae .invalid - movzx rdi, dil - lea edx, [rdi - 65] ; 'A' = 65 - and edx, -33 ; convert to uppercase - add edx, 10 ; 'A' should map to 10 - lea eax, [rdi - 48] ; '0' = 48 - cmp esi, 11 - cmovb edx, eax ; if radix <= 10, then take the difference from '0' - cmp edi, 58 - cmovb edx, eax ; or if char < '9', then take the difference from '0' - xor eax, eax - cmp edx, esi - setb al ; al = edx < radix - ret -.invalid: - xor eax, eax - ret - -parse_num: - sub rsp, 24 - mov qword [rsp], 0 ; acc - mov qword [rsp + 8], rdi ; source iterator - mov dword [rsp + 16], 10 ; radix - call peekc - cmp al, `-` - jne .skip_sign - mov qword [rsp], -1 ; acc = -1 - call consuming_peekc -.skip_sign: - cmp al, `0` - jne .skip_radix - call consuming_peekc - cmp al, `x` - jne .skip_radix - mov dword [rsp + 16], 16 ; radix = 16 - call consuming_peekc -.skip_radix: - mov dil, al - call to_digit - test al, al - jz .done - mov rax, qword [rsp] ; acc - mov rsi, qword [rsp + 16] ; radix - mov rcx, rdx - imul rax, rsi - add rax, rcx - mov qword [rsp], rax ; acc = acc * radix + digit - mov rdi, qword [rsp + 8] ; source iterator - call consuming_peekc - jmp .skip_radix -.done: - mov rax, qword [rsp] ; move the result into rax - add rsp, 24 - ret - -parse_label: - push r12 - lea r12, [rel buf] +print_u8: + call format_u8 sub rsp, 8 - mov qword [rsp], rdi ; source iterator - call consuming_peekc - mov dil, al - call is_alpha - test al, al - jz .done - mov byte [r12], al - inc r12 - mov rdi, qword [rsp] ; restore source iterator - call consuming_peekc - mov dil, al - call is_id_cont - test al, al - jz .done - jmp .loop -.done: - lea rdi, [rel buf] - mov rsi, r12 - sub rsi, rdi - call push_or_find_lbl + mov word [rsp], ax + lea rdi, [rsp] + mov rsi, 2 + call print_str add rsp, 8 - pop r12 ret -;; @param lhs: (rdi, rsi) -;; @param rhs: (rdx, rcx) -;; @return al +print_u32: + call format_u32 + sub rsp, 8 + mov qword [rsp], rax + lea rdi, [rsp] + mov rsi, 8 + call print_str + add rsp, 8 + ret + + ;; print $rsi bytes from $rdi to stdout +print_str: + mov rax, 1 + mov rdx, rsi + mov rsi, rdi + mov rdi, 1 + syscall + ret + +tab: db 9 +print_tab: + lea rsi, [rel tab] + mov rdx, 1 + mov rax, 1 + mov rdi, 1 + syscall + ret + +nl: db 10 +print_nl: + lea rsi, [rel nl] + mov rdx, 1 + mov rax, 1 + mov rdi, 1 + syscall + ret + + ;; print the $rdi-th entry in the op_table +op_table_entry_print: + sub rsp, 8 + lea rax, [rel op_table] + lea rdi, [rdi * 4] + lea rax, [rax + rdi * 8] + mov qword [rsp], rax + + lea rdi, [rel mnemonics] + movsx rax, dword [rax] + sub rdi, rax + call strlen + mov rsi, rax + call print_str ; mnemonic + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 4] + call print_u8 ; num operands + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 8] + call print_u8 ; operand 0 size + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 12] + call print_u8 ; operand 1 size + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 16] + call print_u8 ; encoding + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 20] + call print_u32 ; opcode + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 24] + call print_u8 ; rm-bits + call print_tab + + mov rax, qword [rsp] + mov edi, dword [rax + 28] + call print_u8 ; prefix + + call print_nl + + add rsp, 8 + ret + +print_op_table: + push rbx + xor ebx, ebx +.loop: + cmp ebx, 241 + jge .done + + mov rdi, rbx + call op_table_entry_print + inc ebx + jmp .loop + +.done: + pop rbx + ret + +;; rdi: *u8 +strlen: + xor rax, rax +.strlen_loop: + cmp byte [rdi + rax], 0 + je .strlen_done + inc rax + jmp .strlen_loop +.strlen_done: + ret + +;; lhs: (rdi, rsi) +;; rhs: (rdx, rcx) +;; al strcmp: cmp rcx, rsi cmovb rsi, rcx ; if rhs is shorter, use its length for the loop xor eax, eax .strcmp_loop: cmp rsi, rax - je .strcmp_equal + jz .strcmp_equal movzx ecx, byte [rdx + rax] cmp byte [rdi + rax], cl lea rax, [rax + 1] @@ -274,487 +566,196 @@ strcmp: xor eax, eax ret -memcpy: - xor rax, rax -.memcpy_loop: - cmp rax, rdx - je .memcpy_done - mov al, byte [rdi + rax] - mov byte [rsi + rax], al - lea rax, [rax + 1] - jmp .memcpy_loop -.memcpy_done: - ret - - ;; read from input file -read_file: - -; ;; returns the next byte in the input stream without advancing the read position. -; peekc: - -; ;; returns the next byte in the input stream and advances the read position. - ; getc: -extern panic_abort -extern peekc -extern getc -extern consuming_peekc - -skip_whitespaces: - push rdi - call peekc +;; find the first occurrence of $dl in the first $rsi bytes of $rdi +strfind: + xor eax, eax .loop: - cmp al, ' ' - je .read - cmp al, `\t` - je .read - cmp al, `\n` - je .read - pop rdi - ret - - .read: - call consuming_peekc + cmp rax, rsi + jge .not_found + mov cl, byte [rdi + rax] + cmp cl, dl + je .found + inc rax jmp .loop - - ;; converts char $dil to a digit with radix $rsi, returning it in $edx. $al is set to 1 if the char is a valid digit, and 0 otherwise. -to_digit: - lea eax, [rsi - 2] - cmp eax, 35 - jae .invalid - movzx rdi, dil - lea edx, [rdi - 65] ; 'A' = 65 - and edx, -33 ; convert to uppercase - add edx, 10 ; 'A' should map to 10 - lea eax, [rdi - 48] ; '0' = 48 - cmp esi, 11 - cmovb edx, eax ; if radix <= 10, then take the difference from '0' - cmp edi, 58 - cmovb edx, eax ; or if char < '9', then take the difference from '0' - xor eax, eax - cmp edx, esi - setb al ; al = edx < radix - ret -.invalid: - xor eax, eax +.not_found: + mov rax, -1 +.found: ret -;; reads from $rdi and parses digits with radix $rsi until a non-digit is encountered. -parse_digits: - sub rsp, 24 - mov qword [rsp + 16], rsi ; save the radix - mov qword [rsp + 8], rdi ; save the source iterator - mov qword [rsp], 0 - .loop: - mov rdi, qword [rsp + 8] ; restore the source iterator - call peekc - mov dil, al - mov rsi, qword [rsp + 16] ; restore the radix - call to_digit - test al, al - jz .done - mov rax, qword [rsp] - mov rsi, qword [rsp + 16] ; restore the radix - imul rax, rsi - add rax, rdx - mov qword [rsp], rax - mov rdi, qword [rsp + 8] ; restore the source iterator - call getc - jmp .loop - - .done: - mov rax, [rsp] - add rsp, 24 - ret - -;; enum Register { - ; A = 0, - ; B, - ; C, - ; D, - ; Src, - ; Dst, - ; Sp, - ; Bp, - ; R8, - ; R9, - ; R10, - ; R11, - ; R12, - ; R13, - ; R14, - ; R15, -;; } - - - -;; parses a non-extended GPR operand (e.g. a register name that isn't r8-r15) -;; returns the register number in rax and the width in rdx -;; if $rdx == 0, then parsing failed (invalid register name) -;; $rdi = source -;; $rsi = prefix char (e.g. 'r' or 'e' or 0) -global parse_gpr -parse_gpr: - sub rsp, 24 - mov qword [rsp + 16], -1 ; register number, initialized to -1 (invalid) - mov qword [rsp + 8], rdi ; source iterator - mov qword [rsp], rsi ; prefix char - call getc - - ; check for a,b,c,d,s - movzx rax, al - sub rax, 'a' ; convert 'a' to 0, 'b' to 1, ..., 's' to 4 - cmp rax, 's' - 'a' - ja .invalid ; if it's greater than 's', it's invalid - mov rcx, 4 - cmovz rax, rcx ; if it's 's', set rax to 4 - cmp rax, 4 - ja .invalid ; if it's greater than 4, it's invalid - lea rcx, [rel .jt] ; jump table for a,b,c,d - movsxd rdx, dword [rcx + rax * 4] ; get the offset of the handler if a-d - add rcx, rdx ; calculate the address of the handler - jmp rcx - -.suffix: - mov byte [rsp + 16], al ; save the register number for a,b,c,d,s - mov rdi, qword [rsp + 8] ; restore the source iterator - call peekc - cmp al, 'l' - jne .not_l - mov rdi, qword [rsp + 8] ; restore the source iterator - call getc ; consume the suffix - mov rdx, 1 ; width = 1 for al, bl, cl, dl, sil, dil - jmp .done -.not_l: ; x is only valid for a,b,c,d, not sp, bp, si or di - mov rdx, 2 - cmp byte [rsp + 16], 4 - jae .done ; for sp, bp, si, di, the width is 2 if not 'l' - cmp al, 'x' - jne .not_x - mov rdi, qword [rsp + 8] ; restore the source iterator - call getc ; consume the suffix - mov rdx, 2 ; width = 2 for ax, bx, cx, dx - jmp .done -.not_x: ; x is only valid for a,b,c,d - cmp al, 'h' - jne .invalid - mov rdx, 3 ; width = 3 for ah, bh, ch, dh -.done: - movzx rax, byte [rsp + 16] ; move the register number into rax - add rsp, 24 - ret -.invalid: - xor rax, rax ; rax = 0 indicates invalid register - xor rdx, rdx ; rdx = 0 indicates invalid register - jmp .done - -.a: - mov rax, 0 - jmp .suffix -.b: - mov rdi, qword [rsp + 8] ; restore the source iterator - call peekc - cmp al, 'p' - mov rax, 1 - jne .suffix - mov rdi, qword [rsp + 8] ; restore the source iterator - call getc - mov rax, 5 - jmp .suffix -.c: - mov rax, 2 - jmp .suffix -.d: - mov rdi, qword [rsp + 8] ; restore the source iterator - call peekc - cmp al, 'i' - mov rax, 3 - jne .suffix - mov rdi, qword [rsp + 8] ; restore the source iterator - call getc - mov rax, 7 - jmp .suffix -.s: - mov rdi, qword [rsp + 8] ; restore the source iterator - call getc - mov cl, al - cmp cl, 'i' - mov rax, 6 - je .suffix - cmp cl, 'p' - mov rax, 4 - je .suffix - jmp .invalid - -.jt: - dd .a-.jt - dd .b-.jt - dd .c-.jt - dd .d-.jt - dd .s-.jt - - - - -;; parses an extended GPR operand (e.g. r8-r15) -;; $rdi = source, leading r is already consumed -parse_egpr: - sub rsp, 16 - mov qword [rsp + 8], rdi ; source iterator - mov rsi, 10 - call parse_digits - cmp rax, 8 - jb .invalid - cmp rax, 15 - ja .invalid - mov qword [rsp], rax -.suffix: - mov rdi, qword [rsp + 8] ; restore the source iterator - call peekc - mov rcx, 1 - cmp al, 'b' - je .done_getc - mov rcx, 2 - cmp al, 'w' - je .done_getc - mov rcx, 4 - cmp al, 'd' - je .done_getc - mov rcx, 8 ; default width is 8 for r8-r15 - jmp .done -.done_getc: - mov rdi, qword [rsp + 8] ; restore the source iterator - push rcx - call getc - pop rcx -.done: - mov rdx, rcx - mov rax, qword [rsp] ; move the register number into rax - add rsp, 16 - ret -.invalid: - mov qword [rsp], 0 - xor rcx, rcx ; rdx = 0 indicates invalid register - jmp .done - -;; (rdi, rsi): source string - global parse_reg -parse_reg: - sub rsp, 16 - mov qword [rsp + 8], rdi ; source iterator - mov byte [rsp], 0 ; x1 - call peekc - cmp al, 'r' - mov rdi, qword [rsp + 8] ; restore the source iterator - je .r - cmp al, 'e' - jne .gpr - mov byte [rsp], 1 ; x2 - call getc ; consume the 'e' - mov rdi, qword [rsp + 8] ; restore the source iterator - jmp .gpr -.r: - mov byte [rsp], 2 ; x4 - call getc ; consume the 'r' - mov rdi, qword [rsp + 8] ; restore the source iterator - call peekc - mov dil, al - mov rsi, 10 - call to_digit - test al, al - mov rdi, qword [rsp + 8] ; restore the source iterator - jz .gpr - call parse_egpr - jmp .done -.gpr: - call parse_gpr - mov cl, byte [rsp] - shl rdx, cl -.done: - add rsp, 16 - ret - - -global parse_packed_reg -parse_packed_reg: - call parse_reg +;; rdi: src +;; rsi: dst +;; rdx: len +memcpy: +.loop: test rdx, rdx - jz .invalid - shl rdx, 4 - or rax, rdx - ret -.invalid: - xor rax, rax + jz .done + mov al, byte [rdi] + mov byte [rsi], al + inc rsi + inc rdi + dec rdx + jmp .loop +.done: ret -;; enum Operand { -;; Reg(Reg, width: u8), -;; Imm(u32, width: u8), -;; Mem(width: u8, base: Option, index: Option<(Reg, scale: u8)>, disp: Option), -;; } - -;; operands can be registers, memory operands, immediates or labels -;; labels start with a ' -;; immediates start with a digit or a '-' -;; memory operands may have the forms: [