1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
#ifdef AARCH64_AVAILABLE
#include "AArch64Subtarget.h"
#endif // AARCH64_AVAILABLE
#ifdef X86_AVAILABLE
#include "X86Subtarget.h"
#endif // X86_AVAILABLE
#include "bolt/Core/BinaryBasicBlock.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Rewrite/RewriteInstance.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/TargetSelect.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
using namespace bolt;
namespace {
struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
void SetUp() override {
initalizeLLVM();
prepareElf();
initializeBolt();
}
protected:
void initalizeLLVM() {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllDisassemblers();
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
}
void prepareElf() {
memcpy(ElfBuf, "\177ELF", 4);
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
}
void initializeBolt() {
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile.get(), true, DWARFContext::create(*ObjFile.get())));
ASSERT_FALSE(!BC);
BC->initializeTarget(std::unique_ptr<MCPlusBuilder>(
createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(),
BC->MRI.get(), BC->STI.get())));
}
void testRegAliases(Triple::ArchType Arch, uint64_t Register,
uint64_t *Aliases, size_t Count,
bool OnlySmaller = false) {
if (GetParam() != Arch)
GTEST_SKIP();
const BitVector &BV = BC->MIB->getAliases(Register, OnlySmaller);
ASSERT_EQ(BV.count(), Count);
for (size_t I = 0; I < Count; ++I)
ASSERT_TRUE(BV[Aliases[I]]);
}
char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
std::unique_ptr<ObjectFile> ObjFile;
std::unique_ptr<BinaryContext> BC;
};
} // namespace
#ifdef AARCH64_AVAILABLE
INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester,
::testing::Values(Triple::aarch64));
TEST_P(MCPlusBuilderTester, AliasX0) {
uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0, AArch64::W0_W1,
AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7};
size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count);
}
TEST_P(MCPlusBuilderTester, AliasSmallerX0) {
uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0};
size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0);
testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true);
}
#endif // AARCH64_AVAILABLE
#ifdef X86_AVAILABLE
INSTANTIATE_TEST_SUITE_P(X86, MCPlusBuilderTester,
::testing::Values(Triple::x86_64));
TEST_P(MCPlusBuilderTester, AliasAX) {
uint64_t AliasesAX[] = {X86::RAX, X86::EAX, X86::AX, X86::AL, X86::AH};
size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount);
}
TEST_P(MCPlusBuilderTester, AliasSmallerAX) {
uint64_t AliasesAX[] = {X86::AX, X86::AL, X86::AH};
size_t AliasesAXCount = sizeof(AliasesAX) / sizeof(*AliasesAX);
testRegAliases(Triple::x86_64, X86::AX, AliasesAX, AliasesAXCount, true);
}
TEST_P(MCPlusBuilderTester, ReplaceRegWithImm) {
if (GetParam() != Triple::x86_64)
GTEST_SKIP();
BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
MCInst Inst; // cmpl %eax, %ebx
Inst.setOpcode(X86::CMP32rr);
Inst.addOperand(MCOperand::createReg(X86::EAX));
Inst.addOperand(MCOperand::createReg(X86::EBX));
auto II = BB->addInstruction(Inst);
bool Replaced = BC->MIB->replaceRegWithImm(*II, X86::EBX, 1);
ASSERT_TRUE(Replaced);
ASSERT_EQ(II->getOpcode(), X86::CMP32ri8);
ASSERT_EQ(II->getOperand(0).getReg(), X86::EAX);
ASSERT_EQ(II->getOperand(1).getImm(), 1);
}
#endif // X86_AVAILABLE
TEST_P(MCPlusBuilderTester, Annotation) {
MCInst Inst;
bool Success = BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
BC->Ctx.get());
ASSERT_TRUE(Success);
MCSymbol *LPSymbol = BC->Ctx->createNamedTempSymbol("LP");
uint64_t Value = INT32_MIN;
// Test encodeAnnotationImm using this indirect way
BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value));
// Round-trip encoding-decoding check for negative values
std::optional<MCPlus::MCLandingPad> EHInfo = BC->MIB->getEHInfo(Inst);
ASSERT_TRUE(EHInfo.has_value());
MCPlus::MCLandingPad LP = EHInfo.value();
uint64_t DecodedValue = LP.second;
ASSERT_EQ(Value, DecodedValue);
// Large int64 should trigger an out of range assertion
Value = 0x1FF'FFFF'FFFF'FFFFULL;
Inst.clear();
Success = BC->MIB->createTailCall(Inst, BC->Ctx->createNamedTempSymbol(),
BC->Ctx.get());
ASSERT_TRUE(Success);
ASSERT_DEATH(BC->MIB->addEHInfo(Inst, MCPlus::MCLandingPad(LPSymbol, Value)),
"annotation value out of range");
}
|