1fd38366eSAmir Ayupov //===- bolt/unittest/Core/BinaryContext.cpp -------------------------------===// 2fd38366eSAmir Ayupov // 3fd38366eSAmir Ayupov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fd38366eSAmir Ayupov // See https://llvm.org/LICENSE.txt for license information. 5fd38366eSAmir Ayupov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fd38366eSAmir Ayupov // 7fd38366eSAmir Ayupov //===----------------------------------------------------------------------===// 8fd38366eSAmir Ayupov 977b75ca5SMaksim Panchenko #include "bolt/Core/BinaryContext.h" 1077b75ca5SMaksim Panchenko #include "llvm/BinaryFormat/ELF.h" 1177b75ca5SMaksim Panchenko #include "llvm/DebugInfo/DWARF/DWARFContext.h" 1277b75ca5SMaksim Panchenko #include "llvm/Support/TargetSelect.h" 1377b75ca5SMaksim Panchenko #include "gtest/gtest.h" 1477b75ca5SMaksim Panchenko 1577b75ca5SMaksim Panchenko using namespace llvm; 1677b75ca5SMaksim Panchenko using namespace llvm::object; 1777b75ca5SMaksim Panchenko using namespace llvm::ELF; 1877b75ca5SMaksim Panchenko using namespace bolt; 1977b75ca5SMaksim Panchenko 2077b75ca5SMaksim Panchenko namespace { 2177b75ca5SMaksim Panchenko struct BinaryContextTester : public testing::TestWithParam<Triple::ArchType> { 2277b75ca5SMaksim Panchenko void SetUp() override { 2377b75ca5SMaksim Panchenko initalizeLLVM(); 2477b75ca5SMaksim Panchenko prepareElf(); 2577b75ca5SMaksim Panchenko initializeBOLT(); 2677b75ca5SMaksim Panchenko } 2777b75ca5SMaksim Panchenko 2877b75ca5SMaksim Panchenko protected: 2977b75ca5SMaksim Panchenko void initalizeLLVM() { 3077b75ca5SMaksim Panchenko llvm::InitializeAllTargetInfos(); 3177b75ca5SMaksim Panchenko llvm::InitializeAllTargetMCs(); 3277b75ca5SMaksim Panchenko llvm::InitializeAllAsmParsers(); 3377b75ca5SMaksim Panchenko llvm::InitializeAllDisassemblers(); 3477b75ca5SMaksim Panchenko llvm::InitializeAllTargets(); 3577b75ca5SMaksim Panchenko llvm::InitializeAllAsmPrinters(); 3677b75ca5SMaksim Panchenko } 3777b75ca5SMaksim Panchenko 3877b75ca5SMaksim Panchenko void prepareElf() { 3977b75ca5SMaksim Panchenko memcpy(ElfBuf, "\177ELF", 4); 4077b75ca5SMaksim Panchenko ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf); 4177b75ca5SMaksim Panchenko EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64; 4277b75ca5SMaksim Panchenko EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB; 4377b75ca5SMaksim Panchenko EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64; 4477b75ca5SMaksim Panchenko MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF"); 4577b75ca5SMaksim Panchenko ObjFile = cantFail(ObjectFile::createObjectFile(Source)); 4677b75ca5SMaksim Panchenko } 4777b75ca5SMaksim Panchenko 4877b75ca5SMaksim Panchenko void initializeBOLT() { 4962e894e0SSayhaan Siddiqui Relocation::Arch = ObjFile->makeTriple().getArch(); 5077b75ca5SMaksim Panchenko BC = cantFail(BinaryContext::createBinaryContext( 51*2ccf7ed2SJared Wyles ObjFile->makeTriple(), std::make_shared<orc::SymbolStringPool>(), 52*2ccf7ed2SJared Wyles ObjFile->getFileName(), nullptr, true, 53c0febca3SAmir Ayupov DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); 5477b75ca5SMaksim Panchenko ASSERT_FALSE(!BC); 5577b75ca5SMaksim Panchenko } 5677b75ca5SMaksim Panchenko 5777b75ca5SMaksim Panchenko char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {}; 5877b75ca5SMaksim Panchenko std::unique_ptr<ObjectFile> ObjFile; 5977b75ca5SMaksim Panchenko std::unique_ptr<BinaryContext> BC; 6077b75ca5SMaksim Panchenko }; 6177b75ca5SMaksim Panchenko } // namespace 6277b75ca5SMaksim Panchenko 6377b75ca5SMaksim Panchenko #ifdef X86_AVAILABLE 6477b75ca5SMaksim Panchenko 6577b75ca5SMaksim Panchenko INSTANTIATE_TEST_SUITE_P(X86, BinaryContextTester, 6677b75ca5SMaksim Panchenko ::testing::Values(Triple::x86_64)); 6777b75ca5SMaksim Panchenko 6877b75ca5SMaksim Panchenko #endif 6977b75ca5SMaksim Panchenko 7077b75ca5SMaksim Panchenko #ifdef AARCH64_AVAILABLE 7177b75ca5SMaksim Panchenko 7277b75ca5SMaksim Panchenko INSTANTIATE_TEST_SUITE_P(AArch64, BinaryContextTester, 7377b75ca5SMaksim Panchenko ::testing::Values(Triple::aarch64)); 7477b75ca5SMaksim Panchenko 75485075c0SVladislav Khmelevsky TEST_P(BinaryContextTester, FlushPendingRelocCALL26) { 76485075c0SVladislav Khmelevsky if (GetParam() != Triple::aarch64) 77485075c0SVladislav Khmelevsky GTEST_SKIP(); 78485075c0SVladislav Khmelevsky 79485075c0SVladislav Khmelevsky // This test checks that encodeValueAArch64 used by flushPendingRelocations 80485075c0SVladislav Khmelevsky // returns correctly encoded values for CALL26 relocation for both backward 81485075c0SVladislav Khmelevsky // and forward branches. 82485075c0SVladislav Khmelevsky // 83485075c0SVladislav Khmelevsky // The offsets layout is: 84485075c0SVladislav Khmelevsky // 4: func1 85485075c0SVladislav Khmelevsky // 8: bl func1 86485075c0SVladislav Khmelevsky // 12: bl func2 87485075c0SVladislav Khmelevsky // 16: func2 88485075c0SVladislav Khmelevsky 895daf2001SMaksim Panchenko constexpr size_t DataSize = 20; 905daf2001SMaksim Panchenko uint8_t *Data = new uint8_t[DataSize]; 91485075c0SVladislav Khmelevsky BinarySection &BS = BC->registerOrUpdateSection( 925daf2001SMaksim Panchenko ".text", ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, Data, 935daf2001SMaksim Panchenko DataSize, 4); 94485075c0SVladislav Khmelevsky MCSymbol *RelSymbol1 = BC->getOrCreateGlobalSymbol(4, "Func1"); 95485075c0SVladislav Khmelevsky ASSERT_TRUE(RelSymbol1); 96485075c0SVladislav Khmelevsky BS.addRelocation(8, RelSymbol1, ELF::R_AARCH64_CALL26, 0, 0, true); 97485075c0SVladislav Khmelevsky MCSymbol *RelSymbol2 = BC->getOrCreateGlobalSymbol(16, "Func2"); 98485075c0SVladislav Khmelevsky ASSERT_TRUE(RelSymbol2); 99485075c0SVladislav Khmelevsky BS.addRelocation(12, RelSymbol2, ELF::R_AARCH64_CALL26, 0, 0, true); 100485075c0SVladislav Khmelevsky 101485075c0SVladislav Khmelevsky std::error_code EC; 1025daf2001SMaksim Panchenko SmallVector<char> Vect(DataSize); 103485075c0SVladislav Khmelevsky raw_svector_ostream OS(Vect); 104485075c0SVladislav Khmelevsky 105485075c0SVladislav Khmelevsky BS.flushPendingRelocations(OS, [&](const MCSymbol *S) { 106485075c0SVladislav Khmelevsky return S == RelSymbol1 ? 4 : S == RelSymbol2 ? 16 : 0; 107485075c0SVladislav Khmelevsky }); 108485075c0SVladislav Khmelevsky 109485075c0SVladislav Khmelevsky const uint8_t Func1Call[4] = {255, 255, 255, 151}; 110485075c0SVladislav Khmelevsky const uint8_t Func2Call[4] = {1, 0, 0, 148}; 111485075c0SVladislav Khmelevsky 112485075c0SVladislav Khmelevsky EXPECT_FALSE(memcmp(Func1Call, &Vect[8], 4)) << "Wrong backward call value\n"; 113485075c0SVladislav Khmelevsky EXPECT_FALSE(memcmp(Func2Call, &Vect[12], 4)) << "Wrong forward call value\n"; 114485075c0SVladislav Khmelevsky } 115485075c0SVladislav Khmelevsky 11671c2a132Ssinan TEST_P(BinaryContextTester, FlushPendingRelocJUMP26) { 11771c2a132Ssinan if (GetParam() != Triple::aarch64) 11871c2a132Ssinan GTEST_SKIP(); 11971c2a132Ssinan 12071c2a132Ssinan // This test checks that encodeValueAArch64 used by flushPendingRelocations 12171c2a132Ssinan // returns correctly encoded values for R_AARCH64_JUMP26 relocation for both 12271c2a132Ssinan // backward and forward branches. 12371c2a132Ssinan // 12471c2a132Ssinan // The offsets layout is: 12571c2a132Ssinan // 4: func1 12671c2a132Ssinan // 8: b func1 12771c2a132Ssinan // 12: b func2 12871c2a132Ssinan // 16: func2 12971c2a132Ssinan 13071c2a132Ssinan const uint64_t Size = 20; 13171c2a132Ssinan char *Data = new char[Size]; 13271c2a132Ssinan BinarySection &BS = BC->registerOrUpdateSection( 13371c2a132Ssinan ".text", ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, 13471c2a132Ssinan (uint8_t *)Data, Size, 4); 13571c2a132Ssinan MCSymbol *RelSymbol1 = BC->getOrCreateGlobalSymbol(4, "Func1"); 13671c2a132Ssinan ASSERT_TRUE(RelSymbol1); 13771c2a132Ssinan BS.addRelocation(8, RelSymbol1, ELF::R_AARCH64_JUMP26, 0, 0, true); 13871c2a132Ssinan MCSymbol *RelSymbol2 = BC->getOrCreateGlobalSymbol(16, "Func2"); 13971c2a132Ssinan ASSERT_TRUE(RelSymbol2); 14071c2a132Ssinan BS.addRelocation(12, RelSymbol2, ELF::R_AARCH64_JUMP26, 0, 0, true); 14171c2a132Ssinan 14271c2a132Ssinan std::error_code EC; 14371c2a132Ssinan SmallVector<char> Vect(Size); 14471c2a132Ssinan raw_svector_ostream OS(Vect); 14571c2a132Ssinan 14671c2a132Ssinan BS.flushPendingRelocations(OS, [&](const MCSymbol *S) { 14771c2a132Ssinan return S == RelSymbol1 ? 4 : S == RelSymbol2 ? 16 : 0; 14871c2a132Ssinan }); 14971c2a132Ssinan 15071c2a132Ssinan const uint8_t Func1Call[4] = {255, 255, 255, 23}; 15171c2a132Ssinan const uint8_t Func2Call[4] = {1, 0, 0, 20}; 15271c2a132Ssinan 15371c2a132Ssinan EXPECT_FALSE(memcmp(Func1Call, &Vect[8], 4)) 15471c2a132Ssinan << "Wrong backward branch value\n"; 15571c2a132Ssinan EXPECT_FALSE(memcmp(Func2Call, &Vect[12], 4)) 15671c2a132Ssinan << "Wrong forward branch value\n"; 15771c2a132Ssinan } 15871c2a132Ssinan 15977b75ca5SMaksim Panchenko #endif 16077b75ca5SMaksim Panchenko 16177b75ca5SMaksim Panchenko TEST_P(BinaryContextTester, BaseAddress) { 16277b75ca5SMaksim Panchenko // Check that base address calculation is correct for a binary with the 16377b75ca5SMaksim Panchenko // following segment layout: 1646d216fb7SKristof Beyls BC->SegmentMapInfo[0] = 1656d216fb7SKristof Beyls SegmentInfo{0, 0x10e8c2b4, 0, 0x10e8c2b4, 0x1000, true}; 16677b75ca5SMaksim Panchenko BC->SegmentMapInfo[0x10e8d2b4] = 1676d216fb7SKristof Beyls SegmentInfo{0x10e8d2b4, 0x3952faec, 0x10e8c2b4, 0x3952faec, 0x1000, true}; 16877b75ca5SMaksim Panchenko BC->SegmentMapInfo[0x4a3bddc0] = 1696d216fb7SKristof Beyls SegmentInfo{0x4a3bddc0, 0x148e828, 0x4a3bbdc0, 0x148e828, 0x1000, true}; 17077b75ca5SMaksim Panchenko BC->SegmentMapInfo[0x4b84d5e8] = 1716d216fb7SKristof Beyls SegmentInfo{0x4b84d5e8, 0x294f830, 0x4b84a5e8, 0x3d3820, 0x1000, true}; 17277b75ca5SMaksim Panchenko 1739cbd2959SAmir Ayupov std::optional<uint64_t> BaseAddress = 17477b75ca5SMaksim Panchenko BC->getBaseAddressForMapping(0x7f13f5556000, 0x10e8c000); 1757430894aSFangrui Song ASSERT_TRUE(BaseAddress.has_value()); 17677b75ca5SMaksim Panchenko ASSERT_EQ(*BaseAddress, 0x7f13e46c9000ULL); 17777b75ca5SMaksim Panchenko 17877b75ca5SMaksim Panchenko BaseAddress = BC->getBaseAddressForMapping(0x7f13f5556000, 0x137a000); 1797430894aSFangrui Song ASSERT_FALSE(BaseAddress.has_value()); 18077b75ca5SMaksim Panchenko } 181ae51ec84SJohnLee1243 182ae51ec84SJohnLee1243 TEST_P(BinaryContextTester, BaseAddress2) { 183ae51ec84SJohnLee1243 // Check that base address calculation is correct for a binary if the 184ae51ec84SJohnLee1243 // alignment in ELF file are different from pagesize. 185ae51ec84SJohnLee1243 // The segment layout is as follows: 1866d216fb7SKristof Beyls BC->SegmentMapInfo[0] = SegmentInfo{0, 0x2177c, 0, 0x2177c, 0x10000, true}; 187ae51ec84SJohnLee1243 BC->SegmentMapInfo[0x31860] = 1886d216fb7SKristof Beyls SegmentInfo{0x31860, 0x370, 0x21860, 0x370, 0x10000, true}; 189ae51ec84SJohnLee1243 BC->SegmentMapInfo[0x41c20] = 1906d216fb7SKristof Beyls SegmentInfo{0x41c20, 0x1f8, 0x21c20, 0x1f8, 0x10000, true}; 191ae51ec84SJohnLee1243 BC->SegmentMapInfo[0x54e18] = 1926d216fb7SKristof Beyls SegmentInfo{0x54e18, 0x51, 0x24e18, 0x51, 0x10000, true}; 193ae51ec84SJohnLee1243 194ae51ec84SJohnLee1243 std::optional<uint64_t> BaseAddress = 195ae51ec84SJohnLee1243 BC->getBaseAddressForMapping(0xaaaaea444000, 0x21000); 196ae51ec84SJohnLee1243 ASSERT_TRUE(BaseAddress.has_value()); 197ae51ec84SJohnLee1243 ASSERT_EQ(*BaseAddress, 0xaaaaea413000ULL); 198ae51ec84SJohnLee1243 199ae51ec84SJohnLee1243 BaseAddress = BC->getBaseAddressForMapping(0xaaaaea444000, 0x11000); 200ae51ec84SJohnLee1243 ASSERT_FALSE(BaseAddress.has_value()); 201ae51ec84SJohnLee1243 } 2026d216fb7SKristof Beyls 2036d216fb7SKristof Beyls TEST_P(BinaryContextTester, BaseAddressSegmentsSmallerThanAlignment) { 2046d216fb7SKristof Beyls // Check that the correct segment is used to compute the base address 2056d216fb7SKristof Beyls // when multiple segments are close together in the ELF file (closer 2066d216fb7SKristof Beyls // than the required alignment in the process space). 2076d216fb7SKristof Beyls // See https://github.com/llvm/llvm-project/issues/109384 2086d216fb7SKristof Beyls BC->SegmentMapInfo[0] = SegmentInfo{0, 0x1d1c, 0, 0x1d1c, 0x10000, false}; 2096d216fb7SKristof Beyls BC->SegmentMapInfo[0x11d40] = 2106d216fb7SKristof Beyls SegmentInfo{0x11d40, 0x11e0, 0x1d40, 0x11e0, 0x10000, true}; 2116d216fb7SKristof Beyls BC->SegmentMapInfo[0x22f20] = 2126d216fb7SKristof Beyls SegmentInfo{0x22f20, 0x10e0, 0x2f20, 0x1f0, 0x10000, false}; 2136d216fb7SKristof Beyls BC->SegmentMapInfo[0x33110] = 2146d216fb7SKristof Beyls SegmentInfo{0x33110, 0x89, 0x3110, 0x88, 0x10000, false}; 2156d216fb7SKristof Beyls 2166d216fb7SKristof Beyls std::optional<uint64_t> BaseAddress = 2176d216fb7SKristof Beyls BC->getBaseAddressForMapping(0xaaaaaaab1000, 0x1000); 2186d216fb7SKristof Beyls ASSERT_TRUE(BaseAddress.has_value()); 2196d216fb7SKristof Beyls ASSERT_EQ(*BaseAddress, 0xaaaaaaaa0000ULL); 2206d216fb7SKristof Beyls } 221