| 1066 | } |
| 1067 | |
| 1068 | void Decoder::BranchTargetInMultiblockRange() { |
| 1069 | if (!CTX->Config.Multiblock) { |
| 1070 | return; |
| 1071 | } |
| 1072 | |
| 1073 | // If the RIP setting is conditional AND within our symbol range then it can be considered for multiblock |
| 1074 | uint64_t TargetRIP = 0; |
| 1075 | const auto GPRSize = GetGPROpSize(); |
| 1076 | bool Conditional = true; |
| 1077 | const auto InstEnd = DecodeInst->PC + DecodeInst->InstSize; |
| 1078 | |
| 1079 | if (DecodeInst->TableInfo->Flags & FEXCore::X86Tables::InstFlags::FLAGS_CALL) { |
| 1080 | if (ExecutableRangeWritable && CTX->AreMonoHacksActive()) { |
| 1081 | // Mono generated code often contains noreturn calls with garbage following them, and calls are always backpatched |
| 1082 | // after CIL compilation leading to n recompiles for a multiblock with n calls. Choose to minimize stutters over |
| 1083 | // raw performance and disable tracking past calls for mono generated code. |
| 1084 | return; |
| 1085 | } |
| 1086 | |
| 1087 | AddBranchTarget(InstEnd); |
| 1088 | BlockInfo.EntryPoints.emplace(InstEnd); |
| 1089 | return; |
| 1090 | } |
| 1091 | |
| 1092 | // Calls are handled above |
| 1093 | switch (DecodeInst->OP) { |
| 1094 | case 0x70 ... 0x7F: // Conditional JUMP |
| 1095 | case 0x80 ... 0x8F: { // More conditional |
| 1096 | // Source is a literal |
| 1097 | // auto RIPOffset = LoadSource(Op, Op->Src[0], Op->Flags); |
| 1098 | // auto RIPTargetConst = Constant(Op->PC + Op->InstSize); |
| 1099 | // Target offset is PC + InstSize + Literal |
| 1100 | TargetRIP = InstEnd + DecodeInst->Src[0].Literal(); |
| 1101 | break; |
| 1102 | } |
| 1103 | case 0xE9: |
| 1104 | case 0xEB: // Both are unconditional JMP instructions |
| 1105 | TargetRIP = InstEnd + DecodeInst->Src[0].Literal(); |
| 1106 | Conditional = false; |
| 1107 | break; |
| 1108 | case 0xC2: // RET imm |
| 1109 | case 0xC3: // RET |
| 1110 | default: return; break; |
| 1111 | } |
| 1112 | |
| 1113 | if (GPRSize == IR::OpSize::i32Bit) { |
| 1114 | // If we are running a 32bit guest then wrap around addresses that go above 32bit |
| 1115 | TargetRIP &= 0xFFFFFFFFU; |
| 1116 | } |
| 1117 | |
| 1118 | if (Conditional) { |
| 1119 | // If we are conditional then a target can be the instruction past the conditional instruction |
| 1120 | AddBranchTarget(InstEnd); |
| 1121 | } |
| 1122 | |
| 1123 | // If the target RIP is x86 code within the symbol ranges then we are golden |
| 1124 | // Forbid distant branches to have the cost code better match the guest code layout, avoiding massive (range-wise) code |
| 1125 | // blocks in highly fragmented guest code. Such branches are often not-taken branches to garbage in obfuscated code. |
nothing calls this directly
no test coverage detected