summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lld/ELF/InputSection.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2017-04-02 17:24:58 +0000
committerdim <dim@FreeBSD.org>2017-04-02 17:24:58 +0000
commit60b571e49a90d38697b3aca23020d9da42fc7d7f (patch)
tree99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/tools/lld/ELF/InputSection.cpp
parentbea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff)
downloadFreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip
FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste): Add WITH_LLD_AS_LD build knob If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not capable of linking the world and kernel, but can self-host and link many substantial applications. GNU ld continues to be used for the world and kernel build, regardless of how this knob is set. It is on by default for arm64, and off for all other CPU architectures. Sponsored by: The FreeBSD Foundation MFC r310840: Reapply 310775, now it also builds correctly if lldb is disabled: Move llvm-objdump from CLANG_EXTRAS to installed by default We currently install three tools from binutils 2.17.50: as, ld, and objdump. Work is underway to migrate to a permissively-licensed tool-chain, with one goal being the retirement of binutils 2.17.50. LLVM's llvm-objdump is intended to be compatible with GNU objdump although it is currently missing some options and may have formatting differences. Enable it by default for testing and further investigation. It may later be changed to install as /usr/bin/objdump, it becomes a fully viable replacement. Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D8879 MFC r312855 (by emaste): Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC Reported by: Dan McGregor <dan.mcgregor usask.ca> MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines Don't check struct rtentry on FreeBSD, it is an internal kernel structure. On other systems it may be API structure for SIOCADDRT/SIOCDELRT. Reviewed by: emaste, dim MFC r314152 (by jkim): Remove an assembler flag, which is redundant since r309124. The upstream took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE. http://llvm.org/viewvc/llvm-project?rev=273500&view=rev Reviewed by: dim MFC r314564: Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 (branches/release_40 296509). The release will follow soon. Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11 support to build; see UPDATING for more information. Also note that as of 4.0.0, lld should be able to link the base system on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5). Though please be aware that this is work in progress. Release notes for llvm, clang and lld will be available here: <http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html> <http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html> <http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html> Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for their help. Relnotes: yes Exp-run: antoine PR: 215969, 216008 MFC r314708: For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov): [SCEV] limit recursion depth of CompareSCEVComplexity Summary: CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled loop) and runs almost infinite time. Added cache of "equal" SCEV pairs to earlier cutoff of further estimation. Recursion depth limit was also introduced as a parameter. Reviewers: sanjoy Subscribers: mzolotukhin, tstellarAMD, llvm-commits Differential Revision: https://reviews.llvm.org/D26389 This commit is the cause of excessive compile times on skein_block.c (and possibly other files) during kernel builds on amd64. We never saw the problematic behavior described in this upstream commit, so for now it is better to revert it. An upstream bug has been filed here: https://bugs.llvm.org/show_bug.cgi?id=32142 Reported by: mjg MFC r314795: Reapply r287232 from upstream llvm trunk (by Daniil Fukalov): [SCEV] limit recursion depth of CompareSCEVComplexity Summary: CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled loop) and runs almost infinite time. Added cache of "equal" SCEV pairs to earlier cutoff of further estimation. Recursion depth limit was also introduced as a parameter. Reviewers: sanjoy Subscribers: mzolotukhin, tstellarAMD, llvm-commits Differential Revision: https://reviews.llvm.org/D26389 Pull in r296992 from upstream llvm trunk (by Sanjoy Das): [SCEV] Decrease the recursion threshold for CompareValueComplexity Fixes PR32142. r287232 accidentally increased the recursion threshold for CompareValueComplexity from 2 to 32. This change reverses that change by introducing a separate flag for CompareValueComplexity's threshold. The latter revision fixes the excessive compile times for skein_block.c. MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines Unbreak ARMv6 world. The new compiler_rt library imported with clang 4.0.0 have several fatal issues (non-functional __udivsi3 for example) with ARM specific instrict functions. As temporary workaround, until upstream solve these problems, disable all thumb[1][2] related feature. MFC r315016: Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release. We were already very close to the last release candidate, so this is a pretty minor update. Relnotes: yes MFC r316005: Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by Weiming Zhao): builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA. Summary: Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation mode (-mthumb, -marm), it reflect's capability of given CPU. Due to this: - use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB - use '.thumb' directive consistently in all affected files - decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION() --------- Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 ! Reviewers: weimingz, rengolin, compnerd Subscribers: aemerson, dim Differential Revision: https://reviews.llvm.org/D30938 Discussed with: mmel
Diffstat (limited to 'contrib/llvm/tools/lld/ELF/InputSection.cpp')
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.cpp641
1 files changed, 376 insertions, 265 deletions
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp
index 6564e79..6b1e928 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp
@@ -13,103 +13,138 @@
#include "Error.h"
#include "InputFiles.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "OutputSections.h"
+#include "Relocations.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
-
+#include "llvm/Object/Decompressor.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
+#include <mutex>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support;
using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-template <class ELFT> bool elf::isDiscarded(InputSectionBase<ELFT> *S) {
- return !S || S == &InputSection<ELFT>::Discarded || !S->Live ||
- Script<ELFT>::X->isDiscarded(S);
+// 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();
+}
+
+template <class ELFT>
+static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File,
+ const typename ELFT::Shdr *Hdr) {
+ if (!File || Hdr->sh_type == SHT_NOBITS)
+ return makeArrayRef<uint8_t>(nullptr, Hdr->sh_size);
+ return check(File->getObj().getSectionContents(Hdr));
}
template <class ELFT>
InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
- const Elf_Shdr *Header,
+ 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)
- : Header(Header), File(File), SectionKind(SectionKind), Repl(this),
- Compressed(Header->sh_flags & SHF_COMPRESSED) {
- // The garbage collector sets sections' Live bits.
- // If GC is disabled, all sections are considered live by default.
- Live = !Config->GcSections;
+ : InputSectionData(SectionKind, Name, Data,
+ !Config->GcSections || !(Flags & SHF_ALLOC)),
+ File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link),
+ Info(Info), Repl(this) {
+ NumRelocations = 0;
+ AreRelocsRela = false;
// The ELF spec states that a value of 0 means the section has
// no alignment constraits.
- Alignment = std::max<uintX_t>(Header->sh_addralign, 1);
+ uint64_t V = std::max<uint64_t>(Addralign, 1);
+ if (!isPowerOf2_64(V))
+ fatal(toString(File) + ": section sh_addralign is not a power of 2");
+
+ // 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)
+ 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))
+ return S->getSize();
+
if (auto *D = dyn_cast<InputSection<ELFT>>(this))
if (D->getThunksSize() > 0)
return D->getThunkOff() + D->getThunksSize();
- return Header->sh_size;
-}
-
-template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
- return check(File->getObj().getSectionName(this->Header));
-}
-template <class ELFT>
-ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
- if (Compressed)
- return ArrayRef<uint8_t>((const uint8_t *)Uncompressed.data(),
- Uncompressed.size());
- return check(this->File->getObj().getSectionContents(this->Header));
+ return Data.size();
}
template <class ELFT>
typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
- switch (SectionKind) {
+ switch (kind()) {
case Regular:
return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
+ case Synthetic:
+ // 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);
case EHFrame:
- return cast<EhInputSection<ELFT>>(this)->getOffset(Offset);
+ // 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);
- case MipsReginfo:
- case MipsOptions:
- // MIPS .reginfo and .MIPS.options sections are consumed by the linker,
- // and the linker produces a single output section. It is possible that
- // input files contain section symbol points to the corresponding input
- // section. Redirect it to the produced output section.
- if (Offset != 0)
- fatal("Unsupported reference to the middle of '" + getSectionName() +
- "' section");
- return this->OutSec->getVA();
}
llvm_unreachable("invalid section kind");
}
+// 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() {
- if (!zlib::isAvailable())
- fatal("build lld with zlib to enable compressed sections support");
-
- // A compressed section consists of a header of Elf_Chdr type
- // followed by compressed data.
- ArrayRef<uint8_t> Data =
- check(this->File->getObj().getSectionContents(this->Header));
- if (Data.size() < sizeof(Elf_Chdr))
- fatal("corrupt compressed section");
-
- auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data());
- Data = Data.slice(sizeof(Elf_Chdr));
-
- if (Hdr->ch_type != ELFCOMPRESS_ZLIB)
- fatal("unsupported compression type");
+ Decompressor Decompressor = check(Decompressor::create(
+ Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little,
+ ELFT::Is64Bits));
+
+ size_t Size = Decompressor.getDecompressedSize();
+ char *OutputBuf;
+ {
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Lock(Mu);
+ OutputBuf = BAlloc.Allocate<char>(Size);
+ }
- StringRef Buf((const char *)Data.data(), Data.size());
- if (zlib::uncompress(Buf, Uncompressed, Hdr->ch_size) != zlib::StatusOK)
- fatal("error uncompressing section");
+ if (Error E = Decompressor.decompress({OutputBuf, Size}))
+ fatal(E, toString(this));
+ Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
}
template <class ELFT>
@@ -119,29 +154,71 @@ InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
}
template <class ELFT>
+InputSectionBase<ELFT> *InputSectionBase<ELFT>::getLinkOrderDep() const {
+ if ((Flags & SHF_LINK_ORDER) && Link != 0)
+ return getFile()->getSections()[Link];
+ 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) {
+ // First check if we can get desired values from debugging information.
+ std::string LineInfo = File->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;
+ 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))
+ if (D->Section == this && D->Type == STT_FUNC)
+ if (D->Value <= Offset && Offset < D->Value + D->Size)
+ return SrcFile + ":(function " + toString(*D) + ")";
+
+ // If there's no symbol, print out the offset in the section.
+ 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) {}
+
+template <class ELFT>
InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header)
- : InputSectionBase<ELFT>(F, Header, Base::Regular) {}
+ const Elf_Shdr *Header, StringRef Name)
+ : InputSectionBase<ELFT>(F, Header, Name, Base::Regular) {}
template <class ELFT>
-bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == Base::Regular;
+bool InputSection<ELFT>::classof(const InputSectionData *S) {
+ return S->kind() == Base::Regular || S->kind() == Base::Synthetic;
}
template <class ELFT>
InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
- assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL);
+ assert(this->Type == SHT_RELA || this->Type == SHT_REL);
ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
- return Sections[this->Header->sh_info];
+ return Sections[this->Info];
}
-template <class ELFT>
-void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
+template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
Thunks.push_back(T);
}
template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
- return this->Header->sh_size;
+ return this->Data.size();
}
template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
@@ -163,35 +240,63 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
uint32_t Type = Rel.getType(Config->Mips64EL);
SymbolBody &Body = this->File->getRelocTargetSym(Rel);
- RelTy *P = reinterpret_cast<RelTy *>(Buf);
+ Elf_Rela *P = reinterpret_cast<Elf_Rela *>(Buf);
Buf += sizeof(RelTy);
+ if (Config->Rela)
+ P->r_addend = getAddend<ELFT>(Rel);
P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
- P->setSymbolAndType(Body.DynsymIndex, Type, Config->Mips64EL);
+ P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
+ Config->Mips64EL);
}
}
-// Page(Expr) is the page address of the expression Expr, defined
-// as (Expr & ~0xFFF). (This applies even if the machine page size
-// supported by the platform has a different value.)
-static uint64_t getAArch64Page(uint64_t Expr) {
- return Expr & (~static_cast<uint64_t>(0xFFF));
+static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
+ uint32_t P) {
+ switch (Type) {
+ case R_ARM_THM_JUMP11:
+ return P + 2;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_PREL31:
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ return P + 4;
+ case R_ARM_THM_CALL:
+ // We don't want an interworking BLX to ARM
+ return P + 5;
+ default:
+ return A;
+ }
}
-template <class ELFT>
-static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
- typename ELFT::uint P,
- const SymbolBody &Body, RelExpr Expr) {
- typedef typename ELFT::uint uintX_t;
+static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
+ uint64_t P) {
+ switch (Type) {
+ case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
+ return P + 4;
+ default:
+ return A;
+ }
+}
+template <class ELFT>
+static typename ELFT::uint
+getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
+ const SymbolBody &Body, RelExpr Expr) {
switch (Expr) {
case R_HINT:
+ case R_TLSDESC_CALL:
llvm_unreachable("cannot relocate hint relocs");
case R_TLSLD:
- return Out<ELFT>::Got->getTlsIndexOff() + A -
- Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
case R_TLSLD_PC:
- return Out<ELFT>::Got->getTlsIndexVA() + A - P;
+ return In<ELFT>::Got->getTlsIndexVA() + A - P;
case R_THUNK_ABS:
return Body.getThunkVA<ELFT>() + A;
case R_THUNK_PC:
@@ -200,14 +305,14 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
case R_PPC_TOC:
return getPPC64TocBase() + A;
case R_TLSGD:
- return Out<ELFT>::Got->getGlobalDynOffset(Body) + A -
- Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
+ In<ELFT>::Got->getSize();
case R_TLSGD_PC:
- return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
case R_TLSDESC:
- return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
case R_TLSDESC_PAGE:
- return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
getAArch64Page(P);
case R_PLT:
return Body.getPltVA<ELFT>() + A;
@@ -217,11 +322,13 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
case R_SIZE:
return Body.getSize<ELFT>() + A;
case R_GOTREL:
- return Body.getVA<ELFT>(A) - Out<ELFT>::Got->getVA();
+ return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA();
+ case R_GOTREL_FROM_END:
+ return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() -
+ In<ELFT>::Got->getSize();
case R_RELAX_TLS_GD_TO_IE_END:
case R_GOT_FROM_END:
- return Body.getGotOffset<ELFT>() + A -
- Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize();
case R_RELAX_TLS_GD_TO_IE_ABS:
case R_GOT:
return Body.getGotVA<ELFT>() + A;
@@ -232,11 +339,21 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
case R_GOT_PC:
return Body.getGotVA<ELFT>() + A - P;
case R_GOTONLY_PC:
- return Out<ELFT>::Got->getVA() + A - P;
+ return In<ELFT>::Got->getVA() + A - P;
+ case R_GOTONLY_PC_FROM_END:
+ return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
case R_RELAX_TLS_LD_TO_LE:
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_GD_TO_LE:
case R_TLS:
+ // A weak undefined TLS symbol resolves to the base of the TLS
+ // block, i.e. gets a value of zero. If we pass --gc-sections to
+ // lld and .tbss is not referenced, it gets reclaimed and we don't
+ // create a TLS program header. Therefore, we resolve this
+ // statically to zero.
+ if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) &&
+ Body.symbol()->isWeak())
+ return 0;
if (Target->TcbSize)
return Body.getVA<ELFT>(A) +
alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align);
@@ -253,18 +370,26 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
// 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 Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getPageEntryOffset(Body, A) -
+ In<ELFT>::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 Out<ELFT>::Got->getMipsGotOffset(Body, A);
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
+ In<ELFT>::MipsGot->getGp();
+ case R_MIPS_GOTREL:
+ return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSGD:
- return Out<ELFT>::Got->getGlobalDynOffset(Body) +
- Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSLD:
- return Out<ELFT>::Got->getTlsIndexOff() +
- Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
case R_PPC_OPD: {
uint64_t SymVA = Body.getVA<ELFT>(A);
// If we have an undefined weak symbol, we might get here with a symbol
@@ -275,8 +400,8 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
if (Out<ELF64BE>::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->getVA();
- uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
+ uint64_t OpdStart = Out<ELF64BE>::Opd->Addr;
+ uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->Size;
bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
if (InOpd)
SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
@@ -284,10 +409,20 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
return SymVA - P;
}
case R_PC:
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
+ // On ARM and AArch64 a branch to an undefined weak resolves to the
+ // next instruction, otherwise the place.
+ if (Config->EMachine == EM_ARM)
+ return getARMUndefinedRelativeWeakVA(Type, A, P);
+ if (Config->EMachine == EM_AARCH64)
+ return getAArch64UndefinedRelativeWeakVA(Type, A, P);
+ }
case R_RELAX_GOT_PC:
return Body.getVA<ELFT>(A) - P;
case R_PLT_PAGE_PC:
case R_PAGE_PC:
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+ return getAArch64Page(A);
return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
}
llvm_unreachable("Invalid expression");
@@ -303,7 +438,6 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
template <class ELFT>
template <class RelTy>
void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
- const unsigned Bits = sizeof(uintX_t) * 8;
for (const RelTy &Rel : Rels) {
uint32_t Type = Rel.getType(Config->Mips64EL);
uintX_t Offset = this->getOffset(Rel.r_offset);
@@ -314,13 +448,15 @@ void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
if (Target->getRelExpr(Type, Sym) != R_ABS) {
- error(this->getSectionName() + " has non-ABS reloc");
+ error(this->getLocation(Offset) + ": has non-ABS reloc");
return;
}
- uintX_t AddrLoc = this->OutSec->getVA() + Offset;
- uint64_t SymVA =
- SignExtend64<Bits>(getSymVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
+ uintX_t AddrLoc = this->OutSec->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));
Target->relocateOne(BufLoc, Type, SymVA);
}
}
@@ -331,78 +467,80 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
// 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->Header->sh_flags & SHF_ALLOC)) {
- for (const Elf_Shdr *RelSec : IS->RelocSections) {
- if (RelSec->sh_type == SHT_RELA)
- IS->relocateNonAlloc(Buf, IS->File->getObj().relas(RelSec));
- else
- IS->relocateNonAlloc(Buf, IS->File->getObj().rels(RelSec));
- }
+ if (IS && !(IS->Flags & SHF_ALLOC)) {
+ if (IS->AreRelocsRela)
+ IS->relocateNonAlloc(Buf, IS->relas());
+ else
+ IS->relocateNonAlloc(Buf, IS->rels());
return;
}
const unsigned Bits = sizeof(uintX_t) * 8;
- for (const Relocation<ELFT> &Rel : Relocations) {
- uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset);
+ for (const Relocation &Rel : Relocations) {
+ uintX_t Offset = getOffset(Rel.Offset);
uint8_t *BufLoc = Buf + Offset;
uint32_t Type = Rel.Type;
uintX_t A = Rel.Addend;
- uintX_t AddrLoc = OutSec->getVA() + Offset;
+ uintX_t AddrLoc = OutSec->Addr + Offset;
RelExpr Expr = Rel.Expr;
- uint64_t SymVA =
- SignExtend64<Bits>(getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+ uint64_t TargetVA = SignExtend64<Bits>(
+ getRelocTargetVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
switch (Expr) {
case R_RELAX_GOT_PC:
case R_RELAX_GOT_PC_NOPIC:
- Target->relaxGot(BufLoc, SymVA);
+ Target->relaxGot(BufLoc, TargetVA);
break;
case R_RELAX_TLS_IE_TO_LE:
- Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
+ Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
- Target->relaxTlsLdToLe(BufLoc, Type, SymVA);
+ Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_GD_TO_LE_NEG:
- Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
+ Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_IE:
case R_RELAX_TLS_GD_TO_IE_ABS:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_END:
- Target->relaxTlsGdToIe(BufLoc, Type, SymVA);
+ Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
break;
case R_PPC_PLT_OPD:
// Patch a nop (0x60000000) to a ld.
if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
- // fallthrough
+ // fallthrough
default:
- Target->relocateOne(BufLoc, Type, SymVA);
+ Target->relocateOne(BufLoc, Type, TargetVA);
break;
}
}
}
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
- if (this->Header->sh_type == SHT_NOBITS)
+ if (this->Type == SHT_NOBITS)
return;
- ELFFile<ELFT> &EObj = this->File->getObj();
+
+ if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) {
+ S->writeTo(Buf + OutSecOff);
+ return;
+ }
// If -r is given, then an InputSection may be a relocation section.
- if (this->Header->sh_type == SHT_RELA) {
- copyRelocations(Buf + OutSecOff, EObj.relas(this->Header));
+ if (this->Type == SHT_RELA) {
+ copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
return;
}
- if (this->Header->sh_type == SHT_REL) {
- copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
+ if (this->Type == SHT_REL) {
+ copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rel>());
return;
}
// Copy section contents from source object file to output file.
- ArrayRef<uint8_t> Data = this->getSectionData();
+ ArrayRef<uint8_t> Data = this->Data;
memcpy(Buf + OutSecOff, Data.data(), Data.size());
// Iterate over all relocation sections that apply to this section.
@@ -431,15 +569,9 @@ void InputSection<ELFT>::replace(InputSection<ELFT> *Other) {
}
template <class ELFT>
-SplitInputSection<ELFT>::SplitInputSection(
- elf::ObjectFile<ELFT> *File, const Elf_Shdr *Header,
- typename InputSectionBase<ELFT>::Kind SectionKind)
- : InputSectionBase<ELFT>(File, Header, SectionKind) {}
-
-template <class ELFT>
EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header)
- : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) {
+ const Elf_Shdr *Header, StringRef Name)
+ : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::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.
@@ -447,18 +579,54 @@ EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
}
template <class ELFT>
-bool EhInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
+bool EhInputSection<ELFT>::classof(const InputSectionData *S) {
+ return S->kind() == InputSectionBase<ELFT>::EHFrame;
+}
+
+// Returns the index of the first relocation that points to a region between
+// Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
+ unsigned &RelocI) {
+ // Start search from RelocI for fast access. That works because the
+ // relocations are sorted in .eh_frame.
+ for (unsigned N = Rels.size(); RelocI < N; ++RelocI) {
+ const RelTy &Rel = Rels[RelocI];
+ if (Rel.r_offset < Begin)
+ continue;
+
+ if (Rel.r_offset < Begin + Size)
+ return RelocI;
+ return -1;
+ }
+ return -1;
}
// .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() {
+ // Early exit if already split.
+ if (!this->Pieces.empty())
+ return;
+
+ if (this->NumRelocations) {
+ if (this->AreRelocsRela)
+ split(this->relas());
+ else
+ split(this->rels());
+ return;
+ }
+ split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+}
+
template <class ELFT>
-void EhInputSection<ELFT>::split() {
- ArrayRef<uint8_t> Data = this->getSectionData();
+template <class RelTy>
+void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) {
+ ArrayRef<uint8_t> Data = this->Data;
+ unsigned RelI = 0;
for (size_t Off = 0, End = Data.size(); Off != End;) {
- size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
- this->Pieces.emplace_back(Off, Data.slice(Off, Size));
+ size_t Size = readEhRecordSize<ELFT>(this, Off);
+ this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
// The empty record is the end marker.
if (Size == 4)
break;
@@ -466,21 +634,6 @@ void EhInputSection<ELFT>::split() {
}
}
-template <class ELFT>
-typename ELFT::uint EhInputSection<ELFT>::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;
- const SectionPiece *Piece = this->getSectionPiece(Offset);
- if (Piece->OutputOff == size_t(-1))
- return -1; // Not in the output
-
- uintX_t Addend = Offset - Piece->InputOff;
- return Piece->OutputOff + Addend;
-}
-
static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
// Optimize the common case.
StringRef S((const char *)A.data(), A.size());
@@ -497,75 +650,96 @@ static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
// Split SHF_STRINGS section. Such section is a sequence of
// null-terminated strings.
-static std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> Data,
- size_t EntSize) {
- std::vector<SectionPiece> V;
+template <class ELFT>
+void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
size_t Off = 0;
+ bool IsAlloc = this->Flags & SHF_ALLOC;
while (!Data.empty()) {
size_t End = findNull(Data, EntSize);
if (End == StringRef::npos)
- fatal("string is not null terminated");
+ fatal(toString(this) + ": string is not null terminated");
size_t Size = End + EntSize;
- V.emplace_back(Off, Data.slice(0, Size));
+ Pieces.emplace_back(Off, !IsAlloc);
+ Hashes.push_back(hash_value(toStringRef(Data.slice(0, Size))));
Data = Data.slice(Size);
Off += Size;
}
- return V;
}
// Split non-SHF_STRINGS section. Such section is a sequence of
// fixed size records.
-static std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> Data,
- size_t EntSize) {
- std::vector<SectionPiece> V;
+template <class ELFT>
+void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
size_t Size = Data.size();
assert((Size % EntSize) == 0);
- for (unsigned I = 0, N = Size; I != N; I += EntSize)
- V.emplace_back(I, Data.slice(I, EntSize));
- return V;
+ bool IsAlloc = this->Flags & SHF_ALLOC;
+ for (unsigned I = 0, N = Size; I != N; I += EntSize) {
+ Hashes.push_back(hash_value(toStringRef(Data.slice(I, EntSize))));
+ Pieces.emplace_back(I, !IsAlloc);
+ }
}
template <class ELFT>
MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header)
- : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {}
+ const Elf_Shdr *Header,
+ StringRef Name)
+ : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::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
+// into small chunks for further processing.
+//
+// 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() {
- ArrayRef<uint8_t> Data = this->getSectionData();
- uintX_t EntSize = this->Header->sh_entsize;
- if (this->Header->sh_flags & SHF_STRINGS)
- this->Pieces = splitStrings(Data, EntSize);
+ ArrayRef<uint8_t> Data = this->Data;
+ uintX_t EntSize = this->Entsize;
+ if (this->Flags & SHF_STRINGS)
+ splitStrings(Data, EntSize);
else
- this->Pieces = splitNonStrings(Data, EntSize);
+ splitNonStrings(Data, EntSize);
- if (Config->GcSections)
+ if (Config->GcSections && (this->Flags & SHF_ALLOC))
for (uintX_t Off : LiveOffsets)
this->getSectionPiece(Off)->Live = true;
}
template <class ELFT>
-bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == InputSectionBase<ELFT>::Merge;
+bool MergeInputSection<ELFT>::classof(const InputSectionData *S) {
+ return S->kind() == InputSectionBase<ELFT>::Merge;
}
// Do binary search to get a section piece at a given input offset.
template <class ELFT>
-SectionPiece *SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
- auto *This = static_cast<const SplitInputSection<ELFT> *>(this);
+SectionPiece *MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
+ auto *This = static_cast<const MergeInputSection<ELFT> *>(this);
return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
}
+template <class It, class T, class Compare>
+static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
+ size_t Size = std::distance(First, Last);
+ assert(Size != 0);
+ while (Size != 1) {
+ size_t H = Size / 2;
+ const It MI = First + H;
+ Size -= H;
+ First = Comp(Value, *MI) ? First : First + H;
+ }
+ return Comp(Value, *First) ? First : First + 1;
+}
+
template <class ELFT>
const SectionPiece *
-SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
- ArrayRef<uint8_t> D = this->getSectionData();
- StringRef Data((const char *)D.data(), D.size());
- uintX_t Size = Data.size();
+MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
+ uintX_t Size = this->Data.size();
if (Offset >= Size)
- fatal("entry is past the end of the section");
+ fatal(toString(this) + ": entry is past the end of the section");
// Find the element this offset points to.
- auto I = std::upper_bound(
+ auto I = fastUpperBound(
Pieces.begin(), Pieces.end(), Offset,
[](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
@@ -577,84 +751,31 @@ SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
// it is not just an addition to a base output offset.
template <class ELFT>
typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+ // Initialize OffsetMap lazily.
+ std::call_once(InitOffsetMap, [&] {
+ OffsetMap.reserve(Pieces.size());
+ for (const SectionPiece &Piece : Pieces)
+ OffsetMap[Piece.InputOff] = Piece.OutputOff;
+ });
+
+ // Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
return It->second;
+ if (!this->Live)
+ return 0;
+
// 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.
const SectionPiece &Piece = *this->getSectionPiece(Offset);
- assert(Piece.Live);
+ if (!Piece.Live)
+ return 0;
+
uintX_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
-// Create a map from input offsets to output offsets for all section pieces.
-// It is called after finalize().
-template <class ELFT> void MergeInputSection<ELFT>::finalizePieces() {
- OffsetMap.grow(this->Pieces.size());
- for (SectionPiece &Piece : this->Pieces) {
- if (!Piece.Live)
- continue;
- if (Piece.OutputOff == size_t(-1)) {
- // Offsets of tail-merged strings are computed lazily.
- auto *OutSec = static_cast<MergeOutputSection<ELFT> *>(this->OutSec);
- ArrayRef<uint8_t> D = Piece.data();
- StringRef S((const char *)D.data(), D.size());
- Piece.OutputOff = OutSec->getOffset(S);
- }
- OffsetMap[Piece.InputOff] = Piece.OutputOff;
- }
-}
-
-template <class ELFT>
-MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Hdr)
- : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) {
- // Initialize this->Reginfo.
- ArrayRef<uint8_t> D = this->getSectionData();
- if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) {
- error("invalid size of .reginfo section");
- return;
- }
- Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data());
-}
-
-template <class ELFT>
-bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
-}
-
-template <class ELFT>
-MipsOptionsInputSection<ELFT>::MipsOptionsInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Hdr)
- : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsOptions) {
- // Find ODK_REGINFO option in the section's content.
- ArrayRef<uint8_t> D = this->getSectionData();
- while (!D.empty()) {
- if (D.size() < sizeof(Elf_Mips_Options<ELFT>)) {
- error("invalid size of .MIPS.options section");
- break;
- }
- auto *O = reinterpret_cast<const Elf_Mips_Options<ELFT> *>(D.data());
- if (O->kind == ODK_REGINFO) {
- Reginfo = &O->getRegInfo();
- break;
- }
- D = D.slice(O->size);
- }
-}
-
-template <class ELFT>
-bool MipsOptionsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == InputSectionBase<ELFT>::MipsOptions;
-}
-
-template bool elf::isDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *);
-template bool elf::isDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *);
-template bool elf::isDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *);
-template bool elf::isDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *);
-
template class elf::InputSectionBase<ELF32LE>;
template class elf::InputSectionBase<ELF32BE>;
template class elf::InputSectionBase<ELF64LE>;
@@ -665,11 +786,6 @@ template class elf::InputSection<ELF32BE>;
template class elf::InputSection<ELF64LE>;
template class elf::InputSection<ELF64BE>;
-template class elf::SplitInputSection<ELF32LE>;
-template class elf::SplitInputSection<ELF32BE>;
-template class elf::SplitInputSection<ELF64LE>;
-template class elf::SplitInputSection<ELF64BE>;
-
template class elf::EhInputSection<ELF32LE>;
template class elf::EhInputSection<ELF32BE>;
template class elf::EhInputSection<ELF64LE>;
@@ -680,12 +796,7 @@ template class elf::MergeInputSection<ELF32BE>;
template class elf::MergeInputSection<ELF64LE>;
template class elf::MergeInputSection<ELF64BE>;
-template class elf::MipsReginfoInputSection<ELF32LE>;
-template class elf::MipsReginfoInputSection<ELF32BE>;
-template class elf::MipsReginfoInputSection<ELF64LE>;
-template class elf::MipsReginfoInputSection<ELF64BE>;
-
-template class elf::MipsOptionsInputSection<ELF32LE>;
-template class elf::MipsOptionsInputSection<ELF32BE>;
-template class elf::MipsOptionsInputSection<ELF64LE>;
-template class elf::MipsOptionsInputSection<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> *);
OpenPOWER on IntegriCloud