@@ -2074,6 +2074,19 @@ bool RewriteInstance::analyzeRelocation(
2074
2074
}
2075
2075
2076
2076
void RewriteInstance::processDynamicRelocations () {
2077
+ // Read .relr.dyn section containing compressed R_*_RELATIVE relocations.
2078
+ if (DynamicRelrSize > 0 ) {
2079
+ ErrorOr<BinarySection &> DynamicRelrSectionOrErr =
2080
+ BC->getSectionForAddress (*DynamicRelrAddress);
2081
+ if (!DynamicRelrSectionOrErr)
2082
+ report_error (" unable to find section corresponding to DT_RELR" ,
2083
+ DynamicRelrSectionOrErr.getError ());
2084
+ if (DynamicRelrSectionOrErr->getSize () != DynamicRelrSize)
2085
+ report_error (" section size mismatch for DT_RELRSZ" ,
2086
+ errc::executable_format_error);
2087
+ readDynamicRelrRelocations (*DynamicRelrSectionOrErr);
2088
+ }
2089
+
2077
2090
// Read relocations for PLT - DT_JMPREL.
2078
2091
if (PLTRelocationsSize > 0 ) {
2079
2092
ErrorOr<BinarySection &> PLTRelSectionOrErr =
@@ -2372,6 +2385,60 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
2372
2385
}
2373
2386
}
2374
2387
2388
+ void RewriteInstance::readDynamicRelrRelocations (BinarySection &Section) {
2389
+ assert (Section.isAllocatable () && " allocatable expected" );
2390
+
2391
+ LLVM_DEBUG ({
2392
+ StringRef SectionName = Section.getName ();
2393
+ dbgs () << " BOLT-DEBUG: reading relocations in section " << SectionName
2394
+ << " :\n " ;
2395
+ });
2396
+
2397
+ const uint64_t RType = Relocation::getRelative ();
2398
+ const uint8_t PSize = BC->AsmInfo ->getCodePointerSize ();
2399
+ const uint64_t MaxDelta = ((CHAR_BIT * DynamicRelrEntrySize) - 1 ) * PSize;
2400
+
2401
+ auto ExtractAddendValue = [&](uint64_t Address) -> uint64_t {
2402
+ ErrorOr<BinarySection &> Section = BC->getSectionForAddress (Address);
2403
+ assert (Section && " cannot get section for data address from RELR" );
2404
+ DataExtractor DE = DataExtractor (Section->getContents (),
2405
+ BC->AsmInfo ->isLittleEndian (), PSize);
2406
+ uint64_t Offset = Address - Section->getAddress ();
2407
+ return DE.getUnsigned (&Offset, PSize);
2408
+ };
2409
+
2410
+ auto AddRelocation = [&](uint64_t Address) {
2411
+ uint64_t Addend = ExtractAddendValue (Address);
2412
+ LLVM_DEBUG (dbgs () << " BOLT-DEBUG: R_*_RELATIVE relocation at 0x"
2413
+ << Twine::utohexstr (Address) << " to 0x"
2414
+ << Twine::utohexstr (Addend) << ' \n ' ;);
2415
+ BC->addDynamicRelocation (Address, nullptr , RType, Addend);
2416
+ };
2417
+
2418
+ DataExtractor DE = DataExtractor (Section.getContents (),
2419
+ BC->AsmInfo ->isLittleEndian (), PSize);
2420
+ uint64_t Offset = 0 , Address = 0 ;
2421
+ uint64_t RelrCount = DynamicRelrSize / DynamicRelrEntrySize;
2422
+ while (RelrCount--) {
2423
+ assert (DE.isValidOffset (Offset));
2424
+ uint64_t Entry = DE.getUnsigned (&Offset, DynamicRelrEntrySize);
2425
+ if ((Entry & 1 ) == 0 ) {
2426
+ AddRelocation (Entry);
2427
+ Address = Entry + PSize;
2428
+ } else {
2429
+ const uint64_t StartAddress = Address;
2430
+ while (Entry >>= 1 ) {
2431
+ if (Entry & 1 )
2432
+ AddRelocation (Address);
2433
+
2434
+ Address += PSize;
2435
+ }
2436
+
2437
+ Address = StartAddress + MaxDelta;
2438
+ }
2439
+ }
2440
+ }
2441
+
2375
2442
void RewriteInstance::printRelocationInfo (const RelocationRef &Rel,
2376
2443
StringRef SymbolName,
2377
2444
uint64_t SymbolAddress,
@@ -5203,6 +5270,101 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
5203
5270
ELF::SHT_STRTAB);
5204
5271
}
5205
5272
5273
+ template <typename ELFT>
5274
+ void RewriteInstance::patchELFAllocatableRelrSection (
5275
+ ELFObjectFile<ELFT> *File) {
5276
+ if (!DynamicRelrAddress)
5277
+ return ;
5278
+
5279
+ raw_fd_ostream &OS = Out->os ();
5280
+ const uint8_t PSize = BC->AsmInfo ->getCodePointerSize ();
5281
+ const uint64_t MaxDelta = ((CHAR_BIT * DynamicRelrEntrySize) - 1 ) * PSize;
5282
+
5283
+ auto FixAddend = [&](const BinarySection &Section, const Relocation &Rel) {
5284
+ // Fix relocation symbol value in place if no static relocation found
5285
+ // on the same address
5286
+ if (Section.getRelocationAt (Rel.Offset ))
5287
+ return ;
5288
+
5289
+ // No fixup needed if symbol address was not changed
5290
+ const uint64_t Addend = getNewFunctionOrDataAddress (Rel.Addend );
5291
+ if (!Addend)
5292
+ return ;
5293
+
5294
+ uint64_t FileOffset = Section.getOutputFileOffset ();
5295
+ if (!FileOffset)
5296
+ FileOffset = Section.getInputFileOffset ();
5297
+
5298
+ FileOffset += Rel.Offset ;
5299
+ OS.pwrite (reinterpret_cast <const char *>(&Addend), PSize, FileOffset);
5300
+ };
5301
+
5302
+ // Fill new relative relocation offsets set
5303
+ std::set<uint64_t > RelOffsets;
5304
+ for (const BinarySection &Section : BC->allocatableSections ()) {
5305
+ const uint64_t SectionInputAddress = Section.getAddress ();
5306
+ uint64_t SectionAddress = Section.getOutputAddress ();
5307
+ if (!SectionAddress)
5308
+ SectionAddress = SectionInputAddress;
5309
+
5310
+ for (const Relocation &Rel : Section.dynamicRelocations ()) {
5311
+ if (!Rel.isRelative ())
5312
+ continue ;
5313
+
5314
+ uint64_t RelOffset =
5315
+ getNewFunctionOrDataAddress (SectionInputAddress + Rel.Offset );
5316
+
5317
+ RelOffset = RelOffset == 0 ? SectionAddress + Rel.Offset : RelOffset;
5318
+ assert ((RelOffset & 1 ) == 0 && " Wrong relocation offset" );
5319
+ RelOffsets.emplace (RelOffset);
5320
+ FixAddend (Section, Rel);
5321
+ }
5322
+ }
5323
+
5324
+ ErrorOr<BinarySection &> Section =
5325
+ BC->getSectionForAddress (*DynamicRelrAddress);
5326
+ assert (Section && " cannot get .relr.dyn section" );
5327
+ assert (Section->isRelr () && " Expected section to be SHT_RELR type" );
5328
+ uint64_t RelrDynOffset = Section->getInputFileOffset ();
5329
+ const uint64_t RelrDynEndOffset = RelrDynOffset + Section->getSize ();
5330
+
5331
+ auto WriteRelr = [&](uint64_t Value) {
5332
+ if (RelrDynOffset + DynamicRelrEntrySize > RelrDynEndOffset) {
5333
+ errs () << " BOLT-ERROR: Offset overflow for relr.dyn section\n " ;
5334
+ exit (1 );
5335
+ }
5336
+
5337
+ OS.pwrite (reinterpret_cast <const char *>(&Value), DynamicRelrEntrySize,
5338
+ RelrDynOffset);
5339
+ RelrDynOffset += DynamicRelrEntrySize;
5340
+ };
5341
+
5342
+ for (auto RelIt = RelOffsets.begin (); RelIt != RelOffsets.end ();) {
5343
+ WriteRelr (*RelIt);
5344
+ uint64_t Base = *RelIt++ + PSize;
5345
+ while (1 ) {
5346
+ uint64_t Bitmap = 0 ;
5347
+ for (; RelIt != RelOffsets.end (); ++RelIt) {
5348
+ const uint64_t Delta = *RelIt - Base;
5349
+ if (Delta >= MaxDelta || Delta % PSize)
5350
+ break ;
5351
+
5352
+ Bitmap |= (1ULL << (Delta / PSize));
5353
+ }
5354
+
5355
+ if (!Bitmap)
5356
+ break ;
5357
+
5358
+ WriteRelr ((Bitmap << 1 ) | 1 );
5359
+ Base += MaxDelta;
5360
+ }
5361
+ }
5362
+
5363
+ // Fill the rest of the section with empty bitmap value
5364
+ while (RelrDynOffset != RelrDynEndOffset)
5365
+ WriteRelr (1 );
5366
+ }
5367
+
5206
5368
template <typename ELFT>
5207
5369
void
5208
5370
RewriteInstance::patchELFAllocatableRelaSections (ELFObjectFile<ELFT> *File) {
@@ -5294,8 +5456,11 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
5294
5456
}
5295
5457
};
5296
5458
5297
- // The dynamic linker expects R_*_RELATIVE relocations to be emitted first
5298
- writeRelocations (/* PatchRelative */ true );
5459
+ // Place R_*_RELATIVE relocations in RELA section if RELR is not presented.
5460
+ // The dynamic linker expects all R_*_RELATIVE relocations in RELA
5461
+ // to be emitted first.
5462
+ if (!DynamicRelrAddress)
5463
+ writeRelocations (/* PatchRelative */ true );
5299
5464
writeRelocations (/* PatchRelative */ false );
5300
5465
5301
5466
auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) {
@@ -5501,6 +5666,15 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
5501
5666
case ELF::DT_RELACOUNT:
5502
5667
DynamicRelativeRelocationsCount = Dyn.getVal ();
5503
5668
break ;
5669
+ case ELF::DT_RELR:
5670
+ DynamicRelrAddress = Dyn.getPtr ();
5671
+ break ;
5672
+ case ELF::DT_RELRSZ:
5673
+ DynamicRelrSize = Dyn.getVal ();
5674
+ break ;
5675
+ case ELF::DT_RELRENT:
5676
+ DynamicRelrEntrySize = Dyn.getVal ();
5677
+ break ;
5504
5678
}
5505
5679
}
5506
5680
@@ -5513,6 +5687,20 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
5513
5687
PLTRelocationsAddress.reset ();
5514
5688
PLTRelocationsSize = 0 ;
5515
5689
}
5690
+
5691
+ if (!DynamicRelrAddress || !DynamicRelrSize) {
5692
+ DynamicRelrAddress.reset ();
5693
+ DynamicRelrSize = 0 ;
5694
+ } else if (!DynamicRelrEntrySize) {
5695
+ errs () << " BOLT-ERROR: expected DT_RELRENT to be presented "
5696
+ << " in DYNAMIC section\n " ;
5697
+ exit (1 );
5698
+ } else if (DynamicRelrSize % DynamicRelrEntrySize) {
5699
+ errs () << " BOLT-ERROR: expected RELR table size to be divisible "
5700
+ << " by RELR entry size\n " ;
5701
+ exit (1 );
5702
+ }
5703
+
5516
5704
return Error::success ();
5517
5705
}
5518
5706
@@ -5724,6 +5912,7 @@ void RewriteInstance::rewriteFile() {
5724
5912
5725
5913
if (BC->HasRelocations ) {
5726
5914
patchELFAllocatableRelaSections ();
5915
+ patchELFAllocatableRelrSection ();
5727
5916
patchELFGOT ();
5728
5917
}
5729
5918
0 commit comments