diff --git a/src/data/opcodes.c b/src/data/opcodes.c new file mode 100644 index 0000000..f74f68a --- /dev/null +++ b/src/data/opcodes.c @@ -0,0 +1,145 @@ +#include "opcodes.h" + +// clang-format off +opcode_data_t *const opcodes[] = { + // RET + &(opcode_data_t) { + .mnemonic = "ret", + .opcode = 0xC3, + .opcode_extension = opcode_extension_none, + .operand_count = 0, + }, + // RET imm16 + &(opcode_data_t) { + .mnemonic = "ret", + .opcode = 0xC2, + .opcode_extension = opcode_extension_none, + .operand_count = 1, + .operands = { + { .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_16 }, + }, + }, + // PUSH imm8 + &(opcode_data_t) { + .mnemonic = "push", + .opcode = 0x6A, + .opcode_extension = opcode_extension_none, + .operand_count = 1, + .operands = { + { .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_8}, + }, + }, + // PUSH imm16 + &(opcode_data_t) { + .mnemonic = "push", + .opcode = 0x68, + .opcode_extension = opcode_extension_none, + .operand_size_prefix = true, + .operand_count = 1, + .operands = { + { .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_16}, + }, + }, + // PUSH imm32 + &(opcode_data_t) { + .mnemonic = "push", + .opcode = 0x68, + .opcode_extension = opcode_extension_none, + .operand_size_prefix = false, + .operand_count = 1, + .operands = { + { .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_32}, + }, + }, + // PUSH reg16, + &(opcode_data_t) { + .mnemonic = "push", + .opcode = 0x50, + .opcode_extension = opcode_extension_none, + .encoding_class = ENCODING_OPCODE_REGISTER, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_16 }, + }, + }, + // PUSH reg64 + &(opcode_data_t) { + .mnemonic = "push", + .opcode = 0x50, + .opcode_extension = opcode_extension_none, + .encoding_class = ENCODING_OPCODE_REGISTER, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 }, + }, + }, + // NOT reg16 + &(opcode_data_t) { + .mnemonic = "not", + .opcode = 0xF7, + .opcode_extension = 2, + .operand_size_prefix = true, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_16 }, + }, + }, + // NOT reg32 + &(opcode_data_t) { + .mnemonic = "not", + .opcode = 0xF7, + .opcode_extension = 2, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_32 }, + }, + }, + // NOT reg64 + &(opcode_data_t) { + .mnemonic = "not", + .opcode = 0xF7, + .opcode_extension = 2, + .rex_w_prefix = true, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 }, + }, + }, + + // NEG reg16 + &(opcode_data_t) { + .mnemonic = "neg", + .opcode = 0xF7, + .opcode_extension = 3, + .operand_size_prefix = true, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_16 }, + }, + }, + // NEG reg32 + &(opcode_data_t) { + .mnemonic = "neg", + .opcode = 0xF7, + .opcode_extension = 3, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_32 }, + }, + }, + // NEG reg64 + &(opcode_data_t) { + .mnemonic = "neg", + .opcode = 0xF7, + .opcode_extension = 3, + .rex_w_prefix = true, + .operand_count = 1, + .operands = { + { .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 }, + }, + }, + + + nullptr, +}; + diff --git a/src/data/opcodes.h b/src/data/opcodes.h new file mode 100644 index 0000000..14c842b --- /dev/null +++ b/src/data/opcodes.h @@ -0,0 +1,56 @@ +#ifndef INCLUDE_DATA_OPCODES_H_ +#define INCLUDE_DATA_OPCODES_H_ + +#include "../data/registers.h" +#include +#include + +constexpr uint8_t rex_prefix = 0x40; +constexpr uint8_t rex_prefix_w = 0x48; +constexpr uint8_t rex_prefix_r = 0x44; +constexpr uint8_t rex_prefix_x = 0x42; +constexpr uint8_t rex_prefix_b = 0x41; + +constexpr uint8_t operand_size_prefix = 0x66; +constexpr uint8_t memory_size_prefix = 0x67; +constexpr uint8_t lock_prefix = 0xF0; +constexpr uint8_t repne_prefix = 0xF2; +constexpr uint8_t rep_prefix = 0xF3; + +typedef enum encoding_class { + ENCODING_DEFAULT, // use modrm+sib for registers and memory, append + // immediates + ENCODING_OPCODE_REGISTER, // encode the register in the last 3 bits of the + // opcode +} encoding_class_t; + +typedef enum operand_kind { + OPERAND_REGISTER, + OPERAND_MEMORY, + OPERAND_IMMEDIATE, +} operand_kind_t; + +typedef struct operand_info { + operand_kind_t kind; + operand_size_t size; +} operand_info_t; + +constexpr uint8_t opcode_extension_none = 0xFF; + +typedef struct opcode_data { + const char *mnemonic; + + uint16_t opcode; + uint8_t opcode_extension; // 3 bits for the opcode extension in the reg + // field of a modr/m byte + encoding_class_t encoding_class; + bool operand_size_prefix; + bool address_size_prefix; + bool rex_w_prefix; + size_t operand_count; + operand_info_t operands[3]; +} opcode_data_t; + +extern opcode_data_t *const opcodes[]; + +#endif // INCLUDE_DATA_OPCODES_H_