;; This assembler is a 2-pass compiler, permitting forward and backward label references. ;; It's also the first stage in this bootstrapping experiment that will ;; 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 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 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 ;; 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 ;; 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 print_u8: call format_u8 sub rsp, 8 mov word [rsp], ax lea rdi, [rsp] mov rsi, 2 call print_str add rsp, 8 ret 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 jz .strcmp_equal movzx ecx, byte [rdx + rax] cmp byte [rdi + rax], cl lea rax, [rax + 1] je .strcmp_loop seta al ; al = lhs > rhs sbb al, 0 ; al = al - CF ret .strcmp_equal: xor eax, eax ret ;; find the first occurrence of $dl in the first $rsi bytes of $rdi strfind: xor eax, eax .loop: cmp rax, rsi jge .not_found mov cl, byte [rdi + rax] cmp cl, dl je .found inc rax jmp .loop .not_found: mov rax, -1 .found: ret ;; rdi: src ;; rsi: dst ;; rdx: len memcpy: .loop: test rdx, rdx jz .done mov al, byte [rdi] mov byte [rsi], al inc rsi inc rdi dec rdx jmp .loop .done: ret is_alpha: movzx eax, dil and eax, 0x1fffdf ; ignore bit 5 (case) add eax, -65 ; subtract 'A' cmp eax, 26 ; check if in range 0-25 setb al ret is_digit: movzx edi, dil lea eax, [rdi - 48] ; subtract '0' cmp eax, 10 ; check if in range 0-9 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 exit: mov rax, 60 syscall ;; Operands %define KIND_NONE 0 %define KIND_REG 1 %define KIND_MEM 2 %define KIND_IMM 3 struc operand .type resd 1 .size resd 1 .reg resq 1 .index resq 1 .scale resd 1 .disp resd 1 endstruc struc operand_imm .type resd 1 .size resd 1 .imm resq 1 endstruc abcd_reg_indices: db 0, 3, 1, 2 rX_suffixes: db 'b', 'w', 'd' global try_parse_reg try_parse_reg: push rbx ; buf push r12 ; reg_num push r13 ; size push rdi xor r12d, r12d xor r13d, r13d mov rbx, rdi mov dil, byte [rbx] call is_alpha jnb .done cmp dil, 'r' jne .not_64_or_rX inc rbx mov dil, byte [rbx] call is_digit jnb .not_rX inc rbx sub dil, '0' movzx r12d, dil cmp dil, 1 jne .rX_size shl r12d, 3 lea r12d, [r12d + edi * 2] ; * 10 movzx edi, byte [rbx] sub edi, '0' add r12d, edi ; * 10 + digit inc rbx .rX_size: lea rdi, [rel rX_suffixes] mov rsi, 3 mov dl, byte [rbx] call strfind cmp rax, 0 mov r13d, eax mov edi, 3 cmovl r13d, edi jmp .done .not_rX: mov r13d, 3 ; 64-bit register .r_or_e: mov dx, word [rbx] add rbx, 2 mov r12d, 4 ; rsp cmp dx, 'sp' je .done mov r12d, 5 ; rbp cmp dx, 'bp' je .done mov r12d, 6 ; rsi cmp dx, 'si' je .done mov r12d, 7 ; rdi cmp dx, 'di' je .done mov r12d, -1 ; rip cmp dx, 'ip' je .done lea rax, [rel abcd_reg_indices] sub dl, 'a' movzx edx, dl movzx r12d, byte [rax + rdx] ; rax, rcx, rdx, rbx .done: mov rax, rbx pop rdi sub rax, rdi ; number of bytes consumed movzx rdx, r12d ; reg_num shl rdx, 32 mov r12d, r13d ; size or rdx, r12 pop r13 pop r12 pop rbx ret .not_64_or_rX: cmp dil, 'e' jne .not_32 mov r13d, 2 ; 32-bit register inc rbx jmp .r_or_e .not_32: xor ecx, ecx cmp byte [rbx + 1], 'l' sete al cmp byte [rbx + 2], 'l' sete cl xor al, cl mov r13d, 1 sub r13d, eax jmp .r_or_e try_parse_num: push rbx ; buf push r12 ; radix push r13 ; acc push rdi mov r12, 10 xor r13d, r13d xor eax, eax mov rbx, rdi ; eat leading - and flip sign cmp byte [rbx], '-' sete al sub r13, rax lea rbx, [rbx + rax] ; eat any leading + cmp byte [rbx], '+' sete al lea rbx, [rbx + rax] mov dil, byte [rbx] call is_digit jnb .not_num cmp dil, '0' jne .loop inc rbx mov dil, byte [rbx] and dil, 0xdf ; convert to uppercase cmp dil, 'X' sete al lea ecx, [eax + eax * 2] shl ecx, 1 add r12d, ecx cmp dil, 'O' sete al shl al, 1 sub r12d, eax cmp dil, 'B' sete al shl al, 3 sub r12d, eax cmp r12d, 10 setne al lea rbx, [rbx + rax] .loop: mov dil, byte [rbx] test dil, dil jz .done mov esi, r12d call to_digit mov ecx, edx test al, al jz .done mov rax, r13 imul r12 add rax, rcx mov r13, rax inc rbx jmp .loop .done: mov rax, rbx pop rdi sub rax, rdi ; number of bytes consumed mov rdx, r13 ; acc pop r13 pop r12 pop rbx ret .not_num: xor rax, rax xor rdx, rdx pop rdi pop r13 pop r12 pop rbx ret skip_whitespace_rbx: mov al, byte [rbx] cmp al, ' ' ja .done inc rbx jmp skip_whitespace_rbx .done: ret global try_parse_mem try_parse_mem: push rbx ; buf push r12 ; size push rdi mov rbx, rdi ; buf ptr mov r12, rsi ; output operand ptr mov dword [r12 + operand.type], KIND_MEM mov dword [r12 + operand.size], 0 mov qword [r12 + operand.reg], -1 mov qword [r12 + operand.index], -1 mov dword [r12 + operand.scale], 0 mov dword [r12 + operand.disp], 0 mov edi, dword [rbx] cmp dil, '[' je .bracket lea rbx, [rbx + 4] cmp edi, 'byte' je .bracket mov dword [r12 + operand.size], 1 ; 16-bit cmp edi, 'word' je .bracket lea rbx, [rbx - 4] mov dl, byte [rbx] inc rbx mov edi, dword [rbx] xor eax, eax mov dword [r12 + operand.size], 2 ; 16-bit cmp dl, 'q' sete al cmp dl, 'd' sete dl or al, dl jz .not_mem add dword [r12 + operand.size], eax ; 32-bit? cmp edi, 'word' jne .not_mem lea rbx, [rbx + 4] .bracket: call skip_whitespace_rbx mov dl, byte [rbx] cmp dl, '[' jne .not_mem inc rbx call skip_whitespace_rbx mov rdi, rbx call try_parse_reg add rbx, rax call skip_whitespace_rbx cmp byte [rbx], '*' jne .base mov qword [r12 + operand.index], rdx .scale: inc rbx call skip_whitespace_rbx mov dil, byte [rbx] mov esi, 10 call to_digit mov dword [r12 + operand.scale], edx add rbx, rax call skip_whitespace_rbx mov dil, byte [rbx] cmp dil, ']' je .done ; TODO: allow for label as displacement .disp: sub dil, `,` neg dil ; sign mov al, dil inc al test al, -3 jne .not_mem movsx edi, dil mov dword [r12 + operand.disp], edi inc rbx call skip_whitespace_rbx mov rdi, rbx call try_parse_num test eax, eax jz .not_mem add rbx, rax mov eax, dword [r12 + operand.disp] imul edx mov dword [r12 + operand.disp], eax call skip_whitespace_rbx cmp byte [rbx], ']' je .done jmp .not_mem .base: mov qword [r12 + operand.reg], rdx cmp byte [rbx], ']' je .done cmp byte [rbx], '+' jne .not_mem inc rbx call skip_whitespace_rbx mov rdi, rbx call try_parse_reg test eax, eax jz .disp add rbx, rax mov qword [r12 + operand.index], rdx call skip_whitespace_rbx cmp byte [rbx], '*' je .scale cmp byte [rbx], '+' je .disp cmp byte [rbx], ']' jne .not_mem .done: inc rbx mov rax, rbx pop rdi sub rax, rdi ; number of bytes consumed mov rdx, r12 ; output operand ptr pop r12 pop rbx ret .not_mem: xor rax, rax pop rdi pop r12 pop rbx ret global _entry_print_table _entry_print_table: call print_op_table call exit