Skip to content

Instantly share code, notes, and snippets.

@kobalicek
Last active May 18, 2022 09:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kobalicek/6a11464e2c6777f1c87d44f779e82b7d to your computer and use it in GitHub Desktop.
Save kobalicek/6a11464e2c6777f1c87d44f779e82b7d to your computer and use it in GitHub Desktop.
#include <asmjit/x86.h>
#include <assert.h>
#include <stdio.h>
using namespace asmjit;
class InstSignatureIterator {
public:
typedef asmjit::x86::InstDB::InstSignature InstSignature;
typedef asmjit::x86::InstDB::OpSignature OpSignature;
const InstSignature* _instSignature;
const OpSignature* _opSigArray[asmjit::Globals::kMaxOpCount];
x86::InstDB::OpFlags _opMaskArray[asmjit::Globals::kMaxOpCount];
uint32_t _opCount;
x86::InstDB::OpFlags _filter;
bool _isValid;
static constexpr uint32_t kMaxOpCount = Globals::kMaxOpCount;
static constexpr x86::InstDB::OpFlags kDefaultFilter =
x86::InstDB::OpFlags::kRegMask |
x86::InstDB::OpFlags::kMemMask |
x86::InstDB::OpFlags::kVmMask |
x86::InstDB::OpFlags::kImmMask |
x86::InstDB::OpFlags::kRelMask ;
inline InstSignatureIterator() { reset(); }
inline InstSignatureIterator(const InstSignature* instSignature, x86::InstDB::OpFlags filter = kDefaultFilter) { init(instSignature, filter); }
inline InstSignatureIterator(const InstSignatureIterator& other) { init(other); }
inline void reset() { ::memset(this, 0, sizeof(*this)); }
inline void init(const InstSignatureIterator& other) { ::memcpy(this, &other, sizeof(*this)); }
void init(const InstSignature* instSignature, x86::InstDB::OpFlags filter = kDefaultFilter) {
const OpSignature* opSigArray = asmjit::x86::InstDB::_opSignatureTable;
uint32_t opCount = instSignature->opCount();
_instSignature = instSignature;
_opCount = opCount;
_filter = filter;
uint32_t i;
x86::InstDB::OpFlags flags = x86::InstDB::OpFlags::kNone;
for (i = 0; i < opCount; i++) {
const OpSignature& opSig = instSignature->opSignature(i);
flags = opSig.flags() & _filter;
if (flags == x86::InstDB::OpFlags::kNone)
break;
_opSigArray[i] = &opSig;
_opMaskArray[i] = x86::InstDB::OpFlags(asmjit::Support::blsi(uint64_t(flags)));
}
while (i < kMaxOpCount) {
_opSigArray[i] = &opSigArray[0];
_opMaskArray[i] = x86::InstDB::OpFlags::kNone;
i++;
}
_isValid = opCount == 0 || flags != x86::InstDB::OpFlags::kNone;
}
inline bool isValid() const { return _isValid; }
inline uint32_t opCount() const { return _opCount; }
inline const x86::InstDB::OpFlags* opMaskArray() const { return _opMaskArray; }
inline const OpSignature* const* opSigArray() const { return _opSigArray; }
inline x86::InstDB::OpFlags opMask(uint32_t i) const { return _opMaskArray[i]; }
inline const OpSignature* opSig(uint32_t i) const { return _opSigArray[i]; }
bool next() {
uint32_t i = _opCount - 1u;
for (;;) {
if (i == 0xFFFFFFFFu) {
_isValid = false;
return false;
}
// Iterate over OpFlags.
x86::InstDB::OpFlags prevBit = _opMaskArray[i];
x86::InstDB::OpFlags allFlags = _opSigArray[i]->flags() & _filter;
x86::InstDB::OpFlags bitsToClear = (x86::InstDB::OpFlags)(uint64_t(prevBit) | (uint64_t(prevBit) - 1u));
x86::InstDB::OpFlags remainingBits = allFlags & ~bitsToClear;
if (remainingBits != x86::InstDB::OpFlags::kNone) {
_opMaskArray[i] = (x86::InstDB::OpFlags)asmjit::Support::blsi(uint64_t(remainingBits));
return true;
}
else {
_opMaskArray[i--] = (x86::InstDB::OpFlags)asmjit::Support::blsi(uint64_t(allFlags));
}
}
}
};
static void listISA(Arch arch) {
printf("=== Listing ISA %s ===", arch == Arch::kX86 ? "X86" : "X64");
x86::InstDB::Mode mode = x86::InstDB::modeFromArch(arch);
x86::InstDB::OpFlags opFilter =
x86::InstDB::OpFlags::kRegMask |
x86::InstDB::OpFlags::kMemMask |
x86::InstDB::OpFlags::kVmMask |
x86::InstDB::OpFlags::kImmMask |
x86::InstDB::OpFlags::kRelMask ;
if (arch == Arch::kX86)
opFilter &= ~x86::InstDB::OpFlags::kRegGpq;
for (InstId instId = 1; instId < x86::Inst::_kIdCount; instId++) {
const x86::InstDB::InstInfo& instInfo = x86::InstDB::infoById(instId);
const x86::InstDB::CommonInfo& commonInfo = instInfo.commonInfo();
const x86::InstDB::InstSignature* instSignature = commonInfo.signatureData();
const x86::InstDB::InstSignature* iEnd = commonInfo.signatureEnd();
// Iterate over all signatures and build the instruction we want to test.
for (; instSignature != iEnd; instSignature++) {
if (!instSignature->supportsMode(mode))
continue;
InstSignatureIterator it(instSignature, opFilter);
while (it.isValid()) {
String s;
InstAPI::instIdToString(arch, instId, s);
s.append(' ');
for (uint32_t opIndex = 0; opIndex < it.opCount(); opIndex++) {
const x86::InstDB::OpSignature* opSig = it.opSig(opIndex);
if (opIndex != 0)
s.append(", ");
// NOTE: The iterator iterates over all combinations, always keeping only one bit in the mask.
x86::InstDB::OpFlags flag = it.opMask(opIndex);
switch (flag) {
case x86::InstDB::OpFlags::kRegBnd: s.append("bnd"); break;
case x86::InstDB::OpFlags::kRegCReg: s.append("c"); break;
case x86::InstDB::OpFlags::kRegDReg: s.append("d"); break;
case x86::InstDB::OpFlags::kRegGpbLo: s.append("gpbLo"); break;
case x86::InstDB::OpFlags::kRegGpbHi: s.append("gpbHi"); break;
case x86::InstDB::OpFlags::kRegGpw: s.append("gpw"); break;
case x86::InstDB::OpFlags::kRegGpd: s.append("gpd"); break;
case x86::InstDB::OpFlags::kRegGpq: s.append("gpq"); break;
case x86::InstDB::OpFlags::kRegKReg: s.append("k"); break;
case x86::InstDB::OpFlags::kRegMm: s.append("mm"); break;
case x86::InstDB::OpFlags::kRegXmm: s.append("xmm"); break;
case x86::InstDB::OpFlags::kRegYmm: s.append("ymm"); break;
case x86::InstDB::OpFlags::kRegZmm: s.append("zmm"); break;
case x86::InstDB::OpFlags::kRegSReg: s.append("s"); break;
case x86::InstDB::OpFlags::kRegSt: s.append("st"); break;
case x86::InstDB::OpFlags::kMem8: s.append("m8"); break;
case x86::InstDB::OpFlags::kMem16: s.append("m16"); break;
case x86::InstDB::OpFlags::kMem32: s.append("m32"); break;
case x86::InstDB::OpFlags::kMem48: s.append("m48"); break;
case x86::InstDB::OpFlags::kMem64: s.append("m64"); break;
case x86::InstDB::OpFlags::kMem80: s.append("m80"); break;
case x86::InstDB::OpFlags::kMem128: s.append("m128"); break;
case x86::InstDB::OpFlags::kMem256: s.append("m256"); break;
case x86::InstDB::OpFlags::kMem512: s.append("m512"); break;
case x86::InstDB::OpFlags::kMem1024: s.append("m1024"); break;
case x86::InstDB::OpFlags::kMemUnspecified: s.append("m"); break;
case x86::InstDB::OpFlags::kVm32x: s.append("vm32x"); break;
case x86::InstDB::OpFlags::kVm32y: s.append("vm32y"); break;
case x86::InstDB::OpFlags::kVm32z: s.append("vm32z"); break;
case x86::InstDB::OpFlags::kVm64x: s.append("vm64x"); break;
case x86::InstDB::OpFlags::kVm64y: s.append("vm64y"); break;
case x86::InstDB::OpFlags::kVm64z: s.append("vm64z"); break;
case x86::InstDB::OpFlags::kImmI4: s.append("i4"); break;
case x86::InstDB::OpFlags::kImmI8: s.append("i8"); break;
case x86::InstDB::OpFlags::kImmI16: s.append("i16"); break;
case x86::InstDB::OpFlags::kImmI32: s.append("i32"); break;
case x86::InstDB::OpFlags::kImmI64: s.append("i64"); break;
case x86::InstDB::OpFlags::kImmU4: s.append("u4"); break;
case x86::InstDB::OpFlags::kImmU8: s.append("u8"); break;
case x86::InstDB::OpFlags::kImmU16: s.append("u16"); break;
case x86::InstDB::OpFlags::kImmU32: s.append("u32"); break;
case x86::InstDB::OpFlags::kImmU64: s.append("u64"); break;
case x86::InstDB::OpFlags::kRel8: s.append("rel8"); break;
case x86::InstDB::OpFlags::kRel32: s.append("rel32"); break;
default: s.append("<Unknown>"); break;
}
}
printf("%s\n", s.data());
it.next();
}
}
}
}
int main(int argc, char* argv[]) {
listISA(Arch::kX64);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment