mirror of
https://github.com/pound-emu/ballistic.git
synced 2026-06-17 04:16:48 -07:00
engine: fix name mangling with c++ compilers
Added `extern "C"` to every header file to support using Ballistic with C++ projects Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
+115
-103
@@ -28,10 +28,15 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/// This struct manages a linear buffer of 32-bit integers where ARM64 machine code is written.
|
||||
/// It tracks the current write position and handles boundary checking.
|
||||
typedef struct
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/// This struct manages a linear buffer of 32-bit integers where ARM64 machine code is written.
|
||||
/// It tracks the current write position and handles boundary checking.
|
||||
typedef struct
|
||||
{
|
||||
/// A pointer to the start of the code buffer.
|
||||
uint32_t *buffer;
|
||||
|
||||
@@ -46,125 +51,132 @@ typedef struct
|
||||
|
||||
/// The current error state of the assembler.
|
||||
///
|
||||
/// Once this is set to anything other than [`BAL_SUCCESS`], all subsequent emit calls will be
|
||||
/// ignored until the assembler is reset.
|
||||
/// Once this is set to anything other than [`BAL_SUCCESS`], all subsequent emit calls will
|
||||
/// be ignored until the assembler is reset.
|
||||
bal_error_t status;
|
||||
} bal_assembler_t;
|
||||
} bal_assembler_t;
|
||||
|
||||
/// Initializes the assembler with a specific memory buffer and the size of the buffer in
|
||||
/// `uint32_t` elements.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * [`BAL_SUCCESS`] on success.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if `assembler` or `buffer` is NULL.
|
||||
/// * [`BAL_ERROR_MEMORY_ALIGNMENT`] if `buffer` is not 4-byte aligned.
|
||||
bal_error_t bal_assembler_init(bal_assembler_t *assembler,
|
||||
/// Initializes the assembler with a specific memory buffer and the size of the buffer in
|
||||
/// `uint32_t` elements.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * [`BAL_SUCCESS`] on success.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if `assembler` or `buffer` is NULL.
|
||||
/// * [`BAL_ERROR_MEMORY_ALIGNMENT`] if `buffer` is not 4-byte aligned.
|
||||
bal_error_t bal_assembler_init(bal_assembler_t *assembler,
|
||||
void *buffer,
|
||||
size_t size,
|
||||
bal_logger_t logger);
|
||||
|
||||
/// Emit a `ADD` (Immediate) instruction.
|
||||
///
|
||||
/// Adds a register value `rn` and 12 bit immediate value `imm12` with the optional left shift `sh`
|
||||
/// to apply to the immediate, and writes the result to the destination register `rd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `rn` will be truncated if it exceeds 5 bits.
|
||||
/// * `imm12` will be truncated if it exceeds 12 bits.
|
||||
/// * `sh` must have the value `0`, or `1`
|
||||
/// * Function does not emit instructions if `assembler->status != BALL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_add_immediate(
|
||||
bal_assembler_t *assembler, bal_register_index_t rd, uint8_t rn, uint16_t imm12, uint8_t shift);
|
||||
/// Emit a `ADD` (Immediate) instruction.
|
||||
///
|
||||
/// Adds a register value `rn` and 12 bit immediate value `imm12` with the optional left shift
|
||||
/// `sh` to apply to the immediate, and writes the result to the destination register `rd`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `rn` will be truncated if it exceeds 5 bits.
|
||||
/// * `imm12` will be truncated if it exceeds 12 bits.
|
||||
/// * `sh` must have the value `0`, or `1`
|
||||
/// * Function does not emit instructions if `assembler->status != BALL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_add_immediate(bal_assembler_t *assembler,
|
||||
bal_register_index_t rd,
|
||||
uint8_t rn,
|
||||
uint16_t imm12,
|
||||
uint8_t shift);
|
||||
|
||||
/// Emit a `MOVZ` (Move Wide with Zero) instruction.
|
||||
///
|
||||
/// Moves a 16-bit immediate into a register, shifting it left by 0, 16, 32, or 48 bits, and
|
||||
/// the rest of the register to zero.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `shift` must be 0, 16, 32, or 48.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_movz(bal_assembler_t *assembler,
|
||||
/// Emit a `MOVZ` (Move Wide with Zero) instruction.
|
||||
///
|
||||
/// Moves a 16-bit immediate into a register, shifting it left by 0, 16, 32, or 48 bits, and
|
||||
/// the rest of the register to zero.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `shift` must be 0, 16, 32, or 48.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_movz(bal_assembler_t *assembler,
|
||||
bal_register_index_t rd,
|
||||
uint16_t imm,
|
||||
uint8_t shift);
|
||||
|
||||
/// Emits a `MOVK` (Move Wide with Keep) instruction.
|
||||
///
|
||||
/// Moves a 16-bit immediate into a specific 16-bit field of a register, leaving the other bits
|
||||
/// unchanged.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `shift` must be 0, 16, 32, or 48.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_movk(bal_assembler_t *assembler,
|
||||
/// Emits a `MOVK` (Move Wide with Keep) instruction.
|
||||
///
|
||||
/// Moves a 16-bit immediate into a specific 16-bit field of a register, leaving the other bits
|
||||
/// unchanged.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `shift` must be 0, 16, 32, or 48.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_movk(bal_assembler_t *assembler,
|
||||
bal_register_index_t rd,
|
||||
uint16_t imm,
|
||||
uint8_t shift);
|
||||
|
||||
/// Emits a `MOVN` (Move Wide with Not) instruction.
|
||||
///
|
||||
/// Moves the bitwise inverse of a 16-bit immediate (shifted left) into a register, setting all
|
||||
/// other bits to 1.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `shift` must be 0, 16, 32, or 48.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_movn(bal_assembler_t *assembler,
|
||||
/// Emits a `MOVN` (Move Wide with Not) instruction.
|
||||
///
|
||||
/// Moves the bitwise inverse of a 16-bit immediate (shifted left) into a register, setting all
|
||||
/// other bits to 1.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `shift` must be 0, 16, 32, or 48.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_movn(bal_assembler_t *assembler,
|
||||
bal_register_index_t rd,
|
||||
uint16_t imm,
|
||||
uint8_t shift);
|
||||
|
||||
/// Emits a `RET` instruction.
|
||||
///
|
||||
/// Returns from subroutine branches unconditionally to an address in a register with a hint that
|
||||
/// this is a subroutine return.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `rn` must be between 0-31 inclusive.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_ret(bal_assembler_t *assembler, bal_register_index_t rn);
|
||||
/// Emits a `RET` instruction.
|
||||
///
|
||||
/// Returns from subroutine branches unconditionally to an address in a register with a hint
|
||||
/// that this is a subroutine return.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `rn` must be between 0-31 inclusive.
|
||||
/// * Does not emit if `assembler->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Modifies `assembler->status` to the following if an error occurs:
|
||||
///
|
||||
/// * [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if `assembler->offset >= assembler->capacity`.
|
||||
/// * [`BAL_ERROR_INVALID_ARGUMENT`] if function arguments are invalid.
|
||||
void bal_emit_ret(bal_assembler_t *assembler, bal_register_index_t rn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BALLISTIC_ASSEMBLER_H */
|
||||
|
||||
|
||||
+15
-2
@@ -3,8 +3,17 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void bal_internal_assert_fail(
|
||||
const char *file, int line, const char *func, const char *expr_str, const char *user_msg, ...);
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void bal_internal_assert_fail(const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *expr_str,
|
||||
const char *user_msg,
|
||||
...);
|
||||
|
||||
#define BAL_ASSERT(expression) \
|
||||
do \
|
||||
@@ -33,4 +42,8 @@ void bal_internal_assert_fail(
|
||||
"Unreachable code executed", \
|
||||
##__VA_ARGS__);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // BALLISTIC_COMMON_ASSERT_H
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
#include "bal_platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/// BAL_HOT()/BAL_COLD()
|
||||
/// Marks a function as hot or cold. Hot makes the compiler optimize it more
|
||||
/// aggressively. Cold marks the function as rarely executed.
|
||||
@@ -77,6 +82,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BALLISTIC_ATTRIBUTES_H */
|
||||
|
||||
/*** end of file ***/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define BAL_OPERANDS_SIZE 5
|
||||
#define BAL_OPERAND_BIT_WIDTH 5
|
||||
@@ -91,5 +91,5 @@ extern "C"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
#endif // BAL_DECODER_H
|
||||
|
||||
+70
-60
@@ -8,6 +8,11 @@
|
||||
#include "bal_types.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/// A byte pattern written to memory during initialization, poisoning allocated
|
||||
/// regions. This is mainly used for detecting reads from uninitialized memory.
|
||||
#define POISON_UNINITIALIZED_MEMORY 0xFF
|
||||
@@ -40,24 +45,24 @@
|
||||
/// The bit position for the is constant flag in a bal_instruction_t.
|
||||
#define BAL_IS_CONSTANT_BIT_POSITION (1U << 16U)
|
||||
|
||||
/// Represents the mapping of a Guest Register to an SSA variable.
|
||||
/// This is only used during Single Static Assignment construction
|
||||
/// to track variable definitions across basic blocks.
|
||||
typedef struct
|
||||
{
|
||||
/// Represents the mapping of a Guest Register to an SSA variable.
|
||||
/// This is only used during Single Static Assignment construction
|
||||
/// to track variable definitions across basic blocks.
|
||||
typedef struct
|
||||
{
|
||||
/// The index of the most recent SSA definition for this register.
|
||||
uint32_t current_ssa_index;
|
||||
|
||||
/// The index of the SSA definition that existed at the start of the
|
||||
/// current block.
|
||||
uint32_t original_variable_index;
|
||||
} bal_source_variable_t;
|
||||
} bal_source_variable_t;
|
||||
|
||||
/// Holds the Intermediate Representation buffers, SSA state, and other
|
||||
/// important metadata. The structure is divided into hot and cold data aligned
|
||||
/// to 64 bytes. Both hot and cold data lives on their own cache lines.
|
||||
typedef struct
|
||||
{
|
||||
/// Holds the Intermediate Representation buffers, SSA state, and other
|
||||
/// important metadata. The structure is divided into hot and cold data aligned
|
||||
/// to 64 bytes. Both hot and cold data lives on their own cache lines.
|
||||
typedef struct
|
||||
{
|
||||
/* Hot Data */
|
||||
|
||||
/// Map of ARM registers to their current SSA definitions.
|
||||
@@ -112,64 +117,69 @@ typedef struct
|
||||
/// Handles logging for this engine.
|
||||
bal_logger_t logger;
|
||||
|
||||
} bal_engine_t;
|
||||
} bal_engine_t;
|
||||
|
||||
/// Initializes a Ballistic engine.
|
||||
///
|
||||
/// Populates `engine` with `logger` and empty buffers allocated with `allocator`. This is
|
||||
/// a high-cost memory operation that reserves a lot of memory and should
|
||||
/// be called sparingly.
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] if the engine iz ready for use.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if the pointers are `NULL`.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_ALLOCATION_FAILED`] if the allocator cannot fulfill the
|
||||
/// request.
|
||||
BAL_COLD bal_error_t bal_engine_init(const bal_allocator_t *allocator,
|
||||
/// Initializes a Ballistic engine.
|
||||
///
|
||||
/// Populates `engine` with `logger` and empty buffers allocated with `allocator`. This is
|
||||
/// a high-cost memory operation that reserves a lot of memory and should
|
||||
/// be called sparingly.
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] if the engine iz ready for use.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if the pointers are `NULL`.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_ALLOCATION_FAILED`] if the allocator cannot fulfill the
|
||||
/// request.
|
||||
BAL_COLD bal_error_t bal_engine_init(const bal_allocator_t *allocator,
|
||||
bal_engine_t *engine,
|
||||
bal_logger_t logger);
|
||||
|
||||
/// Translates machine code starting at `guest_address_start` into the engine's
|
||||
/// internal IR. `interface` provides memory access handling (like instruction
|
||||
/// fetching).
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] on success.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If `guest_address_staart` is `NULL`, we assume the entry point is 0x0.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if functino arguments are invalid or
|
||||
/// or `engine->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if the array `engine->constants` overflows.
|
||||
BAL_HOT bal_error_t bal_engine_translate(bal_engine_t *BAL_RESTRICT engine,
|
||||
/// Translates machine code starting at `guest_address_start` into the engine's
|
||||
/// internal IR. `interface` provides memory access handling (like instruction
|
||||
/// fetching).
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] on success.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If `guest_address_staart` is `NULL`, we assume the entry point is 0x0.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if functino arguments are invalid or
|
||||
/// or `engine->status != BAL_SUCCESS`.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INSTRUCTION_OVERFLOW`] if the array `engine->constants` overflows.
|
||||
BAL_HOT bal_error_t bal_engine_translate(bal_engine_t *BAL_RESTRICT engine,
|
||||
const bal_memory_interface_t *BAL_RESTRICT interface,
|
||||
bal_guest_address_t *guest_address_start,
|
||||
size_t max_instructions);
|
||||
|
||||
/// Resets `engine` for the next compilation unit. This is a low-cost memory
|
||||
/// operation designed to be called between translation units.
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] on success.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if `engine` is `NULl`.
|
||||
BAL_HOT bal_error_t bal_engine_reset(bal_engine_t *engine);
|
||||
/// Resets `engine` for the next compilation unit. This is a low-cost memory
|
||||
/// operation designed to be called between translation units.
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] on success.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if `engine` is `NULl`.
|
||||
BAL_HOT bal_error_t bal_engine_reset(bal_engine_t *engine);
|
||||
|
||||
/// Frees all `engine` heap-allocated resources using `allocator`.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This function does not free the [`bal_engine_t`] struct itself, as the
|
||||
/// caller may have allocated it on the stack.
|
||||
BAL_COLD void bal_engine_destroy(const bal_allocator_t *allocator, bal_engine_t *engine);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/// Frees all `engine` heap-allocated resources using `allocator`.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This function does not free the [`bal_engine_t`] struct itself, as the
|
||||
/// caller may have allocated it on the stack.
|
||||
BAL_COLD void bal_engine_destroy(const bal_allocator_t *allocator, bal_engine_t *engine);
|
||||
#endif /* BALLISTIC_ENGINE_H */
|
||||
|
||||
/*** end of file ***/
|
||||
|
||||
+13
-4
@@ -8,8 +8,13 @@
|
||||
|
||||
#include "bal_attributes.h"
|
||||
|
||||
typedef enum
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// General Errors.
|
||||
//
|
||||
BAL_SUCCESS = 0,
|
||||
@@ -30,10 +35,14 @@ typedef enum
|
||||
|
||||
/// The decoded register type does not match the expected type.
|
||||
BAL_ERROR_INCORRECT_REGISTER_TYPE = -101,
|
||||
} bal_error_t;
|
||||
} bal_error_t;
|
||||
|
||||
/// Converts the enum into a readable string for error handling.
|
||||
BAL_COLD const char *bal_error_to_string(bal_error_t error);
|
||||
/// Converts the enum into a readable string for error handling.
|
||||
BAL_COLD const char *bal_error_to_string(bal_error_t error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BAL_ERRORS_H */
|
||||
|
||||
|
||||
+47
-37
@@ -58,9 +58,14 @@
|
||||
#include "bal_attributes.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
/// Defines the severity of a log message.
|
||||
typedef enum
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/// Defines the severity of a log message.
|
||||
typedef enum
|
||||
{
|
||||
/// Logging is disabled.
|
||||
BAL_LOG_LEVEL_NONE = -1,
|
||||
|
||||
@@ -78,11 +83,11 @@ typedef enum
|
||||
|
||||
/// Extreme verbose output.
|
||||
BAL_LOG_LEVEL_TRACE = 4,
|
||||
} bal_log_level_t;
|
||||
} bal_log_level_t;
|
||||
|
||||
/// Metadata associated with a specific log event.
|
||||
typedef struct
|
||||
{
|
||||
/// Metadata associated with a specific log event.
|
||||
typedef struct
|
||||
{
|
||||
/// Source file where the log occurred.
|
||||
const char *filename;
|
||||
|
||||
@@ -94,22 +99,22 @@ typedef struct
|
||||
|
||||
/// The line number where the log occurred
|
||||
int line;
|
||||
} bal_log_data_t;
|
||||
} bal_log_data_t;
|
||||
|
||||
/// A function pointer defining a custom logging backend.
|
||||
///
|
||||
/// Implementations of this function are responsible for formatting and persisting the log
|
||||
/// message. The `user_data` pointer is passed through from the `bal_logger_t` context. The
|
||||
/// `bal_data` struct contains metadata about the event, while `format`, and `args` provide the
|
||||
/// standard printf-style message content.
|
||||
typedef void (*bal_log_function_t)(void *user_data,
|
||||
/// A function pointer defining a custom logging backend.
|
||||
///
|
||||
/// Implementations of this function are responsible for formatting and persisting the log
|
||||
/// message. The `user_data` pointer is passed through from the `bal_logger_t` context. The
|
||||
/// `bal_data` struct contains metadata about the event, while `format`, and `args` provide the
|
||||
/// standard printf-style message content.
|
||||
typedef void (*bal_log_function_t)(void *user_data,
|
||||
bal_log_data_t *bal_data,
|
||||
const char *format,
|
||||
va_list args);
|
||||
|
||||
/// The main logging context.
|
||||
typedef struct
|
||||
{
|
||||
/// The main logging context.
|
||||
typedef struct
|
||||
{
|
||||
/// An opaque pointer passed to the log callback. This can be used to store file handles or
|
||||
/// other context-specific data.
|
||||
void *user_data;
|
||||
@@ -120,7 +125,7 @@ typedef struct
|
||||
|
||||
/// The minimum severity level required for a message to be processed.
|
||||
bal_log_level_t min_level;
|
||||
} bal_logger_t;
|
||||
} bal_logger_t;
|
||||
|
||||
// Remove all log code if log level not defined.
|
||||
//
|
||||
@@ -130,20 +135,21 @@ typedef struct
|
||||
|
||||
#endif
|
||||
|
||||
/// Dispatches a log message to the configured backend.
|
||||
///
|
||||
/// This is the entry point into the logging system. It invokes the callback defined in `logger`.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// Do not call this function directly. Use our logging macros like `BAL_LOG_INFO`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `format` string must match the arguments provided in the variadic list, following standard
|
||||
/// `printf`.
|
||||
/// Dispatches a log message to the configured backend.
|
||||
///
|
||||
/// This is the entry point into the logging system. It invokes the callback defined in
|
||||
/// `logger`.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// Do not call this function directly. Use our logging macros like `BAL_LOG_INFO`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `format` string must match the arguments provided in the variadic list, following
|
||||
/// standard `printf`.
|
||||
|
||||
BAL_COLD void bal_log_message(const bal_logger_t *logger,
|
||||
BAL_COLD void bal_log_message(const bal_logger_t *logger,
|
||||
bal_log_level_t log_level,
|
||||
const char *filename,
|
||||
const char *function,
|
||||
@@ -151,12 +157,12 @@ BAL_COLD void bal_log_message(const bal_logger_t *logger,
|
||||
const char *format,
|
||||
...);
|
||||
|
||||
/// Populates `logger` with Ballistic's default logging implementation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `logger` must NOT be `NULL`.
|
||||
BAL_COLD void bal_logger_init_default(bal_logger_t *logger);
|
||||
/// Populates `logger` with Ballistic's default logging implementation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `logger` must NOT be `NULL`.
|
||||
BAL_COLD void bal_logger_init_default(bal_logger_t *logger);
|
||||
|
||||
#define BAL_LOG_ERROR(logger, format, ...) \
|
||||
bal_log_message((logger), \
|
||||
@@ -212,6 +218,10 @@ BAL_COLD void bal_logger_init_default(bal_logger_t *logger);
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BALLISTIC_LOGGING_H */
|
||||
|
||||
/*** end of file ***/
|
||||
|
||||
+100
-88
@@ -8,55 +8,62 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct bal_allocator_state_s;
|
||||
typedef struct bal_allocator_state_s *bal_allocator_handle_t;
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/// A function signature for allocating aligned memory.
|
||||
///
|
||||
/// Implementations must allocate a block of memory of at least `size` bytes
|
||||
/// with an address that is a multiple of `alignment`. The `alignment`
|
||||
/// parameter is guaranteed to be a power of two. The `allocator` parameter
|
||||
/// provides access to the opaque state registered in [`bal_allocator_t`].
|
||||
///
|
||||
/// Returns a pointer to the allocated memory, or `NULL` if the request could
|
||||
/// not be fulfilled.
|
||||
typedef void *(*bal_allocate_function_t)(bal_allocator_handle_t allocator,
|
||||
struct bal_allocator_state_s;
|
||||
typedef struct bal_allocator_state_s *bal_allocator_handle_t;
|
||||
|
||||
/// A function signature for allocating aligned memory.
|
||||
///
|
||||
/// Implementations must allocate a block of memory of at least `size` bytes
|
||||
/// with an address that is a multiple of `alignment`. The `alignment`
|
||||
/// parameter is guaranteed to be a power of two. The `allocator` parameter
|
||||
/// provides access to the opaque state registered in [`bal_allocator_t`].
|
||||
///
|
||||
/// Returns a pointer to the allocated memory, or `NULL` if the request could
|
||||
/// not be fulfilled.
|
||||
typedef void *(*bal_allocate_function_t)(bal_allocator_handle_t allocator,
|
||||
size_t alignment,
|
||||
size_t size);
|
||||
|
||||
/// A function signature for releasing memory.
|
||||
///
|
||||
/// Implementations must deallocate the memory at `pointer`, which was
|
||||
/// previously allocated by the corresponding to allocate function. The `size`
|
||||
/// parameter indicates the size of the allocation being freed. Access to the
|
||||
/// heap state is provided via `allocator`.
|
||||
typedef void (*bal_free_function_t)(bal_allocator_handle_t allocator, void *pointer, size_t size);
|
||||
/// A function signature for releasing memory.
|
||||
///
|
||||
/// Implementations must deallocate the memory at `pointer`, which was
|
||||
/// previously allocated by the corresponding to allocate function. The `size`
|
||||
/// parameter indicates the size of the allocation being freed. Access to the
|
||||
/// heap state is provided via `allocator`.
|
||||
typedef void (*bal_free_function_t)(bal_allocator_handle_t allocator,
|
||||
void *pointer,
|
||||
size_t size);
|
||||
|
||||
/// Translates a Guest Virtual Address (GVA) to a Host Virtual Address (HVA).
|
||||
///
|
||||
/// Ballistic invokes this callback when it needs to fetch instructions or
|
||||
/// access data.
|
||||
///
|
||||
/// Returns a pointer to the host memory containing the data at `guest_address`, or `NULL`
|
||||
/// if the address is unmapped or invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The implementation must translate the provided `guest_address`
|
||||
/// using the opaque `context` and return a pointer to the corresponding host
|
||||
/// memory.
|
||||
///
|
||||
/// The implementation must write the number of contiguous, readable bytes
|
||||
/// available at the returned pointer into `max_readable_size_bytes`. This prevents
|
||||
/// Ballistic from reading beyond the end of a mapped page or buffer.
|
||||
typedef const uint8_t *(*bal_translate_function_t)(void *context,
|
||||
/// Translates a Guest Virtual Address (GVA) to a Host Virtual Address (HVA).
|
||||
///
|
||||
/// Ballistic invokes this callback when it needs to fetch instructions or
|
||||
/// access data.
|
||||
///
|
||||
/// Returns a pointer to the host memory containing the data at `guest_address`, or `NULL`
|
||||
/// if the address is unmapped or invalid.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The implementation must translate the provided `guest_address`
|
||||
/// using the opaque `context` and return a pointer to the corresponding host
|
||||
/// memory.
|
||||
///
|
||||
/// The implementation must write the number of contiguous, readable bytes
|
||||
/// available at the returned pointer into `max_readable_size_bytes`. This prevents
|
||||
/// Ballistic from reading beyond the end of a mapped page or buffer.
|
||||
typedef const uint8_t *(*bal_translate_function_t)(void *context,
|
||||
bal_guest_address_t guest_address,
|
||||
size_t *max_readable_size_bytes);
|
||||
|
||||
/// The host application is responsible for providing an allocator capable of
|
||||
/// handling aligned memory requests.
|
||||
typedef struct
|
||||
{
|
||||
/// The host application is responsible for providing an allocator capable of
|
||||
/// handling aligned memory requests.
|
||||
typedef struct
|
||||
{
|
||||
/// An opaque pointer defining the state or tracking information for the
|
||||
/// heap.
|
||||
bal_allocator_handle_t handle;
|
||||
@@ -72,68 +79,73 @@ typedef struct
|
||||
/// The callback to release memory.
|
||||
bal_free_function_t free;
|
||||
|
||||
} bal_allocator_t;
|
||||
} bal_allocator_t;
|
||||
|
||||
/// Defines the interface for translating guest addresses to host memory.
|
||||
typedef struct
|
||||
{
|
||||
/// Defines the interface for translating guest addresses to host memory.
|
||||
typedef struct
|
||||
{
|
||||
/// An opaque pointer to the context required for address translation
|
||||
/// (e.g, a page walker or a buffer descriptor.).
|
||||
void *context;
|
||||
|
||||
/// The callback invoked to perform address translation.
|
||||
bal_translate_function_t translate;
|
||||
} bal_memory_interface_t;
|
||||
} bal_memory_interface_t;
|
||||
|
||||
/// Populates `out_allocator` with the default system implementation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `out_allocator` must not be `NULL`.
|
||||
///
|
||||
/// # Platform Support
|
||||
///
|
||||
/// This function only supports windows and POSIX-compliant systems.
|
||||
BAL_COLD void bal_allocator_default_init(bal_allocator_t *out_allocator);
|
||||
/// Populates `out_allocator` with the default system implementation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `out_allocator` must not be `NULL`.
|
||||
///
|
||||
/// # Platform Support
|
||||
///
|
||||
/// This function only supports windows and POSIX-compliant systems.
|
||||
BAL_COLD void bal_allocator_default_init(bal_allocator_t *out_allocator);
|
||||
|
||||
/// Initializes a flat, contiguous translation interface.
|
||||
///
|
||||
/// This convenience function sets up a [`bal_memory_interface_t`] where guest
|
||||
/// addresses map directly to offsets within the provided host `buffer`.
|
||||
///
|
||||
/// The internal interface is allocated with `allocator`. `interface` is
|
||||
/// populated with the resulting context and translation callbacks. `buffer`
|
||||
/// must be a pre-allocated block of host memory of at least `size` bytes.
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] on success.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if any pointer are `NULL`.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_MEMORY_ALIGNMENT`] if `buffer` is not aligned to a 16-byte
|
||||
/// boundary.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_ALLOCATION_FAILED`] if failed to allocate memory interface.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller retains ownership of `buffer`. It must remain valid and
|
||||
/// unmodified for the lifetime of the created interface.
|
||||
BAL_COLD bal_error_t
|
||||
bal_flat_translation_interface_init(bal_allocator_t *BAL_RESTRICT allocator,
|
||||
/// Initializes a flat, contiguous translation interface.
|
||||
///
|
||||
/// This convenience function sets up a [`bal_memory_interface_t`] where guest
|
||||
/// addresses map directly to offsets within the provided host `buffer`.
|
||||
///
|
||||
/// The internal interface is allocated with `allocator`. `interface` is
|
||||
/// populated with the resulting context and translation callbacks. `buffer`
|
||||
/// must be a pre-allocated block of host memory of at least `size` bytes.
|
||||
///
|
||||
/// Returns [`BAL_SUCCESS`] on success.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`BAL_ERROR_INVALID_ARGUMENT`] if any pointer are `NULL`.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_MEMORY_ALIGNMENT`] if `buffer` is not aligned to a 16-byte
|
||||
/// boundary.
|
||||
///
|
||||
/// Returns [`BAL_ERROR_ALLOCATION_FAILED`] if failed to allocate memory interface.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller retains ownership of `buffer`. It must remain valid and
|
||||
/// unmodified for the lifetime of the created interface.
|
||||
BAL_COLD bal_error_t
|
||||
bal_flat_translation_interface_init(bal_allocator_t *BAL_RESTRICT allocator,
|
||||
bal_memory_interface_t *BAL_RESTRICT interface,
|
||||
void *BAL_RESTRICT buffer,
|
||||
size_t size,
|
||||
bal_logger_t logger);
|
||||
|
||||
/// Frees the internal state allocated within `interface` using the provided
|
||||
/// `allocator` and resets `interface` to 0 with a memset.
|
||||
///
|
||||
/// This does **not** free the buffer passed to [`bal_flat_translation_interface_init`] as
|
||||
/// Ballistic does not take ownership of the host memory region.
|
||||
BAL_COLD bal_error_t bal_flat_translation_interface_destroy(bal_allocator_t *allocator,
|
||||
/// Frees the internal state allocated within `interface` using the provided
|
||||
/// `allocator` and resets `interface` to 0 with a memset.
|
||||
///
|
||||
/// This does **not** free the buffer passed to [`bal_flat_translation_interface_init`] as
|
||||
/// Ballistic does not take ownership of the host memory region.
|
||||
BAL_COLD bal_error_t bal_flat_translation_interface_destroy(bal_allocator_t *allocator,
|
||||
bal_memory_interface_t *interface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BALLISTIC_MEMORY_H */
|
||||
|
||||
/*** end of file ***/
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#ifndef BALLISTIC_PLATFORM_H
|
||||
#define BALLISTIC_PLATFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#define BAL_PLATFORM_WINDOWS 1
|
||||
@@ -49,4 +54,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BALLISTIC_PLATFORM_H */
|
||||
|
||||
/*** end of file ***/
|
||||
|
||||
+21
-12
@@ -8,15 +8,20 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint64_t bal_guest_address_t;
|
||||
typedef uint64_t bal_instruction_t;
|
||||
typedef uint64_t bal_constant_t;
|
||||
typedef uint16_t bal_instruction_count_t;
|
||||
typedef uint16_t bal_constant_count_t;
|
||||
typedef uint8_t bal_bit_width_t;
|
||||
|
||||
typedef enum
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef uint64_t bal_guest_address_t;
|
||||
typedef uint64_t bal_instruction_t;
|
||||
typedef uint64_t bal_constant_t;
|
||||
typedef uint16_t bal_instruction_count_t;
|
||||
typedef uint16_t bal_constant_count_t;
|
||||
typedef uint8_t bal_bit_width_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/// This opcode represents a volatile load of a guest register.
|
||||
OPCODE_GET_REGISTER,
|
||||
OPCODE_CONST,
|
||||
@@ -41,10 +46,10 @@ typedef enum
|
||||
OPCODE_CMP_COND,
|
||||
OPCODE_TRAP,
|
||||
OPCODE_ENUM_END = 0x7FF, // Force enum to 2 bytes.
|
||||
} bal_opcode_t;
|
||||
} bal_opcode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
/// The register index for X0.
|
||||
BAL_REGISTER_X0 = 0,
|
||||
|
||||
@@ -140,7 +145,11 @@ typedef enum
|
||||
|
||||
/// The register index for the Zero Register (XZR)/Stack Pointer (SP).
|
||||
BAL_REGISTER_X31 = 31,
|
||||
} bal_register_index_t;
|
||||
} bal_register_index_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BALLISTIC_TYPES_H */
|
||||
|
||||
|
||||
@@ -3,19 +3,32 @@
|
||||
* Generated with tools/generate_a64_table.py
|
||||
*/
|
||||
|
||||
#ifndef BAL_DECODER_TABLE_GENERATED
|
||||
#define BAL_DECODER_TABLE_GENERATED
|
||||
|
||||
#include "bal_decoder.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define BAL_DECODER_ARM64_INSTRUCTIONS_SIZE 3608
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint16_t index;
|
||||
uint8_t count;
|
||||
} decoder_bucket_t;
|
||||
} decoder_bucket_t;
|
||||
|
||||
extern const bal_decoder_instruction_metadata_t g_bal_decoder_arm64_instructions[BAL_DECODER_ARM64_INSTRUCTIONS_SIZE];
|
||||
extern const decoder_bucket_t g_decoder_lookup_table[2048];
|
||||
extern const bal_decoder_instruction_metadata_t
|
||||
g_bal_decoder_arm64_instructions[BAL_DECODER_ARM64_INSTRUCTIONS_SIZE];
|
||||
extern const decoder_bucket_t g_decoder_lookup_table[2048];
|
||||
extern const bal_decoder_instruction_metadata_t *const g_decoder_hash_candidates[];
|
||||
|
||||
extern const bal_decoder_instruction_metadata_t *const g_decoder_hash_candidates[];
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* BAL_DECODER_TABLE_GENERATED */
|
||||
|
||||
/*** end of file ***/
|
||||
|
||||
+17
-10
@@ -10,17 +10,17 @@ Generated ARM decoder table header file -> ../src/decoder_table_gen.h
|
||||
Generated ARM decoder table source file -> ../src/decoder_table_gen.c
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import glob
|
||||
import argparse
|
||||
import xml.etree.ElementTree as ET
|
||||
from xml.etree.ElementTree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
from xml.etree.ElementTree import Element
|
||||
from xml.etree.ElementTree import ElementTree
|
||||
|
||||
DEFAULT_DECODER_GENERATED_HEADER_NAME = "bal_decoder_table_gen.h"
|
||||
DEFAULT_DECODER_GENERATED_SOURCE_NAME = "bal_decoder_table_gen.c"
|
||||
@@ -266,8 +266,6 @@ def parse_operands(
|
||||
if operand_type == "BAL_OPERAND_TYPE_NONE":
|
||||
continue
|
||||
|
||||
|
||||
|
||||
operand: Operand = Operand(operand_type, bit_position, bit_width)
|
||||
|
||||
if operand not in operands:
|
||||
@@ -569,9 +567,14 @@ if __name__ == "__main__":
|
||||
# -------------------------------------------------------------------------
|
||||
with open(output_header_path, "w", encoding="utf-8") as f:
|
||||
f.write(f"{GENERATED_FILE_WARNING}\n\n")
|
||||
f.write("#ifndef BAL_DECODER_TABLE_GENERATED\n")
|
||||
f.write("#define BAL_DECODER_TABLE_GENERATED\n\n")
|
||||
f.write(f'#include "{DECODER_HEADER_NAME}"\n')
|
||||
f.write("#include <stdint.h>\n")
|
||||
f.write("#include <stddef.h>\n\n")
|
||||
f.write("#ifdef __cplusplus\n")
|
||||
f.write('extern "C"\n')
|
||||
f.write("{\n")
|
||||
f.write("#endif /* __cplusplus */\n\n")
|
||||
f.write(
|
||||
f"#define {DECODER_ARM64_INSTRUCTIONS_SIZE_NAME} {len(all_instructions)}\n\n"
|
||||
)
|
||||
@@ -583,11 +586,16 @@ if __name__ == "__main__":
|
||||
f"extern const {DECODER_METADATA_STRUCT_NAME} {DECODER_ARM64_INSTRUCTIONS_ARRAY_NAME}[{DECODER_ARM64_INSTRUCTIONS_SIZE_NAME}];\n"
|
||||
)
|
||||
f.write(
|
||||
f"extern const {DECODER_HASH_TABLE_BUCKET_STRUCT_NAME} g_decoder_lookup_table[{DECODER_HASH_TABLE_SIZE}];\n\n"
|
||||
f"extern const {DECODER_HASH_TABLE_BUCKET_STRUCT_NAME} g_decoder_lookup_table[{DECODER_HASH_TABLE_SIZE}];\n"
|
||||
)
|
||||
f.write(
|
||||
f"extern const {DECODER_METADATA_STRUCT_NAME} *const {DECODER_ARM64_CANDIDATES_ARRAY_NAME}[];\n\n"
|
||||
)
|
||||
f.write("#ifdef __cplusplus\n")
|
||||
f.write("}\n")
|
||||
f.write("#endif /* __cplusplus */\n")
|
||||
f.write("#endif /* BAL_DECODER_TABLE_GENERATED */\n\n")
|
||||
f.write("/*** end of file ***/\n\n")
|
||||
print(f"Generated ARM decoder table header file -> {output_header_path}")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -605,7 +613,7 @@ if __name__ == "__main__":
|
||||
# (start_index, count)
|
||||
bucket_descriptors: List[Tuple[int, int]] = []
|
||||
|
||||
for i in range (DECODER_HASH_TABLE_SIZE):
|
||||
for i in range(DECODER_HASH_TABLE_SIZE):
|
||||
candidate: List[A64Instruction] = buckets[i]
|
||||
count: int = len(candidate)
|
||||
|
||||
@@ -631,7 +639,6 @@ if __name__ == "__main__":
|
||||
|
||||
bucket_descriptors.append((start_index, count))
|
||||
|
||||
|
||||
if len(flat_candidates) >= 65535:
|
||||
printf("Total candidates {len(flat_candidates)} exceeds uint16_t limit.")
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user