Skip to content

Commit fab419a

Browse files
committed
Add Zydis x86/x86-64 disassembler support
Integrate Zydis as an optional dependency to enable x86/x86-64 guest instruction disassembly during JIT compilation. Build with -DENABLE_ZYDIS=TRUE. Use FEX_X86DISASSEMBLE=1 at runtime to output guest x86 instructions for each compiled block.
1 parent d197300 commit fab419a

File tree

6 files changed

+66
-0
lines changed

6 files changed

+66
-0
lines changed

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@
4949
[submodule "External/range-v3"]
5050
path = External/range-v3
5151
url = https://github.com/ericniebler/range-v3.git
52+
[submodule "External/zydis"]
53+
shallow = true
54+
path = External/zydis
55+
url = https://github.com/zyantific/zydis.git

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ option(ENABLE_LIBCXX "Enables LLVM libc++" FALSE)
2828
option(ENABLE_CCACHE "Enables ccache for compile caching" TRUE)
2929
option(ENABLE_VIXL_SIMULATOR "Enable use of VIXL simulator for emulation (only useful for CI testing)" FALSE)
3030
option(ENABLE_VIXL_DISASSEMBLER "Enables debug disassembler output with VIXL" FALSE)
31+
option(ENABLE_ZYDIS "Enables x86/x86-64 guest disassembler output with Zydis" FALSE)
3132
option(USE_LEGACY_BINFMTMISC "Uses legacy method of setting up binfmt_misc" FALSE)
3233
option(ENABLE_FEXCORE_PROFILER "Enables use of the FEXCore timeline profiling capabilities" FALSE)
3334
set (FEXCORE_PROFILER_BACKEND "gpuvis" CACHE STRING "Set which backend to use for the FEXCore profiler (gpuvis, tracy)")
@@ -315,6 +316,12 @@ if (BUILD_TESTING OR ENABLE_VIXL_DISASSEMBLER OR ENABLE_VIXL_SIMULATOR)
315316
include_directories(SYSTEM External/vixl/src/)
316317
endif()
317318

319+
if (ENABLE_ZYDIS)
320+
set(ZYDIS_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
321+
set(ZYDIS_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
322+
add_subdirectory(External/zydis/)
323+
endif()
324+
318325
if (ENABLE_FEXCORE_PROFILER AND FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
319326
add_subdirectory(External/tracy)
320327
endif()

External/zydis

Submodule zydis added at 9bfadd6

FEXCore/Source/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ if (ENABLE_VIXL_DISASSEMBLER)
9696
list(APPEND DEFINES -DVIXL_DISASSEMBLER=1)
9797
endif()
9898

99+
if (ENABLE_ZYDIS)
100+
list(APPEND DEFINES -DZYDIS_DISASSEMBLER=1)
101+
endif()
102+
99103
if (_M_ARM_64 AND HAS_CLANG_PRESERVE_ALL)
100104
list(APPEND DEFINES "-DFEXCORE_PRESERVE_ALL_ATTR=__attribute__((preserve_all));-DFEXCORE_HAS_PRESERVE_ALL_ATTR=1")
101105
else()
@@ -108,6 +112,10 @@ if (ENABLE_VIXL_DISASSEMBLER OR ENABLE_VIXL_SIMULATOR)
108112
list (APPEND LIBS vixl)
109113
endif()
110114

115+
if (ENABLE_ZYDIS)
116+
list (APPEND LIBS Zydis)
117+
endif()
118+
111119
if (NOT MINGW_BUILD)
112120
list (APPEND LIBS dl)
113121
else()

FEXCore/Source/Interface/Config/Config.json.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,14 @@
334334
"\tstats: Will print stats when disassembling the code"
335335
]
336336
},
337+
"X86Disassemble": {
338+
"Type": "bool",
339+
"Default": "false",
340+
"Desc": [
341+
"Enables x86/x86-64 guest disassembly output for compiled blocks.",
342+
"Requires FEX to be built with -DENABLE_ZYDIS=TRUE"
343+
]
344+
},
337345
"ForceSVEWidth": {
338346
"Type": "uint32",
339347
"Default": "0",

FEXCore/Source/Interface/Core/Core.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ desc: Glues Frontend, OpDispatcher and IR Opts & Compilation, LookupCache, Dispa
99
*/
1010

1111
#include <cstdint>
12+
#ifdef ZYDIS_DISASSEMBLER
13+
#include <Zydis/Zydis.h>
14+
#endif
1215
#include "Interface/Core/ArchHelpers/Arm64Emitter.h"
1316
#include "Interface/Core/LookupCache.h"
1417
#include "Interface/Core/CPUBackend.h"
@@ -536,9 +539,25 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
536539

537540
const auto GPRSize = Thread->OpDispatcher->GetGPROpSize();
538541

542+
#ifdef ZYDIS_DISASSEMBLER
543+
FEX_CONFIG_OPT(X86Disassemble, X86DISASSEMBLE);
544+
const auto ZydisMachineMode = Config.Is64BitMode ? ZYDIS_MACHINE_MODE_LONG_64 : ZYDIS_MACHINE_MODE_LEGACY_32;
545+
if (X86Disassemble()) {
546+
const uint64_t DecodedMin = Thread->FrontendDecoder->DecodedMinAddress;
547+
const uint64_t DecodedMax = Thread->FrontendDecoder->DecodedMaxAddress;
548+
LogMan::Msg::IFmt("Guest x86 Begin (RIP={:#x}, {:#x}-{:#x})", GuestRIP, DecodedMin, DecodedMax);
549+
}
550+
#endif
551+
539552
for (size_t j = 0; j < CodeBlocks->size(); ++j) {
540553
const FEXCore::Frontend::Decoder::DecodedBlocks& Block = CodeBlocks->at(j);
541554

555+
#ifdef ZYDIS_DISASSEMBLER
556+
if (X86Disassemble() && CodeBlocks->size() > 1) {
557+
LogMan::Msg::IFmt(" Block {} Entry={:#x} NumInsts={}", j, Block.Entry, Block.NumInstructions);
558+
}
559+
#endif
560+
542561
bool BlockInForceTSOValidRange = false;
543562
auto InstForceTSOIt = ForceTSOInstructions.end();
544563
if (ForceTSOValidRanges.Contains({Block.Entry, Block.Entry + Block.Size})) {
@@ -570,6 +589,19 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
570589

571590
TableInfo = Block.DecodedInstructions[i].TableInfo;
572591
DecodedInfo = &Block.DecodedInstructions[i];
592+
593+
#ifdef ZYDIS_DISASSEMBLER
594+
if (X86Disassemble()) {
595+
const uint8_t* InstBytes = reinterpret_cast<const uint8_t*>(InstAddress);
596+
ZydisDisassembledInstruction ZydisInst;
597+
if (ZYAN_SUCCESS(ZydisDisassembleIntel(ZydisMachineMode, InstAddress, InstBytes, DecodedInfo->InstSize, &ZydisInst))) {
598+
LogMan::Msg::IFmt("{:#x}: {}", InstAddress, ZydisInst.text);
599+
} else {
600+
LogMan::Msg::IFmt("{:#x}: (decode failed, {} bytes)", InstAddress, DecodedInfo->InstSize);
601+
}
602+
}
603+
#endif
604+
573605
bool IsLocked = DecodedInfo->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK;
574606

575607
// Do a partial register cache flush before every instruction. This
@@ -689,6 +721,12 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
689721
}
690722
}
691723

724+
#ifdef ZYDIS_DISASSEMBLER
725+
if (X86Disassemble()) {
726+
LogMan::Msg::IFmt("Guest x86 End");
727+
}
728+
#endif
729+
692730
Thread->OpDispatcher->Finalize();
693731

694732
Thread->FrontendDecoder->DelayedDisownBuffer();

0 commit comments

Comments
 (0)