77
77
#include " InputFiles.h"
78
78
#include " LinkerScript.h"
79
79
#include " OutputSections.h"
80
+ #include " Relocations.h"
80
81
#include " SymbolTable.h"
81
82
#include " Symbols.h"
82
83
#include " SyntheticSections.h"
84
+ #include " llvm/ADT/ArrayRef.h"
83
85
#include " llvm/BinaryFormat/ELF.h"
84
86
#include " llvm/Object/ELF.h"
85
87
#include " llvm/Support/Parallel.h"
@@ -121,6 +123,8 @@ template <class ELFT> class ICF {
121
123
122
124
void forEachClass (llvm::function_ref<void (size_t , size_t )> fn);
123
125
126
+ void applySafeThunksToRange (size_t begin, size_t end);
127
+
124
128
Ctx &ctx;
125
129
SmallVector<InputSection *, 0 > sections;
126
130
@@ -160,10 +164,14 @@ template <class ELFT> class ICF {
160
164
}
161
165
162
166
// Returns true if section S is subject of ICF.
163
- static bool isEligible (InputSection *s) {
164
- if (!s->isLive () || s->keepUnique || !(s->flags & SHF_ALLOC))
167
+ static bool isEligible (InputSection *s, bool safeThunksMode) {
168
+ if (!s->isLive () || (s->keepUnique && !safeThunksMode) ||
169
+ !(s->flags & SHF_ALLOC))
165
170
return false ;
166
171
172
+ if (s->keepUnique )
173
+ return safeThunksMode && (s->flags & ELF::SHF_EXECINSTR);
174
+
167
175
// Don't merge writable sections. .data.rel.ro sections are marked as writable
168
176
// but are semantically read-only.
169
177
if ((s->flags & SHF_WRITE) && s->name != " .data.rel.ro" &&
@@ -459,6 +467,58 @@ static void combineRelocHashes(unsigned cnt, InputSection *isec,
459
467
isec->eqClass [(cnt + 1 ) % 2 ] = hash | (1U << 31 );
460
468
}
461
469
470
+ // Given a range of identical icfInputs, replace address significant functions
471
+ // with a thunk that is just a direct branch to the first function in the
472
+ // series. This way we keep only one main body of the function but we still
473
+ // retain the address uniqueness of relevant functions by having them be a
474
+ // direct branch thunk rather than containing a full copy of the actual function
475
+ // body.
476
+ template <class ELFT >
477
+ void ICF<ELFT>::applySafeThunksToRange(size_t begin, size_t end) {
478
+ InputSection *masterIsec = sections[begin];
479
+
480
+ uint32_t thunkSize = ctx.target ->getICFSafeThunkSize ();
481
+ // If the functions we're dealing with are smaller than the thunk size, then
482
+ // just leave them all as-is - creating thunks would be a net loss.
483
+ if (masterIsec->getSize () <= thunkSize)
484
+ return ;
485
+
486
+ // Find the symbol to create the thunk for.
487
+ Symbol *masterSym = nullptr ;
488
+ for (Symbol *sym : masterIsec->file ->getSymbols ()) {
489
+ if (auto *d = dyn_cast<Defined>(sym)) {
490
+ if (d->section == masterIsec) {
491
+ masterSym = sym;
492
+ break ;
493
+ }
494
+ }
495
+ }
496
+
497
+ if (!masterSym)
498
+ return ;
499
+
500
+ for (size_t i = begin + 1 ; i < end; ++i) {
501
+ InputSection *isec = sections[i];
502
+ if (!isec->keepUnique )
503
+ break ;
504
+
505
+ auto *thunk = make<InputSection>(*isec);
506
+ ctx.target ->initICFSafeThunkBody (thunk, masterSym);
507
+ thunk->markLive ();
508
+ auto *osec = isec->getParent ();
509
+ auto *isd = cast<InputSectionDescription>(osec->commands .back ());
510
+ isd->sections .push_back (thunk);
511
+ osec->commitSection (thunk);
512
+ isec->repl = thunk;
513
+ isec->markDead ();
514
+
515
+ for (Symbol *sym : thunk->file ->getSymbols ())
516
+ if (auto *d = dyn_cast<Defined>(sym))
517
+ if (d->section == isec)
518
+ d->size = thunkSize;
519
+ }
520
+ }
521
+
462
522
// The main function of ICF.
463
523
template <class ELFT > void ICF<ELFT>::run() {
464
524
// Two text sections may have identical content and relocations but different
@@ -475,10 +535,11 @@ template <class ELFT> void ICF<ELFT>::run() {
475
535
[&](InputSection &s) { s.eqClass [0 ] = s.eqClass [1 ] = ++uniqueId; });
476
536
477
537
// Collect sections to merge.
538
+ bool safeThunksMode = ctx.arg .icf == ICFLevel::SafeThunks;
478
539
for (InputSectionBase *sec : ctx.inputSections ) {
479
540
auto *s = dyn_cast<InputSection>(sec);
480
541
if (s && s->eqClass [0 ] == 0 ) {
481
- if (isEligible (s))
542
+ if (isEligible (s, safeThunksMode ))
482
543
sections.push_back (s);
483
544
else
484
545
// Ineligible sections are assigned unique IDs, i.e. each section
@@ -510,9 +571,13 @@ template <class ELFT> void ICF<ELFT>::run() {
510
571
511
572
// From now on, sections in Sections vector are ordered so that sections
512
573
// in the same equivalence class are consecutive in the vector.
513
- llvm::stable_sort (sections, [](const InputSection *a, const InputSection *b) {
514
- return a->eqClass [0 ] < b->eqClass [0 ];
515
- });
574
+ llvm::stable_sort (
575
+ sections, [safeThunksMode](const InputSection *a, const InputSection *b) {
576
+ if (safeThunksMode)
577
+ if (a->eqClass [0 ] == b->eqClass [0 ])
578
+ return a->keepUnique > b->keepUnique ;
579
+ return a->eqClass [0 ] < b->eqClass [0 ];
580
+ });
516
581
517
582
// Compare static contents and assign unique equivalence class IDs for each
518
583
// static content. Use a base offset for these IDs to ensure no overlap with
@@ -535,12 +600,19 @@ template <class ELFT> void ICF<ELFT>::run() {
535
600
auto print = [&ctx = ctx]() -> ELFSyncStream {
536
601
return {ctx, ctx.arg .printIcfSections ? DiagLevel::Msg : DiagLevel::None};
537
602
};
603
+ if (safeThunksMode)
604
+ forEachClassRange (0 , sections.size (), [&](size_t begin, size_t end) {
605
+ applySafeThunksToRange (begin, end);
606
+ });
607
+
538
608
// Merge sections by the equivalence class.
539
609
forEachClassRange (0 , sections.size (), [&](size_t begin, size_t end) {
540
610
if (end - begin == 1 )
541
611
return ;
542
612
print () << " selected section " << sections[begin];
543
613
for (size_t i = begin + 1 ; i < end; ++i) {
614
+ if (safeThunksMode && sections[i]->keepUnique )
615
+ continue ;
544
616
print () << " removing identical section " << sections[i];
545
617
sections[begin]->replace (sections[i]);
546
618
0 commit comments