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