Skip to content

Commit

Permalink
Added op_write_opcode() function (#22)
Browse files Browse the repository at this point in the history
* Added `op_write_opcode()` function

This commit has added the `op_write_opcode` funciton, this funciton
intends to replace the old and weird `OP_OPCODE_HELPER` macro that
attempts to write a opcode using macro functions and without much
consideration about other variable condiitons.

* Added unit test for the `op_write_opcode` function

Since the addition of the `op_write_opcode function in commit number
7875519, this commits adds the
corrisponding test cases to the operand.c test file.

(Not that its supposed to be in the **operand** file)
  • Loading branch information
cheng-alvin authored Dec 30, 2024
1 parent 1146631 commit 64593f5
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
19 changes: 19 additions & 0 deletions libjas/include/operand.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,25 @@ uint8_t op_sizeof(enum operands input);
*/
operand_t op_construct_operand(enum operands type, size_t offset, void *data);

/**
* Function for returning the opcode of the instruction based
* on the instruction encoder table provided in the function
* arguments as well as if a byte opcode is provided in the
* the encoder table.
*
* @param op_arr The operand array to base the opcode from
* @param instr_ref The instruction reference table
* @return The opcode of the instruction
*
* You can literally wrap this into a buffer write function
* to quickly and easily write in the opcode like as shown:
*
* buf_write(buf, op_write_opcode(<operands>, <encoder table>), <opcode size>);
*
* @see buffer.h
*/
uint8_t *op_write_opcode(operand_t *op_arr, instr_encode_table_t *instr_ref);

#define OP_NONE \
(operand_t) { \
.data = NULL, \
Expand Down
24 changes: 24 additions & 0 deletions libjas/operand.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "operand.h"
#include "error.h"
#include "instruction.h"
#include "register.h"
#include "rex.h"
#include <stdbool.h>
Expand Down Expand Up @@ -63,6 +64,29 @@ uint8_t op_sizeof(enum operands input) {
return 0;
}

uint8_t *op_write_opcode(operand_t *op_arr, instr_encode_table_t *instr_ref) {
if (!instr_ref->has_byte_opcode) return instr_ref->opcode;

// According to Oracle's <x86 Assembly Language Reference Manual>
// (Yeah seriously - Oracle has a x86 Assembly Language Reference Manual)
// Only when *BOTH* operands are byte-sized, the opcode will also be byte-sized
// So, wel'll check if they are *BOTH* byte sized then write that.

const uint8_t reference = op_sizeof(op_arr[0].type);
const uint8_t sizes[] =
{reference, op_sizeof(op_arr[1].type),
op_sizeof(op_arr[2].type), op_sizeof(op_arr[3].type)};

bool sizes_are_byte = reference == 8;
for (unsigned char i = 0; i < 4; i++) {
if (op_arr[i].type == OP_NULL) break;
if (sizes[i] != 8 && sizes_are_byte) sizes_are_byte = false;
}

if (sizes_are_byte) return instr_ref->byte_instr_opcode;
return instr_ref->opcode;
}

void op_write_prefix(buffer_t *buf, const operand_t *op_arr, enum modes mode) {
/**
* @brief
Expand Down
14 changes: 14 additions & 0 deletions tests/operand.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "operand.h"
#include "buffer.h"
#include "encoder.h"
#include "instruction.h"
#include "rex.h"
#include "test.h"

Expand Down Expand Up @@ -68,13 +69,26 @@ Test(operand, modrm_mode) {
}
}

Test(operand, write_opcode) {
const operand_t op_arr[] = {r64, imm64, OP_NONE, OP_NONE};
const instr_encode_table_t instr_ref = {ENC_MI, 0, {0xC7}, MODE_SUPPORT_ALL, {0xC6}, 1, NULL, true};

uint8_t *out = op_write_opcode(op_arr, &instr_ref);
assert_eq(out, instr_ref.opcode);

const operand_t op_arr_byte[] = {r8, imm8, OP_NONE, OP_NONE};
out = op_write_opcode(op_arr_byte, &instr_ref);
assert_eq(out, instr_ref.byte_instr_opcode);
}

int main(void) {
TestSuite(operand);

RunTest(operand, write_prefix);
RunTest(operand, construct_operand);
RunTest(operand, ident_identify);
RunTest(operand, modrm_mode);
RunTest(operand, write_opcode);

return 0;
}

0 comments on commit 64593f5

Please sign in to comment.