diff options
Diffstat (limited to 'contrib/llvm/tools/lld/ELF/InputSection.cpp')
-rw-r--r-- | contrib/llvm/tools/lld/ELF/InputSection.cpp | 809 |
1 files changed, 518 insertions, 291 deletions
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp index e6e86d5..c6a539b 100644 --- a/contrib/llvm/tools/lld/ELF/InputSection.cpp +++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp @@ -20,8 +20,11 @@ #include "Target.h" #include "Thunks.h" #include "llvm/Object/Decompressor.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h" #include <mutex> using namespace llvm; @@ -29,17 +32,16 @@ using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; +using namespace llvm::sys; using namespace lld; using namespace lld::elf; +std::vector<InputSectionBase *> elf::InputSections; + // Returns a string to construct an error message. -template <class ELFT> -std::string lld::toString(const InputSectionBase<ELFT> *Sec) { - // File can be absent if section is synthetic. - std::string FileName = - Sec->getFile() ? Sec->getFile()->getName() : "<internal>"; - return (FileName + ":(" + Sec->Name + ")").str(); +std::string lld::toString(const InputSectionBase *Sec) { + return (toString(Sec->File) + ":(" + Sec->Name + ")").str(); } template <class ELFT> @@ -50,91 +52,131 @@ static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File, return check(File->getObj().getSectionContents(Hdr)); } -template <class ELFT> -InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File, - uintX_t Flags, uint32_t Type, - uintX_t Entsize, uint32_t Link, - uint32_t Info, uintX_t Addralign, - ArrayRef<uint8_t> Data, StringRef Name, - Kind SectionKind) - : InputSectionData(SectionKind, Name, Data, - !Config->GcSections || !(Flags & SHF_ALLOC)), - File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), - Info(Info), Repl(this) { +InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, + uint32_t Type, uint64_t Entsize, + uint32_t Link, uint32_t Info, + uint32_t Alignment, ArrayRef<uint8_t> Data, + StringRef Name, Kind SectionKind) + : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, + Link), + File(File), Data(Data), Repl(this) { + Live = !Config->GcSections || !(Flags & SHF_ALLOC); + Assigned = false; NumRelocations = 0; AreRelocsRela = false; // The ELF spec states that a value of 0 means the section has // no alignment constraits. - uint64_t V = std::max<uint64_t>(Addralign, 1); + uint32_t V = std::max<uint64_t>(Alignment, 1); if (!isPowerOf2_64(V)) fatal(toString(File) + ": section sh_addralign is not a power of 2"); + this->Alignment = V; +} + +// Drop SHF_GROUP bit unless we are producing a re-linkable object file. +// SHF_GROUP is a marker that a section belongs to some comdat group. +// That flag doesn't make sense in an executable. +static uint64_t getFlags(uint64_t Flags) { + Flags &= ~(uint64_t)SHF_INFO_LINK; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + return Flags; +} +// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of +// March 2017) fail to infer section types for sections starting with +// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of +// SHF_INIT_ARRAY. As a result, the following assembler directive +// creates ".init_array.100" with SHT_PROGBITS, for example. +// +// .section .init_array.100, "aw" +// +// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle +// incorrect inputs as if they were correct from the beginning. +static uint64_t getType(uint64_t Type, StringRef Name) { + if (Type == SHT_PROGBITS && Name.startswith(".init_array.")) + return SHT_INIT_ARRAY; + if (Type == SHT_PROGBITS && Name.startswith(".fini_array.")) + return SHT_FINI_ARRAY; + return Type; +} + +template <class ELFT> +InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File, + const typename ELFT::Shdr *Hdr, + StringRef Name, Kind SectionKind) + : InputSectionBase(File, getFlags(Hdr->sh_flags), + getType(Hdr->sh_type, Name), Hdr->sh_entsize, + Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, + getSectionContents(File, Hdr), Name, SectionKind) { // We reject object files having insanely large alignments even though // they are allowed by the spec. I think 4GB is a reasonable limitation. // We might want to relax this in the future. - if (V > UINT32_MAX) + if (Hdr->sh_addralign > UINT32_MAX) fatal(toString(File) + ": section sh_addralign is too large"); - Alignment = V; - - // If it is not a mergeable section, overwrite the flag so that the flag - // is consistent with the class. This inconsistency could occur when - // string merging is disabled using -O0 flag. - if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this)) - this->Flags &= ~(SHF_MERGE | SHF_STRINGS); } -template <class ELFT> -InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File, - const Elf_Shdr *Hdr, StringRef Name, - Kind SectionKind) - : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, Hdr->sh_type, - Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info, - Hdr->sh_addralign, getSectionContents(File, Hdr), Name, - SectionKind) { - this->Offset = Hdr->sh_offset; -} - -template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const { - if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) +size_t InputSectionBase::getSize() const { + if (auto *S = dyn_cast<SyntheticSection>(this)) return S->getSize(); - if (auto *D = dyn_cast<InputSection<ELFT>>(this)) - if (D->getThunksSize() > 0) - return D->getThunkOff() + D->getThunksSize(); - return Data.size(); } -template <class ELFT> -typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { +uint64_t InputSectionBase::getOffsetInFile() const { + const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart(); + const uint8_t *SecStart = Data.begin(); + return SecStart - FileStart; +} + +uint64_t SectionBase::getOffset(uint64_t Offset) const { switch (kind()) { + case Output: { + auto *OS = cast<OutputSection>(this); + // For output sections we treat offset -1 as the end of the section. + return Offset == uint64_t(-1) ? OS->Size : Offset; + } case Regular: - return cast<InputSection<ELFT>>(this)->OutSecOff + Offset; - case Synthetic: + return cast<InputSection>(this)->OutSecOff + Offset; + case Synthetic: { + auto *IS = cast<InputSection>(this); // For synthetic sections we treat offset -1 as the end of the section. - // The same approach is used for synthetic symbols (DefinedSynthetic). - return cast<InputSection<ELFT>>(this)->OutSecOff + - (Offset == uintX_t(-1) ? getSize() : Offset); + return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset); + } case EHFrame: // 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. return Offset; case Merge: - return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset); + const MergeInputSection *MS = cast<MergeInputSection>(this); + if (InputSection *IS = MS->getParent()) + return IS->OutSecOff + MS->getOffset(Offset); + return MS->getOffset(Offset); } llvm_unreachable("invalid section kind"); } +OutputSection *SectionBase::getOutputSection() { + InputSection *Sec; + if (auto *IS = dyn_cast<InputSection>(this)) + Sec = IS; + else if (auto *MS = dyn_cast<MergeInputSection>(this)) + Sec = MS->getParent(); + else if (auto *EH = dyn_cast<EhInputSection>(this)) + Sec = EH->getParent(); + else + return cast<OutputSection>(this); + return Sec ? Sec->getParent() : nullptr; +} + // Uncompress section contents. Note that this function is called // from parallel_for_each, so it must be thread-safe. -template <class ELFT> void InputSectionBase<ELFT>::uncompress() { - Decompressor Decompressor = check(Decompressor::create( - Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little, - ELFT::Is64Bits)); +void InputSectionBase::uncompress() { + Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data), + Config->IsLE, Config->Is64)); - size_t Size = Decompressor.getDecompressedSize(); + size_t Size = Dec.getDecompressedSize(); char *OutputBuf; { static std::mutex Mu; @@ -142,41 +184,51 @@ template <class ELFT> void InputSectionBase<ELFT>::uncompress() { OutputBuf = BAlloc.Allocate<char>(Size); } - if (Error E = Decompressor.decompress({OutputBuf, Size})) - fatal(E, toString(this)); - Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); + if (Error E = Dec.decompress({OutputBuf, Size})) + fatal(toString(this) + + ": decompress failed: " + llvm::toString(std::move(E))); + this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); + this->Flags &= ~(uint64_t)SHF_COMPRESSED; } -template <class ELFT> -typename ELFT::uint -InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const { +uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { return getOffset(Sym.Value); } -template <class ELFT> -InputSectionBase<ELFT> *InputSectionBase<ELFT>::getLinkOrderDep() const { - if ((Flags & SHF_LINK_ORDER) && Link != 0) - return getFile()->getSections()[Link]; +InputSection *InputSectionBase::getLinkOrderDep() const { + if ((Flags & SHF_LINK_ORDER) && Link != 0) { + InputSectionBase *L = File->getSections()[Link]; + if (auto *IS = dyn_cast<InputSection>(L)) + return IS; + error( + "Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " + + toString(L)); + } return nullptr; } // Returns a source location string. Used to construct an error message. template <class ELFT> -std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) { +std::string InputSectionBase::getLocation(uint64_t Offset) { + // We don't have file for synthetic sections. + if (getFile<ELFT>() == nullptr) + return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")") + .str(); + // First check if we can get desired values from debugging information. - std::string LineInfo = File->getLineInfo(this, Offset); + std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset); if (!LineInfo.empty()) return LineInfo; // File->SourceFile contains STT_FILE symbol that contains a // source file name. If it's missing, we use an object file name. - std::string SrcFile = File->SourceFile; + std::string SrcFile = getFile<ELFT>()->SourceFile; if (SrcFile.empty()) SrcFile = toString(File); // Find a function symbol that encloses a given location. - for (SymbolBody *B : File->getSymbols()) - if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B)) + for (SymbolBody *B : getFile<ELFT>()->getSymbols()) + if (auto *D = dyn_cast<DefinedRegular>(B)) if (D->Section == this && D->Type == STT_FUNC) if (D->Value <= Offset && Offset < D->Value + D->Size) return SrcFile + ":(function " + toString(*D) + ")"; @@ -185,75 +237,180 @@ std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) { return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); } -template <class ELFT> -InputSection<ELFT>::InputSection() : InputSectionBase<ELFT>() {} - -template <class ELFT> -InputSection<ELFT>::InputSection(uintX_t Flags, uint32_t Type, - uintX_t Addralign, ArrayRef<uint8_t> Data, - StringRef Name, Kind K) - : InputSectionBase<ELFT>(nullptr, Flags, Type, - /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Addralign, - Data, Name, K) {} +// Returns a source location string. This function is intended to be +// used for constructing an error message. The returned message looks +// like this: +// +// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) +// +// Returns an empty string if there's no way to get line info. +template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) { + // Synthetic sections don't have input files. + elf::ObjectFile<ELFT> *File = getFile<ELFT>(); + if (!File) + return ""; + + Optional<DILineInfo> Info = File->getDILineInfo(this, Offset); + + // File->SourceFile contains STT_FILE symbol, and that is a last resort. + if (!Info) + return File->SourceFile; + + std::string Path = Info->FileName; + std::string Filename = path::filename(Path); + std::string Lineno = ":" + std::to_string(Info->Line); + if (Filename == Path) + return Filename + Lineno; + return Filename + Lineno + " (" + Path + Lineno + ")"; +} -template <class ELFT> -InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F, - const Elf_Shdr *Header, StringRef Name) - : InputSectionBase<ELFT>(F, Header, Name, Base::Regular) {} +// Returns a filename string along with an optional section name. This +// function is intended to be used for constructing an error +// message. The returned message looks like this: +// +// path/to/foo.o:(function bar) +// +// or +// +// path/to/foo.o:(function bar) in archive path/to/bar.a +template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) { + // Synthetic sections don't have input files. + elf::ObjectFile<ELFT> *File = getFile<ELFT>(); + if (!File) + return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str(); + std::string Filename = File->getName(); + + std::string Archive; + if (!File->ArchiveName.empty()) + Archive = (" in archive " + File->ArchiveName).str(); + + // Find a symbol that encloses a given location. + for (SymbolBody *B : getFile<ELFT>()->getSymbols()) + if (auto *D = dyn_cast<DefinedRegular>(B)) + if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size) + return Filename + ":(" + toString(*D) + ")" + Archive; -template <class ELFT> -bool InputSection<ELFT>::classof(const InputSectionData *S) { - return S->kind() == Base::Regular || S->kind() == Base::Synthetic; + // If there's no symbol, print out the offset in the section. + return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive) + .str(); } +InputSectionBase InputSectionBase::Discarded; + +InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, + ArrayRef<uint8_t> Data, StringRef Name, Kind K) + : InputSectionBase(nullptr, Flags, Type, + /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data, + Name, K) {} + template <class ELFT> -InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() { - assert(this->Type == SHT_RELA || this->Type == SHT_REL); - ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections(); - return Sections[this->Info]; +InputSection::InputSection(elf::ObjectFile<ELFT> *F, + const typename ELFT::Shdr *Header, StringRef Name) + : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} + +bool InputSection::classof(const SectionBase *S) { + return S->kind() == SectionBase::Regular || + S->kind() == SectionBase::Synthetic; } -template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) { - Thunks.push_back(T); +bool InputSectionBase::classof(const SectionBase *S) { + return S->kind() != Output; } -template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const { - return this->Data.size(); +OutputSection *InputSection::getParent() const { + return cast_or_null<OutputSection>(Parent); } -template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const { - uint64_t Total = 0; - for (const Thunk<ELFT> *T : Thunks) - Total += T->size(); - return Total; +// Copy SHT_GROUP section contents. Used only for the -r option. +template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) { + // ELFT::Word is the 32-bit integral type in the target endianness. + typedef typename ELFT::Word u32; + ArrayRef<u32> From = getDataAs<u32>(); + auto *To = reinterpret_cast<u32 *>(Buf); + + // The first entry is not a section number but a flag. + *To++ = From[0]; + + // Adjust section numbers because section numbers in an input object + // files are different in the output. + ArrayRef<InputSectionBase *> Sections = this->File->getSections(); + for (uint32_t Idx : From.slice(1)) + *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } -// This is used for -r. We can't use memcpy to copy relocations because we need -// to update symbol table offset and section index for each relocation. So we -// copy relocations one by one. -template <class ELFT> -template <class RelTy> -void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { - InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection(); +InputSectionBase *InputSection::getRelocatedSection() { + assert(this->Type == SHT_RELA || this->Type == SHT_REL); + ArrayRef<InputSectionBase *> Sections = this->File->getSections(); + return Sections[this->Info]; +} +// This is used for -r and --emit-relocs. We can't use memcpy to copy +// relocations because we need to update symbol table offset and section index +// for each relocation. So we copy relocations one by one. +template <class ELFT, class RelTy> +void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { + InputSectionBase *RelocatedSection = getRelocatedSection(); + + // Loop is slow and have complexity O(N*M), where N - amount of + // relocations and M - amount of symbols in symbol table. + // That happens because getSymbolIndex(...) call below performs + // simple linear search. for (const RelTy &Rel : Rels) { - uint32_t Type = Rel.getType(Config->Mips64EL); - SymbolBody &Body = this->File->getRelocTargetSym(Rel); + uint32_t Type = Rel.getType(Config->IsMips64EL); + SymbolBody &Body = this->getFile<ELFT>()->getRelocTargetSym(Rel); - Elf_Rela *P = reinterpret_cast<Elf_Rela *>(Buf); + auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); - if (Config->Rela) + if (Config->IsRela) P->r_addend = getAddend<ELFT>(Rel); - P->r_offset = RelocatedSection->getOffset(Rel.r_offset); - P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type, - Config->Mips64EL); + + // Output section VA is zero for -r, so r_offset is an offset within the + // section, but for --emit-relocs it is an virtual address. + P->r_offset = RelocatedSection->getOutputSection()->Addr + + RelocatedSection->getOffset(Rel.r_offset); + P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type, + Config->IsMips64EL); + + if (Body.Type == STT_SECTION) { + // We combine multiple section symbols into only one per + // section. This means we have to update the addend. That is + // trivial for Elf_Rela, but for Elf_Rel we have to write to the + // section data. We do that by adding to the Relocation vector. + + // .eh_frame is horribly special and can reference discarded sections. To + // avoid having to parse and recreate .eh_frame, we just replace any + // relocation in it pointing to discarded sections with R_*_NONE, which + // hopefully creates a frame that is ignored at runtime. + SectionBase *Section = cast<DefinedRegular>(Body).Section; + if (Section == &InputSection::Discarded) { + P->setSymbolAndType(0, 0, false); + continue; + } + + if (Config->IsRela) { + P->r_addend += Body.getVA() - Section->getOutputSection()->Addr; + } else if (Config->Relocatable) { + const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset; + RelocatedSection->Relocations.push_back( + {R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type), + &Body}); + } + } + } } +// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak +// references specially. The general rule is that the value of the symbol in +// this context is the address of the place P. A further special case is that +// branch relocations to an undefined weak reference resolve to the next +// instruction. static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, uint32_t P) { switch (Type) { + // Unresolved branch relocations to weak references resolve to next + // instruction, this will be either 2 or 4 bytes on from P. case R_ARM_THM_JUMP11: return P + 2 + A; case R_ARM_CALL: @@ -267,89 +424,128 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, case R_ARM_THM_CALL: // We don't want an interworking BLX to ARM return P + 5 + A; - default: + // Unresolved non branch pc-relative relocations + // R_ARM_TARGET2 which can be resolved relatively is not present as it never + // targets a weak-reference. + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_REL32: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: return P + A; } + llvm_unreachable("ARM pc-relative relocation expected\n"); } +// The comment above getARMUndefinedRelativeWeakVA applies to this function. static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, uint64_t P) { switch (Type) { + // Unresolved branch relocations to weak references resolve to next + // instruction, this is 4 bytes on from P. case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return P + 4 + A; - default: + // Unresolved non branch pc-relative relocations + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + case R_AARCH64_ADR_PREL_LO21: return P + A; } + llvm_unreachable("AArch64 pc-relative relocation expected\n"); } -template <class ELFT> -static typename ELFT::uint -getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, - const SymbolBody &Body, RelExpr Expr) { +// ARM SBREL relocations are of the form S + A - B where B is the static base +// The ARM ABI defines base to be "addressing origin of the output segment +// defining the symbol S". We defined the "addressing origin"/static base to be +// the base of the PT_LOAD segment containing the Body. +// The procedure call standard only defines a Read Write Position Independent +// RWPI variant so in practice we should expect the static base to be the base +// of the RW segment. +static uint64_t getARMStaticBase(const SymbolBody &Body) { + OutputSection *OS = Body.getOutputSection(); + if (!OS || !OS->FirstInPtLoad) + fatal("SBREL relocation to " + Body.getName() + " without static base"); + return OS->FirstInPtLoad->Addr; +} + +static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, + const SymbolBody &Body, RelExpr Expr) { switch (Expr) { case R_ABS: case R_RELAX_GOT_PC_NOPIC: - return Body.getVA<ELFT>(A); + return Body.getVA(A); + case R_ARM_SBREL: + return Body.getVA(A) - getARMStaticBase(Body); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: - return Body.getGotVA<ELFT>() + A; + return Body.getGotVA() + A; case R_GOTONLY_PC: - return In<ELFT>::Got->getVA() + A - P; + return InX::Got->getVA() + A - P; case R_GOTONLY_PC_FROM_END: - return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize(); + return InX::Got->getVA() + A - P + InX::Got->getSize(); case R_GOTREL: - return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA(); + return Body.getVA(A) - InX::Got->getVA(); case R_GOTREL_FROM_END: - return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() - - In<ELFT>::Got->getSize(); + return Body.getVA(A) - InX::Got->getVA() - InX::Got->getSize(); case R_GOT_FROM_END: case R_RELAX_TLS_GD_TO_IE_END: - return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize(); + return Body.getGotOffset() + A - InX::Got->getSize(); case R_GOT_OFF: - return Body.getGotOffset<ELFT>() + A; + return Body.getGotOffset() + A; case R_GOT_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: - return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P); + return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P); case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: - return Body.getGotVA<ELFT>() + A - P; + return Body.getGotVA() + A - P; case R_HINT: + case R_NONE: case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: - return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp(); + return Body.getVA(A) - InX::MipsGot->getGp(); + case R_MIPS_GOT_GP: + return InX::MipsGot->getGp() + A; + case R_MIPS_GOT_GP_PC: { + // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target + // is _gp_disp symbol. In that case we should use the following + // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + uint64_t V = InX::MipsGot->getGp() + A - P; + if (Type == R_MIPS_LO16) + V += 4; + return V; + } case R_MIPS_GOT_LOCAL_PAGE: // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return In<ELFT>::MipsGot->getVA() + - In<ELFT>::MipsGot->getPageEntryOffset(Body, A) - - In<ELFT>::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Body, A) - + InX::MipsGot->getGp(); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return In<ELFT>::MipsGot->getVA() + - In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) - - In<ELFT>::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getBodyEntryOffset(Body, A) - + InX::MipsGot->getGp(); case R_MIPS_TLSGD: - return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() + - In<ELFT>::MipsGot->getGlobalDynOffset(Body) - - In<ELFT>::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + + InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp(); case R_MIPS_TLSLD: - return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() + - In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + + InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp(); case R_PAGE_PC: case R_PLT_PAGE_PC: { uint64_t Dest; if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) Dest = getAArch64Page(A); else - Dest = getAArch64Page(Body.getVA<ELFT>(A)); + Dest = getAArch64Page(Body.getVA(A)); return Dest - getAArch64Page(P); } case R_PC: { @@ -362,39 +558,39 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, else if (Config->EMachine == EM_AARCH64) Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P); else - Dest = Body.getVA<ELFT>(A); + Dest = Body.getVA(A); } else { - Dest = Body.getVA<ELFT>(A); + Dest = Body.getVA(A); } return Dest - P; } case R_PLT: - return Body.getPltVA<ELFT>() + A; + return Body.getPltVA() + A; case R_PLT_PC: case R_PPC_PLT_OPD: - return Body.getPltVA<ELFT>() + A - P; + return Body.getPltVA() + A - P; case R_PPC_OPD: { - uint64_t SymVA = Body.getVA<ELFT>(A); + uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. if (!SymVA) return 0; - if (Out<ELF64BE>::Opd) { + if (Out::Opd) { // If this is a local call, and we currently have the address of a // function-descriptor, get the underlying code address instead. - uint64_t OpdStart = Out<ELF64BE>::Opd->Addr; - uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->Size; + uint64_t OpdStart = Out::Opd->Addr; + uint64_t OpdEnd = OpdStart + Out::Opd->Size; bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd; if (InOpd) - SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]); + SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]); } return SymVA - P; } case R_PPC_TOC: return getPPC64TocBase() + A; case R_RELAX_GOT_PC: - return Body.getVA<ELFT>(A) - P; + return Body.getVA(A) - P; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_TO_LE: @@ -408,33 +604,26 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, Body.symbol()->isWeak()) return 0; if (Target->TcbSize) - return Body.getVA<ELFT>(A) + - alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align); - return Body.getVA<ELFT>(A) - Out<ELFT>::TlsPhdr->p_memsz; + return Body.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align); + return Body.getVA(A) - Out::TlsPhdr->p_memsz; case R_RELAX_TLS_GD_TO_LE_NEG: case R_NEG_TLS: - return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A); + return Out::TlsPhdr->p_memsz - Body.getVA(A); case R_SIZE: - return Body.getSize<ELFT>() + A; - case R_THUNK_ABS: - return Body.getThunkVA<ELFT>() + A; - case R_THUNK_PC: - case R_THUNK_PLT_PC: - return Body.getThunkVA<ELFT>() + A - P; + return A; // Body.getSize was already folded into the addend. case R_TLSDESC: - return In<ELFT>::Got->getGlobalDynAddr(Body) + A; + return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: - return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) - + return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) - getAArch64Page(P); case R_TLSGD: - return In<ELFT>::Got->getGlobalDynOffset(Body) + A - - In<ELFT>::Got->getSize(); + return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize(); case R_TLSGD_PC: - return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P; + return InX::Got->getGlobalDynAddr(Body) + A - P; case R_TLSLD: - return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize(); + return InX::Got->getTlsIndexOff() + A - InX::Got->getSize(); case R_TLSLD_PC: - return In<ELFT>::Got->getTlsIndexVA() + A - P; + return InX::Got->getTlsIndexVA() + A - P; } llvm_unreachable("Invalid expression"); } @@ -446,57 +635,71 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, // treatement such as GOT or PLT (because at runtime no one refers them). // So, we handle relocations for non-alloc sections directly in this // function as a performance optimization. -template <class ELFT> -template <class RelTy> -void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { +template <class ELFT, class RelTy> +void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { for (const RelTy &Rel : Rels) { - uint32_t Type = Rel.getType(Config->Mips64EL); - uintX_t Offset = this->getOffset(Rel.r_offset); + uint32_t Type = Rel.getType(Config->IsMips64EL); + uint64_t Offset = getOffset(Rel.r_offset); uint8_t *BufLoc = Buf + Offset; - uintX_t Addend = getAddend<ELFT>(Rel); + int64_t Addend = getAddend<ELFT>(Rel); if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); - SymbolBody &Sym = this->File->getRelocTargetSym(Rel); - if (Target->getRelExpr(Type, Sym) != R_ABS) { - error(this->getLocation(Offset) + ": has non-ABS reloc"); + SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); + RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); + if (Expr == R_NONE) + continue; + if (Expr != R_ABS) { + error(this->getLocation<ELFT>(Offset) + ": has non-ABS reloc"); return; } - uintX_t AddrLoc = this->OutSec->Addr + Offset; + uint64_t AddrLoc = getParent()->Addr + Offset; uint64_t SymVA = 0; - if (!Sym.isTls() || Out<ELFT>::TlsPhdr) - SymVA = SignExtend64<sizeof(uintX_t) * 8>( - getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS)); + if (!Sym.isTls() || Out::TlsPhdr) + SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>( + getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } +template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const { + return cast_or_null<elf::ObjectFile<ELFT>>(File); +} + template <class ELFT> -void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) { +void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + if (Flags & SHF_ALLOC) + relocateAlloc(Buf, BufEnd); + else + relocateNonAlloc<ELFT>(Buf, BufEnd); +} + +template <class ELFT> +void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) { // scanReloc function in Writer.cpp constructs Relocations // vector only for SHF_ALLOC'ed sections. For other sections, // we handle relocations directly here. - auto *IS = dyn_cast<InputSection<ELFT>>(this); - if (IS && !(IS->Flags & SHF_ALLOC)) { - if (IS->AreRelocsRela) - IS->relocateNonAlloc(Buf, IS->relas()); - else - IS->relocateNonAlloc(Buf, IS->rels()); - return; - } + auto *IS = cast<InputSection>(this); + assert(!(IS->Flags & SHF_ALLOC)); + if (IS->AreRelocsRela) + IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>()); + else + IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>()); +} - const unsigned Bits = sizeof(uintX_t) * 8; +void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { + assert(Flags & SHF_ALLOC); + const unsigned Bits = Config->Wordsize * 8; for (const Relocation &Rel : Relocations) { - uintX_t Offset = getOffset(Rel.Offset); + uint64_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; uint32_t Type = Rel.Type; - uintX_t A = Rel.Addend; - uintX_t AddrLoc = OutSec->Addr + Offset; + uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; - uint64_t TargetVA = SignExtend64<Bits>( - getRelocTargetVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr)); + uint64_t TargetVA = SignExtend64( + getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); switch (Expr) { case R_RELAX_GOT_PC: @@ -523,7 +726,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) { // Patch a nop (0x60000000) to a ld. if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) - // fallthrough + LLVM_FALLTHROUGH; default: Target->relocateOne(BufLoc, Type, TargetVA); break; @@ -531,67 +734,64 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) { } } -template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) { +template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { if (this->Type == SHT_NOBITS) return; - if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) { + if (auto *S = dyn_cast<SyntheticSection>(this)) { S->writeTo(Buf + OutSecOff); return; } - // If -r is given, then an InputSection may be a relocation section. + // If -r or --emit-relocs is given, then an InputSection + // may be a relocation section. if (this->Type == SHT_RELA) { - copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>()); + copyRelocations<ELFT>(Buf + OutSecOff, + this->template getDataAs<typename ELFT::Rela>()); return; } if (this->Type == SHT_REL) { - copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rel>()); + copyRelocations<ELFT>(Buf + OutSecOff, + this->template getDataAs<typename ELFT::Rel>()); return; } - // Copy section contents from source object file to output file. - ArrayRef<uint8_t> Data = this->Data; - memcpy(Buf + OutSecOff, Data.data(), Data.size()); + // If -r is given, we may have a SHT_GROUP section. + if (this->Type == SHT_GROUP) { + copyShtGroup<ELFT>(Buf + OutSecOff); + return; + } - // Iterate over all relocation sections that apply to this section. + // Copy section contents from source object file to output file + // and then apply relocations. + memcpy(Buf + OutSecOff, Data.data(), Data.size()); uint8_t *BufEnd = Buf + OutSecOff + Data.size(); - this->relocate(Buf, BufEnd); - - // The section might have a data/code generated by the linker and need - // to be written after the section. Usually these are thunks - small piece - // of code used to jump between "incompatible" functions like PIC and non-PIC - // or if the jump target too far and its address does not fit to the short - // jump istruction. - if (!Thunks.empty()) { - Buf += OutSecOff + getThunkOff(); - for (const Thunk<ELFT> *T : Thunks) { - T->writeTo(Buf); - Buf += T->size(); - } - } + this->relocate<ELFT>(Buf, BufEnd); } -template <class ELFT> -void InputSection<ELFT>::replace(InputSection<ELFT> *Other) { +void InputSection::replace(InputSection *Other) { this->Alignment = std::max(this->Alignment, Other->Alignment); Other->Repl = this->Repl; Other->Live = false; } template <class ELFT> -EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F, - const Elf_Shdr *Header, StringRef Name) - : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::EHFrame) { +EhInputSection::EhInputSection(elf::ObjectFile<ELFT> *F, + const typename ELFT::Shdr *Header, + StringRef Name) + : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) { // Mark .eh_frame sections as live by default because there are // usually no relocations that point to .eh_frames. Otherwise, // the garbage collector would drop all .eh_frame sections. this->Live = true; } -template <class ELFT> -bool EhInputSection<ELFT>::classof(const InputSectionData *S) { - return S->kind() == InputSectionBase<ELFT>::EHFrame; +SyntheticSection *EhInputSection::getParent() const { + return cast_or_null<SyntheticSection>(Parent); +} + +bool EhInputSection::classof(const SectionBase *S) { + return S->kind() == InputSectionBase::EHFrame; } // Returns the index of the first relocation that points to a region between @@ -615,24 +815,23 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels, // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. -template <class ELFT> void EhInputSection<ELFT>::split() { +template <class ELFT> void EhInputSection::split() { // Early exit if already split. if (!this->Pieces.empty()) return; if (this->NumRelocations) { if (this->AreRelocsRela) - split(this->relas()); + split<ELFT>(this->relas<ELFT>()); else - split(this->rels()); + split<ELFT>(this->rels<ELFT>()); return; } - split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr)); + split<ELFT>(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr)); } -template <class ELFT> -template <class RelTy> -void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) { +template <class ELFT, class RelTy> +void EhInputSection::split(ArrayRef<RelTy> Rels) { ArrayRef<uint8_t> Data = this->Data; unsigned RelI = 0; for (size_t Off = 0, End = Data.size(); Off != End;) { @@ -659,11 +858,13 @@ static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) { return StringRef::npos; } +SyntheticSection *MergeInputSection::getParent() const { + return cast_or_null<SyntheticSection>(Parent); +} + // Split SHF_STRINGS section. Such section is a sequence of // null-terminated strings. -template <class ELFT> -void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data, - size_t EntSize) { +void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) { size_t Off = 0; bool IsAlloc = this->Flags & SHF_ALLOC; while (!Data.empty()) { @@ -680,9 +881,8 @@ void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data, // Split non-SHF_STRINGS section. Such section is a sequence of // fixed size records. -template <class ELFT> -void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data, - size_t EntSize) { +void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, + size_t EntSize) { size_t Size = Data.size(); assert((Size % EntSize) == 0); bool IsAlloc = this->Flags & SHF_ALLOC; @@ -693,10 +893,10 @@ void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data, } template <class ELFT> -MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F, - const Elf_Shdr *Header, - StringRef Name) - : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::Merge) {} +MergeInputSection::MergeInputSection(elf::ObjectFile<ELFT> *F, + const typename ELFT::Shdr *Header, + StringRef Name) + : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} // This function is called after we obtain a complete list of input sections // that need to be linked. This is responsible to split section contents @@ -704,28 +904,26 @@ MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F, // // Note that this function is called from parallel_for_each. This must be // thread-safe (i.e. no memory allocation from the pools). -template <class ELFT> void MergeInputSection<ELFT>::splitIntoPieces() { +void MergeInputSection::splitIntoPieces() { ArrayRef<uint8_t> Data = this->Data; - uintX_t EntSize = this->Entsize; + uint64_t EntSize = this->Entsize; if (this->Flags & SHF_STRINGS) splitStrings(Data, EntSize); else splitNonStrings(Data, EntSize); if (Config->GcSections && (this->Flags & SHF_ALLOC)) - for (uintX_t Off : LiveOffsets) + for (uint64_t Off : LiveOffsets) this->getSectionPiece(Off)->Live = true; } -template <class ELFT> -bool MergeInputSection<ELFT>::classof(const InputSectionData *S) { - return S->kind() == InputSectionBase<ELFT>::Merge; +bool MergeInputSection::classof(const SectionBase *S) { + return S->kind() == InputSectionBase::Merge; } // Do binary search to get a section piece at a given input offset. -template <class ELFT> -SectionPiece *MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) { - auto *This = static_cast<const MergeInputSection<ELFT> *>(this); +SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { + auto *This = static_cast<const MergeInputSection *>(this); return const_cast<SectionPiece *>(This->getSectionPiece(Offset)); } @@ -742,17 +940,15 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) { return Comp(Value, *First) ? First : First + 1; } -template <class ELFT> -const SectionPiece * -MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const { - uintX_t Size = this->Data.size(); +const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { + uint64_t Size = this->Data.size(); if (Offset >= Size) fatal(toString(this) + ": entry is past the end of the section"); // Find the element this offset points to. auto I = fastUpperBound( Pieces.begin(), Pieces.end(), Offset, - [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; }); + [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; }); --I; return &*I; } @@ -760,10 +956,9 @@ MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const { // Returns the offset in an output section for a given input offset. // Because contents of a mergeable section is not contiguous in output, // it is not just an addition to a base output offset. -template <class ELFT> -typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const { +uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // Initialize OffsetMap lazily. - std::call_once(InitOffsetMap, [&] { + llvm::call_once(InitOffsetMap, [&] { OffsetMap.reserve(Pieces.size()); for (const SectionPiece &Piece : Pieces) OffsetMap[Piece.InputOff] = Piece.OutputOff; @@ -783,31 +978,63 @@ typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const { if (!Piece.Live) return 0; - uintX_t Addend = Offset - Piece.InputOff; + uint64_t Addend = Offset - Piece.InputOff; return Piece.OutputOff + Addend; } -template class elf::InputSectionBase<ELF32LE>; -template class elf::InputSectionBase<ELF32BE>; -template class elf::InputSectionBase<ELF64LE>; -template class elf::InputSectionBase<ELF64BE>; - -template class elf::InputSection<ELF32LE>; -template class elf::InputSection<ELF32BE>; -template class elf::InputSection<ELF64LE>; -template class elf::InputSection<ELF64BE>; - -template class elf::EhInputSection<ELF32LE>; -template class elf::EhInputSection<ELF32BE>; -template class elf::EhInputSection<ELF64LE>; -template class elf::EhInputSection<ELF64BE>; - -template class elf::MergeInputSection<ELF32LE>; -template class elf::MergeInputSection<ELF32BE>; -template class elf::MergeInputSection<ELF64LE>; -template class elf::MergeInputSection<ELF64BE>; - -template std::string lld::toString(const InputSectionBase<ELF32LE> *); -template std::string lld::toString(const InputSectionBase<ELF32BE> *); -template std::string lld::toString(const InputSectionBase<ELF64LE> *); -template std::string lld::toString(const InputSectionBase<ELF64BE> *); +template InputSection::InputSection(elf::ObjectFile<ELF32LE> *, + const ELF32LE::Shdr *, StringRef); +template InputSection::InputSection(elf::ObjectFile<ELF32BE> *, + const ELF32BE::Shdr *, StringRef); +template InputSection::InputSection(elf::ObjectFile<ELF64LE> *, + const ELF64LE::Shdr *, StringRef); +template InputSection::InputSection(elf::ObjectFile<ELF64BE> *, + const ELF64BE::Shdr *, StringRef); + +template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t); +template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t); +template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t); +template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t); + +template std::string InputSectionBase::getSrcMsg<ELF32LE>(uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF32BE>(uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF64LE>(uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF64BE>(uint64_t); + +template std::string InputSectionBase::getObjMsg<ELF32LE>(uint64_t); +template std::string InputSectionBase::getObjMsg<ELF32BE>(uint64_t); +template std::string InputSectionBase::getObjMsg<ELF64LE>(uint64_t); +template std::string InputSectionBase::getObjMsg<ELF64BE>(uint64_t); + +template void InputSection::writeTo<ELF32LE>(uint8_t *); +template void InputSection::writeTo<ELF32BE>(uint8_t *); +template void InputSection::writeTo<ELF64LE>(uint8_t *); +template void InputSection::writeTo<ELF64BE>(uint8_t *); + +template elf::ObjectFile<ELF32LE> *InputSectionBase::getFile<ELF32LE>() const; +template elf::ObjectFile<ELF32BE> *InputSectionBase::getFile<ELF32BE>() const; +template elf::ObjectFile<ELF64LE> *InputSectionBase::getFile<ELF64LE>() const; +template elf::ObjectFile<ELF64BE> *InputSectionBase::getFile<ELF64BE>() const; + +template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32LE> *, + const ELF32LE::Shdr *, StringRef); +template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32BE> *, + const ELF32BE::Shdr *, StringRef); +template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64LE> *, + const ELF64LE::Shdr *, StringRef); +template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64BE> *, + const ELF64BE::Shdr *, StringRef); + +template EhInputSection::EhInputSection(elf::ObjectFile<ELF32LE> *, + const ELF32LE::Shdr *, StringRef); +template EhInputSection::EhInputSection(elf::ObjectFile<ELF32BE> *, + const ELF32BE::Shdr *, StringRef); +template EhInputSection::EhInputSection(elf::ObjectFile<ELF64LE> *, + const ELF64LE::Shdr *, StringRef); +template EhInputSection::EhInputSection(elf::ObjectFile<ELF64BE> *, + const ELF64BE::Shdr *, StringRef); + +template void EhInputSection::split<ELF32LE>(); +template void EhInputSection::split<ELF32BE>(); +template void EhInputSection::split<ELF64LE>(); +template void EhInputSection::split<ELF64BE>(); |