AED_X86_ENCODER(3) Library Functions Manual AED_X86_ENCODER(3)

AED_x86_encoder_alloc, AED_x86_encoder_free, AED_x86_encoder_reset, AED_x86_encoder_encode, AED_x86_encoder_encode_labels, AED_x86_encoder_encode_raw, AED_x86_encoder_set_label, AED_x86_encoder_set_label_at_offset, AED_x86_encoder_align, AED_x86_encoder_fill, AED_x86_encoder_get_buffer, AED_x86_encoder_get_buffer_length, AED_x86_encoder_has_error, AED_x86_encoder_get_error, AED_x86_operand_set_register, AED_x86_operand_set_memory_size, AED_x86_operand_set_memory_base, AED_x86_operand_set_memory_index, AED_x86_operand_set_memory_disp, AED_x86_operand_set_memory_offset, AED_x86_operand_set_memory_label, AED_x86_operand_set_memory_broadcast, AED_x86_operand_set_immediate, AED_x86_operand_set_opmask, AED_x86_operand_set_labelaed x86 encoder functions

/* -laed */
#include <aed/x86.h>

typedef void *
AED_alloc(void *ptr, size_t old_size, size_t new_size, void *opaque);

typedef void
AED_free(void *ptr, size_t size, void *opaque);

AED_x86_encoder *
AED_x86_encoder_alloc(AED_alloc alloc, AED_free free, void *opaque);

void
AED_x86_encoder_free(AED_x86_encoder *ec);

void
AED_x86_encoder_reset(AED_x86_encoder *ec);

size_t
AED_x86_encoder_encode(AED_x86_encoder *ec, AED_x86_mnemonic mnemonic, const AED_x86_operand *operands, uint32_t noperands);

int
AED_x86_encoder_encode_labels(AED_x86_encoder *ec, size_t offset);

size_t
AED_x86_encoder_encode_raw(AED_x86_encoder *ec, const uint8_t *raw, size_t raw_length);

void
AED_x86_encoder_set_label(AED_x86_encoder *ec, int label);

void
AED_x86_encoder_set_label_at_offset(AED_x86_encoder *ec, int label, size_t offset);

size_t
AED_x86_encoder_align(AED_x86_encoder *ec, uint32_t alignment);

size_t
AED_x86_encoder_fill(AED_x86_encoder *ec, uint32_t length);

const uint8_t *
AED_x86_encoder_get_buffer(const AED_x86_encoder *ec);

size_t
AED_x86_encoder_get_buffer_length(const AED_x86_encoder *ec);

int
AED_x86_encoder_has_error(const AED_x86_encoder *ec);

const char *
AED_x86_encoder_get_error(const AED_x86_encoder *ec);

void
AED_x86_operand_set_register(AED_x86_operand *operand, AED_x86_register reg);

void
AED_x86_operand_set_memory_size(AED_x86_operand *operand, uint32_t size);

void
AED_x86_operand_set_memory_base(AED_x86_operand *operand, AED_x86_register reg);

void
AED_x86_operand_set_memory_index(AED_x86_operand *operand, AED_x86_register reg, uint8_t scale);

void
AED_x86_operand_set_memory_disp(AED_x86_operand *operand, uint8_t size, int32_t disp);

void
AED_x86_operand_set_memory_offset(AED_x86_operand *operand, AED_x86_segment segment, uint64_t offset);

void
AED_x86_operand_set_memory_label(AED_x86_operand *operand, uint8_t size, int label);

void
AED_x86_operand_set_memory_broadcast(AED_x86_operand *operand);

void
AED_x86_operand_set_immediate(AED_x86_operand *operand, uint8_t size, int64_t imm);

void
AED_x86_operand_set_opmask(AED_x86_operand *operand, AED_x86_register opmask, uint8_t z);

void
AED_x86_operand_set_label(AED_x86_operand *operand, uint8_t size, int label);

The aed x86 encoder provides functions used to encode instructions targeting the x86 instruction set architecture.

The () function allocates a new encoder. All memory allocations performed by the encoder is done through the alloc callback which must conform to realloc(3) like semantics. Meaning, if the given ptr is not NULL the returned memory address must contain old_size number of bytes copied from ptr. The same returned memory address is always required to have a capacity of new_size. The encoder frees memory using the free callback which is guaranteed to never be given a NULL ptr argument. Note that opaque is passed as is to all callbacks.

The () function frees the encoder and all its associated memory.

The () function resets the instruction buffer, effectively discarding any previously encoded instruction(s).

The () function encodes the instruction identified by mnemonic, operands and noperands. The shortest possible instruction will always be favored with respect to the given arguments. Its return value is interpreted as follows:

> 0
Instruction successfully encoded. Returns the length of the encoded instruction.
= 0
Failed to encode instruction. Errors can be further diagnosed using ().

The () function appends raw_length number of bytes from raw to the instruction buffer. It returns raw_length on success and zero on error. Errors can be further diagnosed using AED_x86_encoder_get_error().

The () function aligns the instruction buffer to the next multiple of alignment using the longest possible NOP instruction(s). Its return value follows the same convention as the AED_x86_encoder_encode() function.

The () function fills the instruction buffer with the smallest amount of NOP instruction(s) that fits within length. Its return value follows the same convention as the AED_x86_encoder_encode() function.

The () function returns the instruction buffer, including all encoded instruction(s).

The () function returns the length of the instruction buffer as obtained through AED_x86_encoder_get_buffer().

The () function returns non-zero if an error was encountered during encoding. Implying that a previous invocation of AED_x86_encoder_encode() did not succeed.

The () function returns a human readable representation of the last encountered error during encoding. Note that this function will never return NULL despite an error being absent.

The () function annotates operand as referring to register reg. Note that operand must be zero initialized before calling this function.

The () function annotates operand as referring to memory of size number of bits. Calling this function is not mandatory as the encoder can infer the size from other operands. However, it can be used to disambiguate between instructions which only differs in terms of memory size. Note that operand must be zero initialized before calling this function.

The () function annotates operand as referring to memory using reg as the base register.

The () function annotates operand as referring to memory using reg as the index register. The same register can optionally be scaled using scale which treats 2, 4 and 8 as valid scalars. Passing a scale of 0 disables scaling.

The () function annotates operand as referring to memory using disp as the displacement of size number of bits.

The () function annotates operand as referring to a memory offset in segment segment. Note that operand must be zero initialized before calling this function.

The () function annotates operand as a broadcast in which the element loaded from memory will be broadcasted to all elements in the destination register. The element size is declared using the AED_x86_operand_set_memory_size() function.

The () function annotates operand as an immediate imm of size number of bits.

The () function annotates operand as using opmask as the opmask register. A non-zero z enables zeroing-masking, otherwise merging-masking is favored. Note that the AED_x86_operand_set_register() function must have been called with the same operand before calling this function.

The () function associates the current instruction buffer offset with label, allowing instructions to encode operands referring to the same offset using the () function and passing the same label.

The effective relative offsets for such operands are encoded by the () function, intended to be called after the final call to AED_x86_encoder_encode(). The offset argument can be used when the encoded instructions are expected to reside at certain offset in memory, affecting the effective relative offsets. The AED_x86_encoder_encode_labels() function returns non-zero on success and zero on error. Errors can be further diagnosed using AED_x86_encoder_get_error().

Instead of associating the current instruction buffer offset with a label, an explicit offset can be defined using the () function. Intended to be used when the encoded instructions are expected to reside at certain offset within memory.

Labels can be used to encode RIP-relative addressing using the () function.

/* Label for global accessed through RIP-relative addressing. */
static const int Lglobal = 0;

/* Position Lglobal at offset 0x1000. */
AED_x86_encoder_set_offset(ec, 0x1000);
AED_x86_encoder_set_label(ec, Lglobal);

/* Move Lglobal to register, instruction expected to reside at offset 0x2000. */
AED_x86_encoder_set_offset(ec, 0x2000);
AED_x86_operand operands[2] = {0};
AED_x86_operand_set_register(&operands[0], AED_X86_RAX);
AED_x86_operand_set_memory_size(&operands[1], 32);
AED_x86_operand_set_memory_label(&operands[1], 32, Lglobal);
AED_x86_encoder_encode(ec, AED_X86_MOV, operands, 2);
AED_x86_encoder_encode_labels(ec);

#include <aed/x86.h>

static void *
encoder_alloc(void *ptr, size_t old_size, size_t new_size, void *arg)
{
	return realloc(ptr, new_size);
}

static void
encoder_free(void *ptr, size_t size, void *arg)
{
	free(ptr);
}

int
main(void)
{
	AED_x86_encoder *ec = AED_x86_encoder_alloc(
	    encoder_alloc, encoder_free, NULL);

	/* xor rax, rax */
	{
		AED_x86_operand operands[2] = {0};
		AED_x86_operand_set_register(&operands[0], AED_X86_RAX);
		AED_x86_operand_set_register(&operands[1], AED_X86_RAX);
		AED_x86_encoder_encode(ec, AED_X86_XOR, operands, 2);
	}

	if (AED_x86_encoder_has_error(ec))
		errx(1, "%s", AED_x86_encoder_get_error(ec));

	AED_x86_encoder_free(ec);

	return 0;
}

Anton Lindqvist <anton@basename.se>

OpenBSD 7.8 June 8, 2025 AED_X86_ENCODER(3)