Affix
view release on metacpan or search on metacpan
infix/src/arch/x64/abi_sysv_x64.c view on Meta::CPAN
.generate_forward_prologue = generate_forward_prologue_sysv_x64,
.generate_forward_argument_moves = generate_forward_argument_moves_sysv_x64,
.generate_forward_call_instruction = generate_forward_call_instruction_sysv_x64,
.generate_forward_epilogue = generate_forward_epilogue_sysv_x64};
/** The v-table of System V x64 functions for generating reverse trampolines. */
static infix_status prepare_reverse_call_frame_sysv_x64(infix_arena_t * arena,
infix_reverse_call_frame_layout ** out_layout,
infix_reverse_t * context);
static infix_status generate_reverse_prologue_sysv_x64(code_buffer * buf, infix_reverse_call_frame_layout * layout);
static infix_status generate_reverse_argument_marshalling_sysv_x64(code_buffer * buf,
infix_reverse_call_frame_layout * layout,
infix_reverse_t * context);
static infix_status generate_reverse_dispatcher_call_sysv_x64(code_buffer * buf,
infix_reverse_call_frame_layout * layout,
infix_reverse_t * context);
static infix_status generate_reverse_epilogue_sysv_x64(code_buffer * buf,
infix_reverse_call_frame_layout * layout,
infix_reverse_t * context);
const infix_reverse_abi_spec g_sysv_x64_reverse_spec = {
.prepare_reverse_call_frame = prepare_reverse_call_frame_sysv_x64,
.generate_reverse_prologue = generate_reverse_prologue_sysv_x64,
.generate_reverse_argument_marshalling = generate_reverse_argument_marshalling_sysv_x64,
.generate_reverse_dispatcher_call = generate_reverse_dispatcher_call_sysv_x64,
.generate_reverse_epilogue = generate_reverse_epilogue_sysv_x64};
/** The v-table for the new Direct Marshalling ABI. */
static infix_status prepare_direct_forward_call_frame_sysv_x64(infix_arena_t * arena,
infix_direct_call_frame_layout ** out_layout,
infix_type * ret_type,
infix_type ** arg_types,
size_t num_args,
infix_direct_arg_handler_t * handlers,
void * target_fn);
static infix_status generate_direct_forward_prologue_sysv_x64(code_buffer * buf,
infix_direct_call_frame_layout * layout);
static infix_status generate_direct_forward_argument_moves_sysv_x64(code_buffer * buf,
infix_direct_call_frame_layout * layout);
static infix_status generate_direct_forward_call_instruction_sysv_x64(code_buffer * buf,
infix_direct_call_frame_layout * layout);
static infix_status generate_direct_forward_epilogue_sysv_x64(code_buffer * buf,
infix_direct_call_frame_layout * layout,
infix_type * ret_type);
const infix_direct_forward_abi_spec g_sysv_x64_direct_forward_spec = {
.prepare_direct_forward_call_frame = prepare_direct_forward_call_frame_sysv_x64,
.generate_direct_forward_prologue = generate_direct_forward_prologue_sysv_x64,
.generate_direct_forward_argument_moves = generate_direct_forward_argument_moves_sysv_x64,
.generate_direct_forward_call_instruction = generate_direct_forward_call_instruction_sysv_x64,
.generate_direct_forward_epilogue = generate_direct_forward_epilogue_sysv_x64};
/**
* @internal
* @brief Recursively classifies the eightbytes of an aggregate type.
* @details This is the core of the complex System V classification algorithm. It traverses
* the fields of a struct/array, examining each 8-byte chunk ("eightbyte") and assigning it a
* class (INTEGER, SSE, MEMORY). The classification is "merged" according to ABI rules
* (e.g., if an eightbyte contains both INTEGER and SSE parts, it becomes INTEGER).
*
* @param type The type of the current member/element being examined.
* @param offset The byte offset of this member from the start of the aggregate.
* @param[in,out] classes An array of two `arg_class_t` that is updated during classification.
* @param depth The current recursion depth (to prevent stack overflow on malicious input).
* @param field_count A counter to prevent DoS from excessively complex types.
* @param is_bitfield True if the current member is a bitfield.
* @return `true` if a condition forcing MEMORY classification is found, `false` otherwise.
*/
static bool classify_recursive(
const infix_type * type, size_t offset, arg_class_t classes[2], int depth, size_t * field_count, bool is_bitfield) {
// A recursive call can be made with a NULL type (e.g., from a malformed array from fuzzer).
if (type == nullptr)
return false; // Terminate recusion path.
// Abort classification if the type is excessively complex or too deep. Give up and pass in memory.
if (*field_count > MAX_AGGREGATE_FIELDS_TO_CLASSIFY || depth > MAX_CLASSIFY_DEPTH) {
classes[0] = MEMORY;
return true;
}
// The ABI requires natural alignment for standard members.
// Bitfields are an exception: they are allowed to be unaligned relative to their
// base type's alignment, as long as they stay within their storage unit.
if (!is_bitfield && type->alignment != 0 && offset % type->alignment != 0) {
classes[0] = MEMORY;
return true;
}
// If a struct is packed, its layout is explicit and should not be inferred
// by recursive classification. Treat it as an opaque block of memory.
// For classification purposes, this is equivalent to an integer array.
if (type->category == INFIX_TYPE_PRIMITIVE) {
(*field_count)++;
// `long double` is a special case. It is passed in memory on the stack, not x87 registers.
if (is_long_double(type)) {
classes[0] = MEMORY;
return true;
}
// Consider all eightbytes that the primitive occupies, not just the starting offset.
size_t start_offset = offset;
// Check for overflow before calculating end_offset
if (type->size == 0)
return false;
if (start_offset > SIZE_MAX - (type->size - 1)) {
classes[0] = MEMORY;
return true;
}
size_t end_offset = start_offset + type->size - 1;
size_t start_eightbyte = start_offset / 8;
size_t end_eightbyte = end_offset / 8;
arg_class_t new_class = (is_float16(type) || is_float(type) || is_double(type)) ? SSE : INTEGER;
for (size_t index = start_eightbyte; index <= end_eightbyte && index < 2; ++index) {
// Merge the new class with the existing class for this eightbyte.
// The rule is: if an eightbyte contains both SSE and INTEGER parts, it is classified as INTEGER.
if (classes[index] != new_class)
classes[index] = (classes[index] == NO_CLASS) ? new_class : INTEGER;
}
return false;
}
if (type->category == INFIX_TYPE_POINTER) {
(*field_count)++;
size_t index = offset / 8;
if (index < 2 && classes[index] != INTEGER)
classes[index] = INTEGER; // Pointers are always INTEGER class. Merge with existing class.
return false;
}
( run in 2.253 seconds using v1.01-cache-2.11-cpan-98e64b0badf )