Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add size and offset to immediate and memory operand structs #489

Merged
merged 9 commits into from
Mar 15, 2024
19 changes: 17 additions & 2 deletions assets/porting-guide-v4-v5.md
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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;
NaC-L marked this conversation as resolved.
Show resolved Hide resolved
/**
* 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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading