Skip to content

Commit

Permalink
Add size and offset to immediate and memory operand structs (#489)
Browse files Browse the repository at this point in the history
  • Loading branch information
NaC-L committed Mar 15, 2024
1 parent ffde0f4 commit 1ad8a15
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 16 deletions.
19 changes: 17 additions & 2 deletions assets/porting-guide-v4-v5.md
@@ -1,9 +1,24 @@
# Porting Guide v4 -> v5

# Encoder
### Encoder

- `ZydisRegisterGetLargestEnclosing` will now return the given register itself for registers that don't have
an enclosing register. Previously it would return `ZYDIS_REGISTER_NONE` in these cases.
- `ZydisEncoderDecodedInstructionToEncoderRequest` now expects exactly `instruction->operand_count_visible` to be
passed, not `operand_count_visible` at maximum. Passing a lower value was previously allowed but didn't really
make much sense at all.
make much sense at all.

### Decoder

- `ZydisDecodedOperandImm` struct was changed
- Added field `offset`
- Contains the offset of the immediate data, relative to the beginning of the instruction, in bytes.
- Added field `size`
- Contains the physical immediate size, in bits.
- `ZydisDecodedOperandMemDisp_` struct was changed
- Added field `offset`
- Contains the offset of the immediate data, relative to the beginning of the instruction, in bytes.
- Added field `size`
- Contains the physical displacement size, in bits.
- Removed field `has_displacement`
- A `size` of 0 indicates that there is no displacement, effectively replacing the need for `has_displacement`.
22 changes: 18 additions & 4 deletions include/Zydis/DecoderTypes.h
Expand Up @@ -149,14 +149,19 @@ typedef struct ZydisDecodedOperandMem_
*/
struct ZydisDecodedOperandMemDisp_
{
/**
* Signals, if the displacement value is used.
*/
ZyanBool has_displacement;
/**
* The displacement value
*/
ZyanI64 value;
/**
* The offset of the displacement data, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
/**
* The physical displacement size, in bits.
*/
ZyanU8 size;
} disp;
} ZydisDecodedOperandMem;

Expand Down Expand Up @@ -191,6 +196,15 @@ typedef struct ZydisDecodedOperandImm_
ZyanU64 u;
ZyanI64 s;
} value;
/**
* The offset of the immediate data, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
/**
* The physical immediate size, in bits.
*/
ZyanU8 size;
} ZydisDecodedOperandImm;

/**
Expand Down
8 changes: 6 additions & 2 deletions src/Decoder.c
Expand Up @@ -1433,8 +1433,9 @@ static ZyanStatus ZydisDecodeOperandMemory(const ZydisDecoderContext* context,
if (displacement_size)
{
ZYAN_ASSERT(instruction->raw.disp.size == displacement_size);
operand->mem.disp.has_displacement = ZYAN_TRUE;
operand->mem.disp.value = instruction->raw.disp.value;
operand->mem.disp.size = displacement_size;
operand->mem.disp.offset = instruction->raw.disp.offset;
}
return ZYAN_STATUS_SUCCESS;
}
Expand Down Expand Up @@ -1829,7 +1830,8 @@ static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDe
ZYAN_ASSERT(instruction->raw.disp.size);
operands[i].type = ZYDIS_OPERAND_TYPE_MEMORY;
operands[i].mem.type = ZYDIS_MEMOP_TYPE_MEM;
operands[i].mem.disp.has_displacement = ZYAN_TRUE;
operands[i].mem.disp.size = instruction->raw.disp.size;
operands[i].mem.disp.offset = instruction->raw.disp.offset;
operands[i].mem.disp.value = instruction->raw.disp.value;
break;
case ZYDIS_SEMANTIC_OPTYPE_MIB:
Expand Down Expand Up @@ -1877,6 +1879,8 @@ static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDe
{
operands[i].imm.value.u = instruction->raw.imm[imm_id].value.u;
}
operands[i].imm.offset = instruction->raw.imm->offset;
operands[i].imm.size = instruction->raw.imm->size;
operands[i].imm.is_signed = instruction->raw.imm[imm_id].is_signed;
operands[i].imm.is_relative = instruction->raw.imm[imm_id].is_relative;
++imm_id;
Expand Down
2 changes: 1 addition & 1 deletion src/Encoder.c
Expand Up @@ -4705,7 +4705,7 @@ ZYDIS_EXPORT ZyanStatus ZydisEncoderDecodedInstructionToEncoderRequest(
enc_op->mem.base = dec_op->mem.base;
enc_op->mem.index = dec_op->mem.index;
enc_op->mem.scale = dec_op->mem.type != ZYDIS_MEMOP_TYPE_MIB ? dec_op->mem.scale : 0;
if (dec_op->mem.disp.has_displacement)
if (dec_op->mem.disp.size)
{
enc_op->mem.displacement = dec_op->mem.disp.value;
}
Expand Down
4 changes: 2 additions & 2 deletions src/FormatterATT.c
Expand Up @@ -208,7 +208,7 @@ ZyanStatus ZydisFormatterATTFormatOperandMEM(const ZydisFormatter* formatter,

const ZyanBool absolute = !formatter->force_relative_riprel &&
(context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
if (absolute && context->operand->mem.disp.has_displacement &&
if (absolute && context->operand->mem.disp.size &&
(context->operand->mem.index == ZYDIS_REGISTER_NONE) &&
((context->operand->mem.base == ZYDIS_REGISTER_NONE) ||
(context->operand->mem.base == ZYDIS_REGISTER_EIP ) ||
Expand All @@ -226,7 +226,7 @@ ZyanStatus ZydisFormatterATTFormatOperandMEM(const ZydisFormatter* formatter,
if (neither_reg_nor_idx)
{
ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
} else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value)
} else if (context->operand->mem.disp.size && context->operand->mem.disp.value)
{
ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context));
}
Expand Down
4 changes: 2 additions & 2 deletions src/FormatterIntel.c
Expand Up @@ -212,7 +212,7 @@ ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter,

const ZyanBool absolute = !formatter->force_relative_riprel &&
(context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
if (absolute && context->operand->mem.disp.has_displacement &&
if (absolute && context->operand->mem.disp.size &&
(context->operand->mem.index == ZYDIS_REGISTER_NONE) &&
((context->operand->mem.base == ZYDIS_REGISTER_NONE) ||
(context->operand->mem.base == ZYDIS_REGISTER_EIP ) ||
Expand Down Expand Up @@ -253,7 +253,7 @@ ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter,
if (neither_reg_nor_idx)
{
ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
} else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value)
} else if (context->operand->mem.disp.size && context->operand->mem.disp.value)
{
ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Utils.c
Expand Up @@ -49,7 +49,7 @@ ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* instruction,
switch (operand->type)
{
case ZYDIS_OPERAND_TYPE_MEMORY:
if (!operand->mem.disp.has_displacement)
if (!operand->mem.disp.size)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
Expand Down
2 changes: 1 addition & 1 deletion tools/ZydisFuzzEncoder.c
Expand Up @@ -132,7 +132,7 @@ void ZydisCompareRequestToInstruction(const ZydisEncoderRequest *request,
ZyanBool acceptable_mismatch = ZYAN_FALSE;
if (op1->mem.displacement != op2->mem.disp.value)
{
if ((op2->mem.disp.has_displacement) &&
if ((op2->mem.disp.size) &&
(op1->mem.index == ZYDIS_REGISTER_NONE) &&
((op1->mem.base == ZYDIS_REGISTER_NONE) ||
(op1->mem.base == ZYDIS_REGISTER_EIP) ||
Expand Down
21 changes: 20 additions & 1 deletion tools/ZydisFuzzShared.c
Expand Up @@ -136,6 +136,20 @@ void ZydisPrintInstruction(const ZydisDecodedInstruction* instruction,

#endif

void ZydisValidateImmediateSize(ZyanU64 value)
{
if ((value != 0) &&
(value != 8) &&
(value != 16) &&
(value != 32) &&
(value != 64))
{
fprintf(stderr, "Value 0x%016" PRIX64 " does not match any of the expected "
"values (0, 8, 16, 32, 64).\n", value);
abort();
}
}

// NOTE: This function doesn't validate flag values, yet.
void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn,
const ZydisDecodedOperand* operands, ZyanU8 operand_count)
Expand All @@ -147,6 +161,7 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn,
" = 0x%016" PRIX64 "\n", (ZyanU64)(value), (ZyanU64)(max)); \
abort(); \
}
# define ZYDIS_CHECK_MAX ZYDIS_CHECK_ENUM

ZYDIS_CHECK_ENUM(insn->length, ZYDIS_MAX_INSTRUCTION_LENGTH);

Expand Down Expand Up @@ -175,11 +190,14 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn,
ZYDIS_CHECK_ENUM(op->mem.segment, ZYDIS_REGISTER_MAX_VALUE);
ZYDIS_CHECK_ENUM(op->mem.base, ZYDIS_REGISTER_MAX_VALUE);
ZYDIS_CHECK_ENUM(op->mem.index, ZYDIS_REGISTER_MAX_VALUE);
ZYDIS_CHECK_ENUM(op->mem.disp.has_displacement, ZYAN_TRUE);
ZydisValidateImmediateSize(op->mem.disp.size);
ZYDIS_CHECK_MAX(op->mem.disp.offset + (op->mem.disp.size / 8), insn->length);
break;
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
ZYDIS_CHECK_ENUM(op->imm.is_signed, ZYAN_TRUE);
ZYDIS_CHECK_ENUM(op->imm.is_relative, ZYAN_TRUE);
ZydisValidateImmediateSize(op->imm.size);
ZYDIS_CHECK_MAX(op->imm.offset + (op->imm.size / 8), insn->length);
break;
default:
break;
Expand Down Expand Up @@ -216,6 +234,7 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn,
}

# undef ZYDIS_CHECK_ENUM
# undef ZYDIS_CHECK_MAX
}

void ZydisValidateInstructionIdentity(const ZydisDecodedInstruction* insn1,
Expand Down

0 comments on commit 1ad8a15

Please sign in to comment.