Skip to content

Commit 4612fed

Browse files
author
Andrew Kaylor
committed
Adding PIC support for ELF on x86_64 platforms
llvm-svn: 188726
1 parent f708c87 commit 4612fed

File tree

4 files changed

+244
-16
lines changed

4 files changed

+244
-16
lines changed

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) {
169169
}
170170
}
171171

172+
// Give the subclasses a chance to tie-up any loose ends.
173+
finalizeLoad();
174+
172175
return obj.take();
173176
}
174177

@@ -424,6 +427,10 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
424427
writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1
425428
// 8-byte address stored at Addr + 8
426429
return Addr;
430+
} else if (Arch == Triple::x86_64) {
431+
*Addr = 0xFF; // jmp
432+
*(Addr+1) = 0x25; // rip
433+
// 32-bit PC-relative address of the GOT entry will be stored at Addr+2
427434
}
428435
return Addr;
429436
}
@@ -473,6 +480,7 @@ void RuntimeDyldImpl::resolveExternalSymbols() {
473480
// MemoryManager.
474481
uint8_t *Addr = (uint8_t*) MemMgr->getPointerToNamedFunction(Name.data(),
475482
true);
483+
updateGOTEntries(Name, (uint64_t)Addr);
476484
DEBUG(dbgs() << "Resolving relocations Name: " << Name
477485
<< "\t" << format("%p", Addr)
478486
<< "\n");

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp

Lines changed: 196 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
202202
uint64_t Offset,
203203
uint64_t Value,
204204
uint32_t Type,
205-
int64_t Addend) {
205+
int64_t Addend,
206+
uint64_t SymOffset) {
206207
switch (Type) {
207208
default:
208209
llvm_unreachable("Relocation type not implemented yet!");
@@ -227,6 +228,21 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
227228
<< " at " << format("%p\n",Target));
228229
break;
229230
}
231+
case ELF::R_X86_64_GOTPCREL: {
232+
// findGOTEntry returns the 'G + GOT' part of the relocation calculation
233+
// based on the load/target address of the GOT (not the current/local addr).
234+
uint64_t GOTAddr = findGOTEntry(Value, SymOffset);
235+
uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset);
236+
uint64_t FinalAddress = Section.LoadAddress + Offset;
237+
// The processRelocationRef method combines the symbol offset and the addend
238+
// and in most cases that's what we want. For this relocation type, we need
239+
// the raw addend, so we subtract the symbol offset to get it.
240+
int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress;
241+
assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN);
242+
int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
243+
*Target = TruncOffset;
244+
break;
245+
}
230246
case ELF::R_X86_64_PC32: {
231247
// Get the placeholder value from the generated object since
232248
// a previous relocation attempt may have overwritten the loaded version
@@ -240,6 +256,16 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
240256
*Target = TruncOffset;
241257
break;
242258
}
259+
case ELF::R_X86_64_PC64: {
260+
// Get the placeholder value from the generated object since
261+
// a previous relocation attempt may have overwritten the loaded version
262+
uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress
263+
+ Offset);
264+
uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset);
265+
uint64_t FinalAddress = Section.LoadAddress + Offset;
266+
*Target = *Placeholder + Value + Addend - FinalAddress;
267+
break;
268+
}
243269
}
244270
}
245271

@@ -584,7 +610,7 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
584610
// Finally compares the Symbol value and the target symbol offset
585611
// to check if this .opd entry refers to the symbol the relocation
586612
// points to.
587-
if (Rel.Addend != (intptr_t)TargetSymbolOffset)
613+
if (Rel.Addend != (int64_t)TargetSymbolOffset)
588614
continue;
589615

590616
section_iterator tsi(Obj.end_sections());
@@ -757,17 +783,19 @@ void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
757783
void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE,
758784
uint64_t Value) {
759785
const SectionEntry &Section = Sections[RE.SectionID];
760-
return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
786+
return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
787+
RE.SymOffset);
761788
}
762789

763790
void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
764791
uint64_t Offset,
765792
uint64_t Value,
766793
uint32_t Type,
767-
int64_t Addend) {
794+
int64_t Addend,
795+
uint64_t SymOffset) {
768796
switch (Arch) {
769797
case Triple::x86_64:
770-
resolveX86_64Relocation(Section, Offset, Value, Type, Addend);
798+
resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset);
771799
break;
772800
case Triple::x86:
773801
resolveX86Relocation(Section, Offset,
@@ -830,6 +858,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
830858
}
831859
if (lsi != Symbols.end()) {
832860
Value.SectionID = lsi->second.first;
861+
Value.Offset = lsi->second.second;
833862
Value.Addend = lsi->second.second + Addend;
834863
} else {
835864
// Search for the symbol in the global symbol table
@@ -838,6 +867,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
838867
gsi = GlobalSymbolTable.find(TargetName.data());
839868
if (gsi != GlobalSymbolTable.end()) {
840869
Value.SectionID = gsi->second.first;
870+
Value.Offset = gsi->second.second;
841871
Value.Addend = gsi->second.second + Addend;
842872
} else {
843873
switch (SymType) {
@@ -860,6 +890,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
860890
Value.Addend = Addend;
861891
break;
862892
}
893+
case SymbolRef::ST_Data:
863894
case SymbolRef::ST_Unknown: {
864895
Value.SymbolName = TargetName.data();
865896
Value.Addend = Addend;
@@ -1150,15 +1181,174 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
11501181
ELF::R_390_PC32DBL, Addend);
11511182
else
11521183
resolveRelocation(Section, Offset, StubAddress, RelType, Addend);
1184+
} else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) {
1185+
// The way the PLT relocations normally work is that the linker allocates the
1186+
// PLT and this relocation makes a PC-relative call into the PLT. The PLT
1187+
// entry will then jump to an address provided by the GOT. On first call, the
1188+
// GOT address will point back into PLT code that resolves the symbol. After
1189+
// the first call, the GOT entry points to the actual function.
1190+
//
1191+
// For local functions we're ignoring all of that here and just replacing
1192+
// the PLT32 relocation type with PC32, which will translate the relocation
1193+
// into a PC-relative call directly to the function. For external symbols we
1194+
// can't be sure the function will be within 2^32 bytes of the call site, so
1195+
// we need to create a stub, which calls into the GOT. This case is
1196+
// equivalent to the usual PLT implementation except that we use the stub
1197+
// mechanism in RuntimeDyld (which puts stubs at the end of the section)
1198+
// rather than allocating a PLT section.
1199+
if (Value.SymbolName) {
1200+
// This is a call to an external function.
1201+
// Look for an existing stub.
1202+
SectionEntry &Section = Sections[SectionID];
1203+
StubMap::const_iterator i = Stubs.find(Value);
1204+
uintptr_t StubAddress;
1205+
if (i != Stubs.end()) {
1206+
StubAddress = uintptr_t(Section.Address) + i->second;
1207+
DEBUG(dbgs() << " Stub function found\n");
1208+
} else {
1209+
// Create a new stub function (equivalent to a PLT entry).
1210+
DEBUG(dbgs() << " Create a new stub function\n");
1211+
1212+
uintptr_t BaseAddress = uintptr_t(Section.Address);
1213+
uintptr_t StubAlignment = getStubAlignment();
1214+
StubAddress = (BaseAddress + Section.StubOffset +
1215+
StubAlignment - 1) & -StubAlignment;
1216+
unsigned StubOffset = StubAddress - BaseAddress;
1217+
Stubs[Value] = StubOffset;
1218+
createStubFunction((uint8_t *)StubAddress);
1219+
1220+
// Create a GOT entry for the external function.
1221+
GOTEntries.push_back(Value);
1222+
1223+
// Make our stub function a relative call to the GOT entry.
1224+
RelocationEntry RE(SectionID, StubOffset + 2,
1225+
ELF::R_X86_64_GOTPCREL, -4);
1226+
addRelocationForSymbol(RE, Value.SymbolName);
1227+
1228+
// Bump our stub offset counter
1229+
Section.StubOffset = StubOffset + getMaxStubSize();
1230+
}
1231+
1232+
// Make the target call a call into the stub table.
1233+
resolveRelocation(Section, Offset, StubAddress,
1234+
ELF::R_X86_64_PC32, Addend);
1235+
} else {
1236+
RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend,
1237+
Value.Offset);
1238+
addRelocationForSection(RE, Value.SectionID);
1239+
}
11531240
} else {
1154-
RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
1241+
if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) {
1242+
GOTEntries.push_back(Value);
1243+
}
1244+
RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset);
11551245
if (Value.SymbolName)
11561246
addRelocationForSymbol(RE, Value.SymbolName);
11571247
else
11581248
addRelocationForSection(RE, Value.SectionID);
11591249
}
11601250
}
11611251

1252+
void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) {
1253+
for (int i = 0, e = GOTEntries.size(); i != e; ++i) {
1254+
if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName == Name) {
1255+
GOTEntries[i].Offset = Addr;
1256+
}
1257+
}
1258+
}
1259+
1260+
size_t RuntimeDyldELF::getGOTEntrySize() {
1261+
// We don't use the GOT in all of these cases, but it's essentially free
1262+
// to put them all here.
1263+
size_t Result = 0;
1264+
switch (Arch) {
1265+
case Triple::x86_64:
1266+
case Triple::aarch64:
1267+
case Triple::ppc64:
1268+
case Triple::ppc64le:
1269+
case Triple::systemz:
1270+
Result = sizeof(uint64_t);
1271+
break;
1272+
case Triple::x86:
1273+
case Triple::arm:
1274+
case Triple::thumb:
1275+
case Triple::mips:
1276+
case Triple::mipsel:
1277+
Result = sizeof(uint32_t);
1278+
break;
1279+
default: llvm_unreachable("Unsupported CPU type!");
1280+
}
1281+
return Result;
1282+
}
1283+
1284+
uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress,
1285+
uint64_t Offset) {
1286+
assert(GOTSectionID != 0
1287+
&& "Attempting to lookup GOT entry but the GOT was never allocated.");
1288+
if (GOTSectionID == 0) {
1289+
return 0;
1290+
}
1291+
1292+
size_t GOTEntrySize = getGOTEntrySize();
1293+
1294+
// Find the matching entry in our vector.
1295+
int GOTIndex = -1;
1296+
uint64_t SymbolOffset = 0;
1297+
for (int i = 0, e = GOTEntries.size(); i != e; ++i) {
1298+
if (GOTEntries[i].SymbolName == 0) {
1299+
if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress &&
1300+
GOTEntries[i].Offset == Offset) {
1301+
GOTIndex = i;
1302+
SymbolOffset = GOTEntries[i].Offset;
1303+
break;
1304+
}
1305+
} else {
1306+
// GOT entries for external symbols use the addend as the address when
1307+
// the external symbol has been resolved.
1308+
if (GOTEntries[i].Offset == LoadAddress) {
1309+
GOTIndex = i;
1310+
// Don't use the Addend here. The relocation handler will use it.
1311+
break;
1312+
}
1313+
}
1314+
}
1315+
assert(GOTIndex != -1 && "Unable to find requested GOT entry.");
1316+
if (GOTIndex == -1)
1317+
return 0;
1318+
1319+
if (GOTEntrySize == sizeof(uint64_t)) {
1320+
uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID);
1321+
// Fill in this entry with the address of the symbol being referenced.
1322+
LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset;
1323+
} else {
1324+
uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID);
1325+
// Fill in this entry with the address of the symbol being referenced.
1326+
LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset);
1327+
}
1328+
1329+
// Calculate the load address of this entry
1330+
return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize);
1331+
}
1332+
1333+
void RuntimeDyldELF::finalizeLoad() {
1334+
// Allocate the GOT if necessary
1335+
size_t numGOTEntries = GOTEntries.size();
1336+
if (numGOTEntries != 0) {
1337+
// Allocate memory for the section
1338+
unsigned SectionID = Sections.size();
1339+
size_t TotalSize = numGOTEntries * getGOTEntrySize();
1340+
uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, getGOTEntrySize(),
1341+
SectionID, false);
1342+
if (!Addr)
1343+
report_fatal_error("Unable to allocate memory for GOT!");
1344+
Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0));
1345+
// For now, initialize all GOT entries to zero. We'll fill them in as
1346+
// needed when GOT-based relocations are applied.
1347+
memset(Addr, 0, TotalSize);
1348+
GOTSectionID = SectionID;
1349+
}
1350+
}
1351+
11621352
bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const {
11631353
if (Buffer->getBufferSize() < strlen(ELF::ElfMagic))
11641354
return false;

llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
3535
uint64_t Offset,
3636
uint64_t Value,
3737
uint32_t Type,
38-
int64_t Addend);
38+
int64_t Addend,
39+
uint64_t SymOffset=0);
3940

4041
void resolveX86_64Relocation(const SectionEntry &Section,
4142
uint64_t Offset,
4243
uint64_t Value,
4344
uint32_t Type,
44-
int64_t Addend);
45+
int64_t Addend,
46+
uint64_t SymOffset);
4547

4648
void resolveX86Relocation(const SectionEntry &Section,
4749
uint64_t Offset,
@@ -84,8 +86,18 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
8486
ObjSectionToIDMap &LocalSections,
8587
RelocationValueRef &Rel);
8688

89+
uint64_t findGOTEntry(uint64_t LoadAddr, uint64_t Offset);
90+
size_t getGOTEntrySize();
91+
92+
virtual void updateGOTEntries(StringRef Name, uint64_t Addr);
93+
94+
SmallVector<RelocationValueRef, 2> GOTEntries;
95+
unsigned GOTSectionID;
96+
8797
public:
88-
RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
98+
RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm),
99+
GOTSectionID(0)
100+
{}
89101

90102
virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value);
91103
virtual void processRelocationRef(unsigned SectionID,
@@ -97,6 +109,7 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
97109
virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const;
98110
virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
99111
virtual StringRef getEHFrameSection();
112+
virtual void finalizeLoad();
100113
virtual ~RuntimeDyldELF();
101114
};
102115

0 commit comments

Comments
 (0)