general: Improve documentation

This commit is contained in:
Alexis Engelke
2021-04-02 11:31:28 +02:00
parent c99e860a5e
commit d67eb93148
3 changed files with 32 additions and 7 deletions

View File

@@ -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)); failed |= fe_enc64(&cur, FE_MOVZXr32m8, FE_CX, FE_MEM(FE_DI, 1, FE_AX, 0));
// test ecx, ecx // test ecx, ecx
failed |= fe_enc64(&cur, FE_TEST32rr, FE_CX, FE_CX); failed |= fe_enc64(&cur, FE_TEST32rr, FE_CX, FE_CX);
// jz $ // jnz $
// This will be replaced later FE_JMPL enforces use of longest offset // This will be replaced later; FE_JMPL enforces use of longest offset
uint8_t* fwd_jmp = cur; uint8_t* fwd_jmp = cur;
failed |= fe_enc64(&cur, FE_JNZ|FE_JMPL, (intptr_t) cur); failed |= fe_enc64(&cur, FE_JNZ|FE_JMPL, (intptr_t) cur);
uint8_t* loop_tgt = 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. - For offset operands, specify the target address.
## Known issues ## Known issues
- The encoder doesn't support VEX encodings (yet).
- The EVEX prefix (AVX-512) is not supported (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`. - Prefixes for indirect jumps and calls are not properly decoded, e.g. `notrack`, `bnd`.
- Low test coverage. (Help needed.) - Low test coverage. (Help needed.)
- No Python API. - No Python API.

View File

@@ -22,16 +22,26 @@ typedef enum {
typedef int64_t FeOp; 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)) #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) #define FE_SEG(seg) ((((seg) & 0x7) + 1) << 16)
/** Do not use. **/
#define FE_SEG_MASK 0x70000 #define FE_SEG_MASK 0x70000
/** Overrides address size. **/
#define FE_ADDR32 0x80000 #define FE_ADDR32 0x80000
/** Used together with a RIP-relative (conditional) jump, this will force the /** 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 * 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, * 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. **/ * FE_JMPL must be specified there, too, so that the encoding lengths match. **/
#define FE_JMPL 0x100000 #define FE_JMPL 0x100000
/** Do not use. **/
#define FE_MNEM_MASK 0xffff #define FE_MNEM_MASK 0xffff
enum { enum {
@@ -41,8 +51,22 @@ enum {
FE_MNEM_MAX 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) #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) #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); int fe_enc64_impl(uint8_t** buf, uint64_t mnem, FeOp op0, FeOp op1, FeOp op2, FeOp op3);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -42,6 +42,7 @@ enum {
FD_FLAG_64 = 1 << 7, FD_FLAG_64 = 1 << 7,
}; };
/** Operand types. **/
typedef enum { typedef enum {
FD_OT_NONE = 0, FD_OT_NONE = 0,
FD_OT_REG = 1, FD_OT_REG = 1,
@@ -186,8 +187,7 @@ const char* fdi_name(FdInstrType ty);
#define FD_HAS_REP(instr) ((instr)->flags & FD_FLAG_REP) #define FD_HAS_REP(instr) ((instr)->flags & FD_FLAG_REP)
/** Indicates whether the instruction was encoded with a REPNZ prefix. **/ /** Indicates whether the instruction was encoded with a REPNZ prefix. **/
#define FD_HAS_REPNZ(instr) ((instr)->flags & FD_FLAG_REPNZ) #define FD_HAS_REPNZ(instr) ((instr)->flags & FD_FLAG_REPNZ)
/** Indicates whether the instruction was encoded with a LOCK prefix. Note that /** Indicates whether the instruction was encoded with a LOCK prefix. **/
* it is not checked whether the LOCK prefix is valid for the instruction. **/
#define FD_HAS_LOCK(instr) ((instr)->flags & FD_FLAG_LOCK) #define FD_HAS_LOCK(instr) ((instr)->flags & FD_FLAG_LOCK)
/** Do not use. **/ /** Do not use. **/
#define FD_IS64(instr) ((instr)->flags & FD_FLAG_64) #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) #define FD_OP_SIZE(instr,idx) ((instr)->operands[idx].size)
/** Gets the accessed register index of a register operand. Note that /only/ the /** 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 * 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. * FD_OP_REG_TYPE, e.g. for distinguishing high-byte registers.
* Only valid if FD_OP_TYPE == FD_OT_REG **/ * Only valid if FD_OP_TYPE == FD_OT_REG **/
#define FD_OP_REG(instr,idx) ((FdReg) (instr)->operands[idx].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 **/ * Only valid if FD_OP_TYPE == FD_OT_MEM **/
#define FD_OP_DISP(instr,idx) ((int64_t) (instr)->disp) #define FD_OP_DISP(instr,idx) ((int64_t) (instr)->disp)
/** Gets the (sign-extended) encoded constant for an immediate operand. /** 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) #define FD_OP_IMM(instr,idx) ((instr)->imm)
#ifdef __cplusplus #ifdef __cplusplus