Skip to content

Commit 8fb29ba

Browse files
committed
[JITLink] Teach x86_64 GOT & PLT table managers to discover existing entries.
x86_64::GOTTableManager and x86_64::PLTTableManager will now look for existing GOT and PLT sections and re-use existing entries if they're present. This will be used for an upcoming MachO patch to enable compact unwind support. This patch is the x86-64 counterpart 42595bd, which added the same functionality to the GOT and PLT managers for aarch64.
1 parent fd4f94d commit 8fb29ba

File tree

6 files changed

+134
-11
lines changed

6 files changed

+134
-11
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,11 @@ class GOTTableManager : public TableManager<GOTTableManager> {
671671
public:
672672
static StringRef getSectionName() { return "$__GOT"; }
673673

674+
GOTTableManager(LinkGraph &G) {
675+
if ((GOTSection = G.findSectionByName(getSectionName())))
676+
registerExistingEntries();
677+
}
678+
674679
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
675680
Edge::Kind KindToSet = Edge::Invalid;
676681
switch (E.getKind()) {
@@ -721,16 +726,21 @@ class GOTTableManager : public TableManager<GOTTableManager> {
721726
return *GOTSection;
722727
}
723728

729+
void registerExistingEntries();
730+
724731
Section *GOTSection = nullptr;
725732
};
726733

727734
/// Procedure Linkage Table Builder.
728735
class PLTTableManager : public TableManager<PLTTableManager> {
729736
public:
730-
PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
731-
732737
static StringRef getSectionName() { return "$__STUBS"; }
733738

739+
PLTTableManager(LinkGraph &G, GOTTableManager &GOT) : GOT(GOT) {
740+
if ((StubsSection = G.findSectionByName(getSectionName())))
741+
registerExistingEntries();
742+
}
743+
734744
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
735745
if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
736746
DEBUG_WITH_TYPE("jitlink", {
@@ -754,14 +764,16 @@ class PLTTableManager : public TableManager<PLTTableManager> {
754764

755765
public:
756766
Section &getStubsSection(LinkGraph &G) {
757-
if (!PLTSection)
758-
PLTSection = &G.createSection(getSectionName(),
759-
orc::MemProt::Read | orc::MemProt::Exec);
760-
return *PLTSection;
767+
if (!StubsSection)
768+
StubsSection = &G.createSection(getSectionName(),
769+
orc::MemProt::Read | orc::MemProt::Exec);
770+
return *StubsSection;
761771
}
762772

773+
void registerExistingEntries();
774+
763775
GOTTableManager &GOT;
764-
Section *PLTSection = nullptr;
776+
Section *StubsSection = nullptr;
765777
};
766778

767779
/// Optimize the GOT and Stub relocations if the edge target address is in range

llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ const uint8_t TLSInfoTableManager_ELF_x86_64::TLSInfoEntryContent[16] = {
8888
Error buildTables_ELF_x86_64(LinkGraph &G) {
8989
LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
9090

91-
x86_64::GOTTableManager GOT;
92-
x86_64::PLTTableManager PLT(GOT);
91+
x86_64::GOTTableManager GOT(G);
92+
x86_64::PLTTableManager PLT(G, GOT);
9393
TLSInfoTableManager_ELF_x86_64 TLSInfo;
9494
visitExistingEdges(G, GOT, PLT, TLSInfo);
9595
return Error::success();

llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,8 @@ class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
459459
};
460460

461461
Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
462-
x86_64::GOTTableManager GOT;
463-
x86_64::PLTTableManager PLT(GOT);
462+
x86_64::GOTTableManager GOT(G);
463+
x86_64::PLTTableManager PLT(G, GOT);
464464
visitExistingEdges(G, GOT, PLT);
465465
return Error::success();
466466
}

llvm/lib/ExecutionEngine/JITLink/x86_64.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,26 @@ const char ReentryTrampolineContent[5] = {
8989
static_cast<char>(0xe8), 0x00, 0x00, 0x00, 0x00
9090
};
9191

92+
void GOTTableManager::registerExistingEntries() {
93+
for (auto *EntrySym : GOTSection->symbols()) {
94+
assert(EntrySym->getBlock().edges_size() == 1 &&
95+
"GOT block edge count != 1");
96+
registerPreExistingEntry(EntrySym->getBlock().edges().begin()->getTarget(),
97+
*EntrySym);
98+
}
99+
}
100+
101+
void PLTTableManager::registerExistingEntries() {
102+
for (auto *EntrySym : StubsSection->symbols()) {
103+
assert(EntrySym->getBlock().edges_size() == 1 &&
104+
"PLT block edge count != 1");
105+
auto &GOTSym = EntrySym->getBlock().edges().begin()->getTarget();
106+
assert(GOTSym.getBlock().edges_size() == 1 && "GOT block edge count != 1");
107+
registerPreExistingEntry(GOTSym.getBlock().edges().begin()->getTarget(),
108+
*EntrySym);
109+
}
110+
}
111+
92112
Error optimizeGOTAndStubAccesses(LinkGraph &G) {
93113
LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
94114

llvm/unittests/ExecutionEngine/JITLink/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_llvm_unittest(JITLinkTests
1717
MachOLinkGraphTests.cpp
1818
MemoryManagerErrorTests.cpp
1919
StubsTests.cpp
20+
X86_64Tests.cpp
2021
)
2122

2223
target_link_libraries(JITLinkTests PRIVATE LLVMTestingSupport)
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===-------- X86_64Tests.cpp - Unit tests for the AArch64 backend --------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <llvm/BinaryFormat/ELF.h>
10+
#include <llvm/ExecutionEngine/JITLink/x86_64.h>
11+
12+
#include "gtest/gtest.h"
13+
14+
using namespace llvm;
15+
using namespace llvm::jitlink;
16+
using namespace llvm::jitlink::x86_64;
17+
18+
TEST(X86_64, EmptyLinkGraph) {
19+
LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
20+
Triple("x86_64-apple-darwin"), SubtargetFeatures(),
21+
getEdgeKindName);
22+
EXPECT_EQ(G.getName(), "foo");
23+
EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin");
24+
EXPECT_EQ(G.getPointerSize(), 8U);
25+
EXPECT_EQ(G.getEndianness(), llvm::endianness::little);
26+
EXPECT_TRUE(G.external_symbols().empty());
27+
EXPECT_TRUE(G.absolute_symbols().empty());
28+
EXPECT_TRUE(G.defined_symbols().empty());
29+
EXPECT_TRUE(G.blocks().empty());
30+
}
31+
32+
TEST(X86_64, GOTAndStubs) {
33+
LinkGraph G("foo", std::make_shared<orc::SymbolStringPool>(),
34+
Triple("x86_64-apple-darwin"), SubtargetFeatures(),
35+
getEdgeKindName);
36+
37+
auto &External = G.addExternalSymbol("external", 0, false);
38+
39+
// First table accesses. We expect the graph to be empty:
40+
EXPECT_EQ(G.findSectionByName(GOTTableManager::getSectionName()), nullptr);
41+
EXPECT_EQ(G.findSectionByName(PLTTableManager::getSectionName()), nullptr);
42+
43+
{
44+
// Create first GOT and PLT table managers and request a PLT stub. This
45+
// should force creation of both a PLT stub and GOT entry.
46+
GOTTableManager GOT(G);
47+
PLTTableManager PLT(G, GOT);
48+
49+
PLT.getEntryForTarget(G, External);
50+
}
51+
52+
auto *GOTSec = G.findSectionByName(GOTTableManager::getSectionName());
53+
EXPECT_NE(GOTSec, nullptr);
54+
if (GOTSec) {
55+
// Expect one entry in the GOT now.
56+
EXPECT_EQ(GOTSec->symbols_size(), 1U);
57+
EXPECT_EQ(GOTSec->blocks_size(), 1U);
58+
}
59+
60+
auto *PLTSec = G.findSectionByName(PLTTableManager::getSectionName());
61+
EXPECT_NE(PLTSec, nullptr);
62+
if (PLTSec) {
63+
// Expect one entry in the PLT.
64+
EXPECT_EQ(PLTSec->symbols_size(), 1U);
65+
EXPECT_EQ(PLTSec->blocks_size(), 1U);
66+
}
67+
68+
{
69+
// Create second GOT and PLT table managers and request a PLT stub. This
70+
// should force creation of both a PLT stub and GOT entry.
71+
GOTTableManager GOT(G);
72+
PLTTableManager PLT(G, GOT);
73+
74+
PLT.getEntryForTarget(G, External);
75+
}
76+
77+
EXPECT_EQ(G.findSectionByName(GOTTableManager::getSectionName()), GOTSec);
78+
if (GOTSec) {
79+
// Expect the same one entry in the GOT.
80+
EXPECT_EQ(GOTSec->symbols_size(), 1U);
81+
EXPECT_EQ(GOTSec->blocks_size(), 1U);
82+
}
83+
84+
EXPECT_EQ(G.findSectionByName(PLTTableManager::getSectionName()), PLTSec);
85+
if (PLTSec) {
86+
// Expect the same one entry in the GOT.
87+
EXPECT_EQ(PLTSec->symbols_size(), 1U);
88+
EXPECT_EQ(PLTSec->blocks_size(), 1U);
89+
}
90+
}

0 commit comments

Comments
 (0)