Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/ELF/InputSection.h @@ -70,16 +70,16 @@ StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } ObjectFile *getFile() const { return File; } - uintX_t getOffset(const DefinedRegular &Sym); + uintX_t getOffset(const DefinedRegular &Sym) const; // Translate an offset in the input section to an offset in the output // section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; ArrayRef getSectionData() const; void relocate(uint8_t *Buf, uint8_t *BufEnd); - std::vector Relocations; + std::vector> Relocations; }; template InputSectionBase InputSectionBase::Discarded; @@ -125,6 +125,7 @@ // Returns the SectionPiece at a given input section offset. SectionPiece *getSectionPiece(uintX_t Offset); + const SectionPiece *getSectionPiece(uintX_t Offset) const; }; // This corresponds to a SHF_MERGE section of an input file. @@ -143,7 +144,7 @@ // Translate an offset in the input section to an offset // in the output section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; void finalizePieces(); @@ -163,7 +164,7 @@ // Translate an offset in the input section to an offset in the output // section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; // Relocation section that refer to this one. const Elf_Shdr *RelocSection = nullptr; Index: lld/trunk/ELF/InputSection.cpp =================================================================== --- lld/trunk/ELF/InputSection.cpp +++ lld/trunk/ELF/InputSection.cpp @@ -56,7 +56,7 @@ } template -typename ELFT::uint InputSectionBase::getOffset(uintX_t Offset) { +typename ELFT::uint InputSectionBase::getOffset(uintX_t Offset) const { switch (SectionKind) { case Regular: return cast>(this)->OutSecOff + Offset; @@ -80,7 +80,7 @@ template typename ELFT::uint -InputSectionBase::getOffset(const DefinedRegular &Sym) { +InputSectionBase::getOffset(const DefinedRegular &Sym) const { return getOffset(Sym.Value); } @@ -297,8 +297,8 @@ } const unsigned Bits = sizeof(uintX_t) * 8; - for (const Relocation &Rel : Relocations) { - uintX_t Offset = Rel.Offset; + for (const Relocation &Rel : Relocations) { + uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; uint32_t Type = Rel.Type; uintX_t A = Rel.Addend; @@ -422,13 +422,13 @@ } template -typename ELFT::uint EhInputSection::getOffset(uintX_t Offset) { +typename ELFT::uint EhInputSection::getOffset(uintX_t Offset) const { // The file crtbeginT.o has relocations pointing to the start of an empty // .eh_frame that is known to be the first in the link. It does that to // identify the start of the output .eh_frame. Handle this special case. if (this->getSectionHdr()->sh_size == 0) return Offset; - SectionPiece *Piece = this->getSectionPiece(Offset); + const SectionPiece *Piece = this->getSectionPiece(Offset); if (Piece->OutputOff == size_t(-1)) return -1; // Not in the output @@ -506,6 +506,13 @@ // Do binary search to get a section piece at a given input offset. template SectionPiece *SplitInputSection::getSectionPiece(uintX_t Offset) { + auto *This = static_cast *>(this); + return const_cast(This->getSectionPiece(Offset)); +} + +template +const SectionPiece * +SplitInputSection::getSectionPiece(uintX_t Offset) const { ArrayRef D = this->getSectionData(); StringRef Data((const char *)D.data(), D.size()); uintX_t Size = Data.size(); @@ -524,14 +531,14 @@ // Because contents of a mergeable section is not contiguous in output, // it is not just an addition to a base output offset. template -typename ELFT::uint MergeInputSection::getOffset(uintX_t Offset) { +typename ELFT::uint MergeInputSection::getOffset(uintX_t Offset) const { auto It = OffsetMap.find(Offset); if (It != OffsetMap.end()) return It->second; // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. - SectionPiece &Piece = *this->getSectionPiece(Offset); + const SectionPiece &Piece = *this->getSectionPiece(Offset); assert(Piece.Live); uintX_t Addend = Offset - Piece.InputOff; return Piece.OutputOff + Addend; Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -96,8 +96,7 @@ virtual void finalize() {} virtual void finalizePieces() {} - virtual void - forEachInputSection(std::function *)> F) {} + virtual void assignOffsets() {} virtual void writeTo(uint8_t *Buf) {} virtual ~OutputSectionBase() = default; @@ -197,21 +196,35 @@ std::vector> Entries; }; -template struct DynamicReloc { +template class DynamicReloc { typedef typename ELFT::uint uintX_t; + +public: + DynamicReloc(uint32_t Type, const InputSectionBase *InputSec, + uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, + uintX_t Addend) + : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), + UseSymVA(UseSymVA), Addend(Addend) {} + + DynamicReloc(uint32_t Type, const OutputSectionBase *OutputSec, + uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, + uintX_t Addend) + : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec), + UseSymVA(UseSymVA), Addend(Addend) {} + + uintX_t getOffset() const; + uintX_t getAddend() const; + uint32_t getSymIndex() const; + uint32_t Type; +private: SymbolBody *Sym; - const OutputSectionBase *OffsetSec; + const InputSectionBase *InputSec = nullptr; + const OutputSectionBase *OutputSec = nullptr; uintX_t OffsetInSec; bool UseSymVA; uintX_t Addend; - - DynamicReloc(uint32_t Type, const OutputSectionBase *OffsetSec, - uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, - uintX_t Addend) - : Type(Type), Sym(Sym), OffsetSec(OffsetSec), OffsetInSec(OffsetInSec), - UseSymVA(UseSymVA), Addend(Addend) {} }; template @@ -343,8 +356,7 @@ void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; void finalize() override; - void - forEachInputSection(std::function *)> F) override; + void assignOffsets() override; std::vector *> Sections; }; @@ -385,8 +397,6 @@ void writeTo(uint8_t *Buf) override; void finalize() override; bool empty() const { return Sections.empty(); } - void - forEachInputSection(std::function *)> F) override; void addSection(InputSectionBase *S) override; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -351,13 +351,11 @@ for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(Buf); Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - SymbolBody *Sym = Rel.Sym; if (Config->Rela) - P->r_addend = Rel.UseSymVA ? Sym->getVA(Rel.Addend) : Rel.Addend; - P->r_offset = Rel.OffsetInSec + Rel.OffsetSec->getVA(); - uint32_t SymIdx = (!Rel.UseSymVA && Sym) ? Sym->DynsymIndex : 0; - P->setSymbolAndType(SymIdx, Rel.Type, Config->Mips64EL); + P->r_addend = Rel.getAddend(); + P->r_offset = Rel.getOffset(); + P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); } if (Sort) { @@ -836,11 +834,16 @@ return V; } -template -void OutputSection::forEachInputSection( - std::function *)> F) { - for (InputSection *S : Sections) - F(S); +// This function is called after we sort input sections +// and scan relocations to setup sections' offsets. +template void OutputSection::assignOffsets() { + uintX_t Off = this->Header.sh_size; + for (InputSection *S : Sections) { + Off = alignTo(Off, S->Alignment); + S->OutSecOff = Off; + Off += S->getSize(); + } + this->Header.sh_size = Off; } // Sorts input sections by section name suffixes, so that .foo.N comes @@ -947,13 +950,6 @@ EhOutputSection::EhOutputSection() : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {} -template -void EhOutputSection::forEachInputSection( - std::function *)> F) { - for (EhInputSection *S : Sections) - F(S); -} - // Returns the first relocation that points to a region // between Begin and Begin+Size. template @@ -1269,6 +1265,26 @@ } template +typename ELFT::uint DynamicReloc::getOffset() const { + if (OutputSec) + return OutputSec->getVA() + OffsetInSec; + return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec); +} + +template +typename ELFT::uint DynamicReloc::getAddend() const { + if (UseSymVA) + return Sym->getVA(Addend); + return Addend; +} + +template uint32_t DynamicReloc::getSymIndex() const { + if (Sym && !UseSymVA) + return Sym->DynsymIndex; + return 0; +} + +template SymbolTableSection::SymbolTableSection( StringTableSection &StrTabSec) : OutputSectionBase(StrTabSec.isDynamic() ? ".dynsym" : ".symtab", Index: lld/trunk/ELF/Relocations.h =================================================================== --- lld/trunk/ELF/Relocations.h +++ lld/trunk/ELF/Relocations.h @@ -60,9 +60,10 @@ R_TLSLD_PC }; -struct Relocation { +template struct Relocation { RelExpr Expr; uint32_t Type; + InputSectionBase *InputSec; uint64_t Offset; uint64_t Addend; SymbolBody *Sym; Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -103,7 +103,7 @@ {Target->TlsDescRel, Out::Got, Off, false, &Body, 0}); } if (Expr != R_HINT) - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); return 1; } @@ -111,21 +111,21 @@ // Local-Dynamic relocs can be relaxed to Local-Exec. if (!Config->Shared) { C.Relocations.push_back( - {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); + {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body}); return 2; } if (Out::Got->addTlsIndex()) Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, Out::Got->getTlsIndexOff(), false, nullptr, 0}); - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); return 1; } // Local-Dynamic relocs can be relaxed to Local-Exec. if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) { C.Relocations.push_back( - {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); + {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body}); return 1; } @@ -144,7 +144,7 @@ Off + (uintX_t)sizeof(uintX_t), false, &Body, 0}); } - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); return 1; } @@ -153,7 +153,7 @@ if (isPreemptible(Body, Type)) { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, - Offset, Addend, &Body}); + &C, Offset, Addend, &Body}); if (!Body.isInGot()) { Out::Got->addEntry(Body); Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, @@ -163,7 +163,7 @@ return Target->TlsGdRelaxSkip; } C.Relocations.push_back( - {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, &C, Offset, Addend, &Body}); return Target->TlsGdRelaxSkip; } @@ -173,7 +173,7 @@ if (Target->isTlsInitialExecRel(Type) && !Config->Shared && !isPreemptible(Body, Type)) { C.Relocations.push_back( - {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); + {R_RELAX_TLS_IE_TO_LE, Type, &C, Offset, Addend, &Body}); return 1; } return 0; @@ -497,8 +497,9 @@ if (HasError) continue; - uintX_t Offset = C.getOffset(RI.r_offset); - if (Offset == (uintX_t)-1) + // Skip a relocation that points to a dead piece + // in a mergeable section. + if (C.getOffset(RI.r_offset) == (uintX_t)-1) continue; // This relocation does not require got entry, but it is relative to got and @@ -508,8 +509,8 @@ uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body); - if (unsigned Processed = - handleTlsRelocation(Type, Body, C, Offset, Addend, Expr)) { + if (unsigned Processed = handleTlsRelocation( + Type, Body, C, RI.r_offset, Addend, Expr)) { I += (Processed - 1); continue; } @@ -529,17 +530,17 @@ // relocation. We can process some of it and and just ask the dynamic // linker to add the load address. if (!Constant) - AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend}); + AddDyn({Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend}); // If the produced value is a constant, we just remember to write it // when outputting this section. We also have to do it if the format // uses Elf_Rel, since in that case the written value is the addend. if (Constant || !RelTy::IsRela) - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, &C, RI.r_offset, Addend, &Body}); } else { // We don't know anything about the finaly symbol. Just ask the dynamic // linker to handle the relocation for us. - AddDyn({Target->getDynRel(Type), C.OutSec, Offset, false, &Body, Addend}); + AddDyn({Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend}); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries // MIPS ABI requires dynamic linker to fills up GOT entries using Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -793,24 +793,24 @@ // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. - for (OutputSectionBase *Sec : OutputSections) { - Sec->forEachInputSection([&](InputSectionBase *S) { - if (auto *IS = dyn_cast>(S)) { - // Set OutSecOff so that scanRelocations can use it. - uintX_t Off = alignTo(Sec->getSize(), S->Alignment); - IS->OutSecOff = Off; - - scanRelocations(*IS); - - // Now that scan relocs possibly changed the size, update the offset. - Sec->setSize(Off + S->getSize()); - } else if (auto *EH = dyn_cast>(S)) { - if (EH->RelocSection) - scanRelocations(*EH, *EH->RelocSection); + for (const std::unique_ptr> &F : + Symtab.getObjectFiles()) { + for (InputSectionBase *C : F->getSections()) { + if (isDiscarded(C)) + continue; + if (auto *S = dyn_cast>(C)) { + scanRelocations(*S); + continue; } - }); + if (auto *S = dyn_cast>(C)) + if (S->RelocSection) + scanRelocations(*S, *S->RelocSection); + } } + for (OutputSectionBase *Sec : OutputSections) + Sec->assignOffsets(); + // Now that we have defined all possible symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. std::vector CommonSymbols; Index: lld/trunk/test/ELF/mips-npic-call-pic.s =================================================================== --- lld/trunk/test/ELF/mips-npic-call-pic.s +++ lld/trunk/test/ELF/mips-npic-call-pic.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check LA25 stubs creation. This stub code is necessary when # non-PIC code calls PIC function. @@ -7,8 +8,6 @@ # RUN: ld.lld %t-npic.o %t-pic.o %p/Inputs/mips-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 20000: 0c 00 80 0e jal 131128 @@ -72,6 +71,68 @@ # CHECK-NEXT: 200a4: 08 00 80 20 j 131200 # CHECK-NEXT: 200a8: 27 39 00 80 addiu $25, $25, 128 +# Make sure tha thunks are created properly no matter how +# objects are laid out. +# +# RUN: ld.lld %t-pic.o %t-npic.o %p/Inputs/mips-sto-pic.o -o %t.exe +# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s + +# REVERSE: foo1a: +# REVERSE-NEXT: 20000: 00 00 00 00 nop +# +# REVERSE: foo1b: +# REVERSE-NEXT: 20004: 00 00 00 00 nop +# REVERSE-NEXT: 20008: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 2000c: 08 00 80 00 j 131072 +# REVERSE-NEXT: 20010: 27 39 00 00 addiu $25, $25, 0 +# REVERSE-NEXT: 20014: 00 00 00 00 nop +# REVERSE-NEXT: 20018: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 2001c: 08 00 80 01 j 131076 +# REVERSE-NEXT: 20020: 27 39 00 04 addiu $25, $25, 4 +# REVERSE-NEXT: 20024: 00 00 00 00 nop +# REVERSE-NEXT: 20028: 00 00 00 00 nop +# REVERSE-NEXT: 2002c: 00 00 00 00 nop +# +# REVERSE: foo2: +# REVERSE-NEXT: 20030: 00 00 00 00 nop +# REVERSE-NEXT: 20034: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 20038: 08 00 80 0c j 131120 +# REVERSE-NEXT: 2003c: 27 39 00 30 addiu $25, $25, 48 +# REVERSE-NEXT: 20040: 00 00 00 00 nop +# REVERSE-NEXT: 20044: 00 00 00 00 nop +# REVERSE-NEXT: 20048: 00 00 00 00 nop +# REVERSE-NEXT: 2004c: 00 00 00 00 nop +# +# REVERSE: __start: +# REVERSE-NEXT: 20050: 0c 00 80 02 jal 131080 +# REVERSE-NEXT: 20054: 00 00 00 00 nop +# REVERSE-NEXT: 20058: 0c 00 80 0d jal 131124 +# REVERSE-NEXT: 2005c: 00 00 00 00 nop +# REVERSE-NEXT: 20060: 0c 00 80 06 jal 131096 +# REVERSE-NEXT: 20064: 00 00 00 00 nop +# REVERSE-NEXT: 20068: 0c 00 80 0d jal 131124 +# REVERSE-NEXT: 2006c: 00 00 00 00 nop +# REVERSE-NEXT: 20070: 0c 00 80 28 jal 131232 +# REVERSE-NEXT: 20074: 00 00 00 00 nop +# REVERSE-NEXT: 20078: 0c 00 80 24 jal 131216 +# REVERSE-NEXT: 2007c: 00 00 00 00 nop +# +# REVERSE: fpic: +# REVERSE-NEXT: 20080: 00 00 00 00 nop +# REVERSE-NEXT: 20084: 00 00 00 00 nop +# REVERSE-NEXT: 20088: 00 00 00 00 nop +# REVERSE-NEXT: 2008c: 00 00 00 00 nop +# +# REVERSE: fnpic: +# REVERSE-NEXT: 20090: 00 00 00 00 nop +# REVERSE-NEXT: 20094: 00 00 00 00 nop +# REVERSE-NEXT: 20098: 00 00 00 00 nop +# REVERSE-NEXT: 2009c: 00 00 00 00 nop +# REVERSE-NEXT: 200a0: 3c 19 00 02 lui $25, 2 +# REVERSE-NEXT: 200a4: 08 00 80 20 j 131200 +# REVERSE-NEXT: 200a8: 27 39 00 80 addiu $25, $25, 128 +# REVERSE-NEXT: 200ac: 00 00 00 00 nop + .text .globl __start __start: