Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -130,7 +130,7 @@ : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections), - Type(Type), StOther(StOther), Name(Name) {} + CachedVA(false), Type(Type), StOther(StOther), Name(Name) {} const unsigned SymbolKind : 8; @@ -156,6 +156,8 @@ // True if an undefined or shared symbol is used from a live section. unsigned Used : 1; + unsigned CachedVA : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -39,7 +39,7 @@ Defined *ElfSym::MipsGpDisp; Defined *ElfSym::MipsLocalGp; -static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { +static uint64_t getSymVA(const Symbol &Sym) { switch (Sym.kind()) { case Symbol::DefinedKind: { auto &D = cast(Sym); @@ -56,24 +56,6 @@ if (!IS) return D.Value; - uint64_t Offset = D.Value; - - // An object in an SHF_MERGE section might be referenced via a - // section symbol (as a hack for reducing the number of local - // symbols). - // Depending on the addend, the reference via a section symbol - // refers to a different object in the merge section. - // Since the objects in the merge section are not necessarily - // contiguous in the output, the addend can thus affect the final - // VA in a non-linear way. - // To make this work, we incorporate the addend into the section - // offset (and zero out the addend for later processing) so that - // we find the right object in the section. - if (D.isSection()) { - Offset += Addend; - Addend = 0; - } - // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: // 1. The address of the output section. @@ -84,7 +66,7 @@ // If you understand the data structures involved with this next // line (and how they get built), then you have a pretty good // understanding of the linker. - uint64_t VA = IS->getVA(Offset); + uint64_t VA = IS->getVA(D.Value); if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) @@ -113,7 +95,33 @@ } uint64_t Symbol::getVA(int64_t Addend) const { - uint64_t OutVA = getSymVA(*this, Addend); + if (CachedVA) + return cast(this)->Value + Addend; + + // An object in an SHF_MERGE section might be referenced via a + // section symbol (as a hack for reducing the number of local + // symbols). + // Depending on the addend, the reference via a section symbol + // refers to a different object in the merge section. + // Since the objects in the merge section are not necessarily + // contiguous in the output, the addend can thus affect the final + // VA in a non-linear way. + // To make this work, we incorporate the addend into the section + // offset (and zero out the addend for later processing) so that + // we find the right object in the section. + if (isSection()) { + if (auto *Sec = dyn_cast(cast(this)->Section)) { + if (SyntheticSection *SS = Sec->getParent()) + return SS->getParent()->Addr + SS->OutSecOff + Sec->getOffset(Addend); + return Sec->getOffset(Addend); + } + } + + uint64_t OutVA = getSymVA(*this); + if (auto *D = dyn_cast(this)) { + const_cast(D)->Value = OutVA; + const_cast(D)->CachedVA = true; + } return OutVA + Addend; }