NAME
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_label —
aed x86 encoder functions
SYNOPSIS
/* -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);
DESCRIPTION
The aed x86 encoder provides functions used to encode instructions targeting the x86 instruction set architecture.
The
AED_x86_encoder_alloc()
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
AED_x86_encoder_free()
function frees the encoder and all its associated memory.
The
AED_x86_encoder_reset()
function resets the instruction buffer, effectively discarding any
previously encoded instruction(s).
The
AED_x86_encoder_encode()
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
AED_x86_encoder_get_error().
The
AED_x86_encoder_encode_raw()
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
AED_x86_encoder_align()
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
AED_x86_encoder_fill()
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
AED_x86_encoder_get_buffer()
function returns the instruction buffer, including all encoded
instruction(s).
The
AED_x86_encoder_get_buffer_length()
function returns the length of the instruction buffer as obtained through
AED_x86_encoder_get_buffer().
The
AED_x86_encoder_has_error()
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
AED_x86_encoder_get_error()
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
AED_x86_operand_set_register()
function annotates operand as referring to register
reg. Note that operand must be
zero initialized before calling this function.
The
AED_x86_operand_set_memory_size()
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
AED_x86_operand_set_memory_base()
function annotates operand as referring to memory
using reg as the base register.
The
AED_x86_operand_set_memory_index()
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
AED_x86_operand_set_memory_disp()
function annotates operand as referring to memory
using disp as the displacement of
size number of bits.
The
AED_x86_operand_set_memory_offset()
function annotates operand as referring to a memory
offset in segment segment. Note that
operand must be zero initialized before calling this
function.
The
AED_x86_operand_set_memory_broadcast()
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
AED_x86_operand_set_immediate()
function annotates operand as an immediate
imm of size number of bits.
The
AED_x86_operand_set_opmask()
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.
Encoding of jump labels
The
AED_x86_encoder_set_label()
function associates the current instruction buffer offset with
label, allowing instructions to encode operands
referring to the same offset using the
AED_x86_operand_set_label()
function and passing the same label.
The effective relative offsets
for such operands are encoded by the
AED_x86_encoder_encode_labels()
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
AED_x86_encoder_set_label_at_offset()
function. Intended to be used when the encoded instructions are expected to
reside at certain offset within memory.
Encoding of RIP-relative addressing
Labels can be used to encode RIP-relative addressing using the
AED_x86_operand_set_memory_label()
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);
EXAMPLES
#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;
}
AUTHORS
Anton Lindqvist <anton@basename.se>