@@ -333,6 +333,28 @@ bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) {
333333 : constantEq (a, ra.relas , b, rb.relas );
334334}
335335
336+ template <class RelTy >
337+ static SmallVector<Symbol *> getReloc (const InputSection *sec,
338+ Relocs<RelTy> relocs) {
339+ SmallVector<Symbol *> syms;
340+ for (auto ri = relocs.begin (), re = relocs.end (); ri != re; ++ri) {
341+ Symbol &sym = sec->file ->getRelocTargetSym (*ri);
342+ syms.push_back (&sym);
343+ }
344+ return syms;
345+ }
346+
347+ template <class ELFT >
348+ static SmallVector<Symbol *> getRelocTargetSyms (const InputSection *sec) {
349+ const RelsOrRelas<ELFT> rel = sec->template relsOrRelas <ELFT>();
350+ if (rel.areRelocsCrel ())
351+ return getReloc (sec, rel.crels );
352+ if (rel.areRelocsRel ())
353+ return getReloc (sec, rel.rels );
354+
355+ return getReloc (sec, rel.relas );
356+ }
357+
336358// Compare two lists of relocations. Returns true if all pairs of
337359// relocations point to the same section in terms of ICF.
338360template <class ELFT >
@@ -535,14 +557,35 @@ template <class ELFT> void ICF<ELFT>::run() {
535557 auto print = [&ctx = ctx]() -> ELFSyncStream {
536558 return {ctx, ctx.arg .printIcfSections ? DiagLevel::Msg : DiagLevel::None};
537559 };
560+
561+ DenseMap<Symbol *, Symbol *> symbolMap;
538562 // Merge sections by the equivalence class.
563+ // Merge symbols identified as equivalent during ICF
539564 forEachClassRange (0 , sections.size (), [&](size_t begin, size_t end) {
540565 if (end - begin == 1 )
541566 return ;
542567 print () << " selected section " << sections[begin];
568+ SmallVector<Symbol *> syms = getRelocTargetSyms<ELFT>(sections[begin]);
543569 for (size_t i = begin + 1 ; i < end; ++i) {
544570 print () << " removing identical section " << sections[i];
545571 sections[begin]->replace (sections[i]);
572+ SmallVector<Symbol *> replacedSyms =
573+ getRelocTargetSyms<ELFT>(sections[i]);
574+ assert (syms.size () == replacedSyms.size () &&
575+ " Should have same number of syms!" );
576+ for (size_t i = 0 ; i < syms.size (); i++) {
577+ if (syms[i] == replacedSyms[i] || !syms[i]->isGlobal () ||
578+ !replacedSyms[i]->isGlobal ())
579+ continue ;
580+ auto [it, inserted] =
581+ symbolMap.insert (std::make_pair (replacedSyms[i], syms[i]));
582+ print () << " selected symbol: " << syms[i]->getName ().data ()
583+ << " ; replaced symbol: " << replacedSyms[i]->getName ().data ();
584+ if (!inserted) {
585+ print () << " replacement already exists: "
586+ << it->getSecond ()->getName ().data ();
587+ }
588+ }
546589
547590 // At this point we know sections merged are fully identical and hence
548591 // we want to remove duplicate implicit dependencies such as link order
@@ -561,11 +604,17 @@ template <class ELFT> void ICF<ELFT>::run() {
561604 d->folded = true ;
562605 }
563606 };
564- for (Symbol *sym : ctx.symtab ->getSymbols ())
607+ for (Symbol *sym : ctx.symtab ->getSymbols ()) {
565608 fold (sym);
609+ if (Symbol *s = symbolMap.lookup (sym))
610+ ctx.symtab ->redirect (sym, s);
611+ }
566612 parallelForEach (ctx.objectFiles , [&](ELFFileBase *file) {
567613 for (Symbol *sym : file->getLocalSymbols ())
568614 fold (sym);
615+ for (Symbol *&sym : file->getMutableGlobalSymbols ())
616+ if (Symbol *s = symbolMap.lookup (sym))
617+ sym = s;
569618 });
570619
571620 // InputSectionDescription::sections is populated by processSectionCommands().
0 commit comments