@@ -202,7 +202,8 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
202
202
uint64_t Offset,
203
203
uint64_t Value,
204
204
uint32_t Type,
205
- int64_t Addend) {
205
+ int64_t Addend,
206
+ uint64_t SymOffset) {
206
207
switch (Type) {
207
208
default :
208
209
llvm_unreachable (" Relocation type not implemented yet!" );
@@ -227,6 +228,21 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
227
228
<< " at " << format (" %p\n " ,Target));
228
229
break ;
229
230
}
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
+ }
230
246
case ELF::R_X86_64_PC32: {
231
247
// Get the placeholder value from the generated object since
232
248
// a previous relocation attempt may have overwritten the loaded version
@@ -240,6 +256,16 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section,
240
256
*Target = TruncOffset;
241
257
break ;
242
258
}
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
+ }
243
269
}
244
270
}
245
271
@@ -584,7 +610,7 @@ void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
584
610
// Finally compares the Symbol value and the target symbol offset
585
611
// to check if this .opd entry refers to the symbol the relocation
586
612
// points to.
587
- if (Rel.Addend != (intptr_t )TargetSymbolOffset)
613
+ if (Rel.Addend != (int64_t )TargetSymbolOffset)
588
614
continue ;
589
615
590
616
section_iterator tsi (Obj.end_sections ());
@@ -757,17 +783,19 @@ void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
757
783
void RuntimeDyldELF::resolveRelocation (const RelocationEntry &RE,
758
784
uint64_t Value) {
759
785
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 );
761
788
}
762
789
763
790
void RuntimeDyldELF::resolveRelocation (const SectionEntry &Section,
764
791
uint64_t Offset,
765
792
uint64_t Value,
766
793
uint32_t Type,
767
- int64_t Addend) {
794
+ int64_t Addend,
795
+ uint64_t SymOffset) {
768
796
switch (Arch) {
769
797
case Triple::x86_64:
770
- resolveX86_64Relocation (Section, Offset, Value, Type, Addend);
798
+ resolveX86_64Relocation (Section, Offset, Value, Type, Addend, SymOffset );
771
799
break ;
772
800
case Triple::x86:
773
801
resolveX86Relocation (Section, Offset,
@@ -830,6 +858,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
830
858
}
831
859
if (lsi != Symbols.end ()) {
832
860
Value.SectionID = lsi->second .first ;
861
+ Value.Offset = lsi->second .second ;
833
862
Value.Addend = lsi->second .second + Addend;
834
863
} else {
835
864
// Search for the symbol in the global symbol table
@@ -838,6 +867,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
838
867
gsi = GlobalSymbolTable.find (TargetName.data ());
839
868
if (gsi != GlobalSymbolTable.end ()) {
840
869
Value.SectionID = gsi->second .first ;
870
+ Value.Offset = gsi->second .second ;
841
871
Value.Addend = gsi->second .second + Addend;
842
872
} else {
843
873
switch (SymType) {
@@ -860,6 +890,7 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
860
890
Value.Addend = Addend;
861
891
break ;
862
892
}
893
+ case SymbolRef::ST_Data:
863
894
case SymbolRef::ST_Unknown: {
864
895
Value.SymbolName = TargetName.data ();
865
896
Value.Addend = Addend;
@@ -1150,15 +1181,174 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
1150
1181
ELF::R_390_PC32DBL, Addend);
1151
1182
else
1152
1183
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
+ }
1153
1240
} 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 );
1155
1245
if (Value.SymbolName )
1156
1246
addRelocationForSymbol (RE, Value.SymbolName );
1157
1247
else
1158
1248
addRelocationForSection (RE, Value.SectionID );
1159
1249
}
1160
1250
}
1161
1251
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
+
1162
1352
bool RuntimeDyldELF::isCompatibleFormat (const ObjectBuffer *Buffer) const {
1163
1353
if (Buffer->getBufferSize () < strlen (ELF::ElfMagic))
1164
1354
return false ;
0 commit comments