diff --git a/include/Zydis/Internal/EncoderData.h b/include/Zydis/Internal/EncoderData.h index 808c1fa5..886e4a7d 100644 --- a/include/Zydis/Internal/EncoderData.h +++ b/include/Zydis/Internal/EncoderData.h @@ -221,6 +221,10 @@ typedef struct ZydisEncoderRelInfo_ * True if instruction accepts branch hint prefixes. */ ZyanBool accepts_branch_hints; + /** + * True if instruction accepts bound (`BND`) prefix. + */ + ZyanBool accepts_bound; } ZydisEncoderRelInfo; /** diff --git a/src/Encoder.c b/src/Encoder.c index 27c606e3..db8eef37 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -4373,10 +4373,20 @@ ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstructionAbsolute(ZydisEncoderReques } if ((rel_info->accepts_branch_hints) && (request->prefixes & (ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN | - ZYDIS_ATTRIB_HAS_BRANCH_TAKEN | - ZYDIS_ATTRIB_HAS_BND))) + ZYDIS_ATTRIB_HAS_BRANCH_TAKEN))) { - extra_length = 1; + extra_length += 1; + } + if ((rel_info->accepts_bound) && (request->prefixes & ZYDIS_ATTRIB_HAS_BND)) + { + extra_length += 1; + // `BND` prefix is not accepted for short `JMP` (Intel SDM Vol. 1) + if ((request->mnemonic == ZYDIS_MNEMONIC_JMP) && + (request->branch_type == ZYDIS_BRANCH_TYPE_NONE) && + (request->branch_width == ZYDIS_BRANCH_WIDTH_NONE)) + { + start_offset = 1; + } } if (request->branch_width == ZYDIS_BRANCH_WIDTH_NONE) { diff --git a/src/Generated/GetRelInfo.inc b/src/Generated/GetRelInfo.inc index 20556267..a7748f81 100644 --- a/src/Generated/GetRelInfo.inc +++ b/src/Generated/GetRelInfo.inc @@ -2,15 +2,15 @@ const ZydisEncoderRelInfo *ZydisGetRelInfo(ZydisMnemonic mnemonic) { static const ZydisEncoderRelInfo info_lookup[9] = { - { { { 0, 3, 6 }, { 0, 4, 5 }, { 0, 0, 5 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, - { { { 2, 4, 7 }, { 2, 5, 6 }, { 2, 0, 6 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_TRUE }, - { { { 2, 0, 0 }, { 3, 0, 0 }, { 0, 0, 0 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, - { { { 3, 0, 0 }, { 2, 0, 0 }, { 3, 0, 0 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, - { { { 0, 0, 0 }, { 0, 0, 0 }, { 5, 0, 7 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, - { { { 2, 3, 6 }, { 2, 4, 5 }, { 2, 0, 5 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, - { { { 0, 0, 0 }, { 0, 0, 0 }, { 2, 0, 0 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, - { { { 2, 0, 0 }, { 2, 0, 0 }, { 2, 0, 0 } }, ZYDIS_SIZE_HINT_ASZ, ZYAN_FALSE }, - { { { 0, 4, 7 }, { 0, 5, 6 }, { 0, 5, 6 } }, ZYDIS_SIZE_HINT_OSZ, ZYAN_FALSE }, + { { { 0, 3, 6 }, { 0, 4, 5 }, { 0, 0, 5 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE, ZYAN_TRUE }, + { { { 2, 4, 7 }, { 2, 5, 6 }, { 2, 0, 6 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_TRUE, ZYAN_TRUE }, + { { { 2, 0, 0 }, { 3, 0, 0 }, { 0, 0, 0 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE, ZYAN_FALSE }, + { { { 3, 0, 0 }, { 2, 0, 0 }, { 3, 0, 0 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE, ZYAN_FALSE }, + { { { 0, 0, 0 }, { 0, 0, 0 }, { 5, 0, 7 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE, ZYAN_FALSE }, + { { { 2, 3, 6 }, { 2, 4, 5 }, { 2, 0, 5 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE, ZYAN_TRUE }, + { { { 0, 0, 0 }, { 0, 0, 0 }, { 2, 0, 0 } }, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE, ZYAN_FALSE }, + { { { 2, 0, 0 }, { 2, 0, 0 }, { 2, 0, 0 } }, ZYDIS_SIZE_HINT_ASZ, ZYAN_FALSE, ZYAN_FALSE }, + { { { 0, 4, 7 }, { 0, 5, 6 }, { 0, 5, 6 } }, ZYDIS_SIZE_HINT_OSZ, ZYAN_FALSE, ZYAN_FALSE }, }; switch (mnemonic) diff --git a/tools/ZydisTestEncoderAbsolute.c b/tools/ZydisTestEncoderAbsolute.c index 82889c2b..af7745a7 100644 --- a/tools/ZydisTestEncoderAbsolute.c +++ b/tools/ZydisTestEncoderAbsolute.c @@ -225,12 +225,14 @@ static ZyanBool RunBranchingTests(void) 0, ZYDIS_ATTRIB_HAS_BRANCH_TAKEN, ZYDIS_ATTRIB_HAS_BND, + ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN | ZYDIS_ATTRIB_HAS_BND, }; static const char *str_prefixes[] = { "P00", "PBT", - "PBN", + "PBD", + "PBN+PBD", }; static const ZydisAddressSizeHint address_hints[] = { @@ -285,7 +287,12 @@ static ZyanBool RunBranchingTests(void) const ZydisEncoderRelInfo *rel_info = ZydisGetRelInfo(mnemonic); ZYAN_ASSERT(rel_info); - if (!rel_info->accepts_branch_hints && iter_branches[5].value != 0) + if ((!rel_info->accepts_branch_hints) && (prefix & (ZYDIS_ATTRIB_HAS_BRANCH_TAKEN | + ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN))) + { + continue; + } + if ((!rel_info->accepts_bound) && (prefix & ZYDIS_ATTRIB_HAS_BND)) { continue; }