general: Improve documentation
This commit is contained in:
@@ -67,8 +67,8 @@ failed |= fe_enc64(&cur, FE_XOR32rr, FE_AX, FE_AX);
|
||||
failed |= fe_enc64(&cur, FE_MOVZXr32m8, FE_CX, FE_MEM(FE_DI, 1, FE_AX, 0));
|
||||
// test ecx, ecx
|
||||
failed |= fe_enc64(&cur, FE_TEST32rr, FE_CX, FE_CX);
|
||||
// jz $
|
||||
// This will be replaced later FE_JMPL enforces use of longest offset
|
||||
// jnz $
|
||||
// This will be replaced later; FE_JMPL enforces use of longest offset
|
||||
uint8_t* fwd_jmp = cur;
|
||||
failed |= fe_enc64(&cur, FE_JNZ|FE_JMPL, (intptr_t) cur);
|
||||
uint8_t* loop_tgt = cur;
|
||||
@@ -104,8 +104,9 @@ The API consists of one function to handle encode requests, as well as some macr
|
||||
- For offset operands, specify the target address.
|
||||
|
||||
## Known issues
|
||||
- The encoder doesn't support VEX encodings (yet).
|
||||
- The EVEX prefix (AVX-512) is not supported (yet).
|
||||
- MPX instructions are not supported.
|
||||
- HLE prefixes `xacquire`/`xrelease` are not supported by the encoder (yet).
|
||||
- Prefixes for indirect jumps and calls are not properly decoded, e.g. `notrack`, `bnd`.
|
||||
- Low test coverage. (Help needed.)
|
||||
- No Python API.
|
||||
|
||||
24
fadec-enc.h
24
fadec-enc.h
@@ -22,16 +22,26 @@ typedef enum {
|
||||
|
||||
typedef int64_t FeOp;
|
||||
|
||||
/** Construct a memory operand. Unused parts can be set to 0 and will be
|
||||
* ignored. FE_IP can be used as base register, in which case the offset is
|
||||
* interpreted as the offset from the /current/ position -- the size of the
|
||||
* encoded instruction will be subtracted during encoding. scale must be 1, 2,
|
||||
* 4, or 8; but is ignored if idx == 0. **/
|
||||
#define FE_MEM(base,sc,idx,off) (INT64_MIN | ((int64_t) ((base) & 0xfff) << 32) | ((int64_t) ((idx) & 0xfff) << 44) | ((int64_t) ((sc) & 0xf) << 56) | ((off) & 0xffffffff))
|
||||
|
||||
/** Add segment override prefix. This may or may not generate prefixes for the
|
||||
* ignored prefixes ES/CS/DS/SS in 64-bit mode. **/
|
||||
#define FE_SEG(seg) ((((seg) & 0x7) + 1) << 16)
|
||||
/** Do not use. **/
|
||||
#define FE_SEG_MASK 0x70000
|
||||
/** Overrides address size. **/
|
||||
#define FE_ADDR32 0x80000
|
||||
/** Used together with a RIP-relative (conditional) jump, this will force the
|
||||
* use of the encoding with the largest distance. Useful for reserving a jump
|
||||
* when the target offset is still unknown; if the jump is re-encoded later on,
|
||||
* FE_JMPL must be specified there, too, so that the encoding lengths match. **/
|
||||
#define FE_JMPL 0x100000
|
||||
/** Do not use. **/
|
||||
#define FE_MNEM_MASK 0xffff
|
||||
|
||||
enum {
|
||||
@@ -41,8 +51,22 @@ enum {
|
||||
FE_MNEM_MAX
|
||||
};
|
||||
|
||||
/** Do not use. **/
|
||||
#define fe_enc64_1(buf, mnem, op0, op1, op2, op3, ...) fe_enc64_impl(buf, mnem, op0, op1, op2, op3)
|
||||
/** Encode a single instruction for 64-bit mode.
|
||||
* \param buf Pointer to the buffer for instruction bytes, must have a size of
|
||||
* 15 bytes. The pointer is advanced by the number of bytes used for
|
||||
* encoding the specified instruction.
|
||||
* \param mnem Mnemonic, optionally or-ed with FE_SEG(), FE_ADDR32, or FE_JMPL.
|
||||
* \param operands... Instruction operands. Immediate operands are passed as
|
||||
* plain value; register operands using the FeReg enum; memory operands
|
||||
* using FE_MEM(); and offset operands for RIP-relative jumps/calls are
|
||||
* specified as _address in buf_, e.g. (intptr_t) jmptgt, the address of
|
||||
* buf and the size of the encoded instruction are subtracted internally.
|
||||
* \return Zero for success or a negative value in case of an error.
|
||||
**/
|
||||
#define fe_enc64(buf, ...) fe_enc64_1(buf, __VA_ARGS__, 0, 0, 0, 0, 0)
|
||||
/** Do not use. **/
|
||||
int fe_enc64_impl(uint8_t** buf, uint64_t mnem, FeOp op0, FeOp op1, FeOp op2, FeOp op3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
8
fadec.h
8
fadec.h
@@ -42,6 +42,7 @@ enum {
|
||||
FD_FLAG_64 = 1 << 7,
|
||||
};
|
||||
|
||||
/** Operand types. **/
|
||||
typedef enum {
|
||||
FD_OT_NONE = 0,
|
||||
FD_OT_REG = 1,
|
||||
@@ -186,8 +187,7 @@ const char* fdi_name(FdInstrType ty);
|
||||
#define FD_HAS_REP(instr) ((instr)->flags & FD_FLAG_REP)
|
||||
/** Indicates whether the instruction was encoded with a REPNZ prefix. **/
|
||||
#define FD_HAS_REPNZ(instr) ((instr)->flags & FD_FLAG_REPNZ)
|
||||
/** Indicates whether the instruction was encoded with a LOCK prefix. Note that
|
||||
* it is not checked whether the LOCK prefix is valid for the instruction. **/
|
||||
/** Indicates whether the instruction was encoded with a LOCK prefix. **/
|
||||
#define FD_HAS_LOCK(instr) ((instr)->flags & FD_FLAG_LOCK)
|
||||
/** Do not use. **/
|
||||
#define FD_IS64(instr) ((instr)->flags & FD_FLAG_64)
|
||||
@@ -204,7 +204,7 @@ const char* fdi_name(FdInstrType ty);
|
||||
#define FD_OP_SIZE(instr,idx) ((instr)->operands[idx].size)
|
||||
/** Gets the accessed register index of a register operand. Note that /only/ the
|
||||
* index is returned, no further interpretation of the index (which depends on
|
||||
* the instruction type) is done. The register type can be fetches using
|
||||
* the instruction type) is done. The register type can be fetched using
|
||||
* FD_OP_REG_TYPE, e.g. for distinguishing high-byte registers.
|
||||
* Only valid if FD_OP_TYPE == FD_OT_REG **/
|
||||
#define FD_OP_REG(instr,idx) ((FdReg) (instr)->operands[idx].reg)
|
||||
@@ -236,7 +236,7 @@ const char* fdi_name(FdInstrType ty);
|
||||
* Only valid if FD_OP_TYPE == FD_OT_MEM **/
|
||||
#define FD_OP_DISP(instr,idx) ((int64_t) (instr)->disp)
|
||||
/** Gets the (sign-extended) encoded constant for an immediate operand.
|
||||
* Only valid if FD_OP_TYPE == FD_OT_IMM **/
|
||||
* Only valid if FD_OP_TYPE == FD_OT_IMM or FD_OP_TYPE == FD_OT_OFF **/
|
||||
#define FD_OP_IMM(instr,idx) ((instr)->imm)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user