diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-24 01:00:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-24 01:00:50 +0000 |
commit | 0d9ba4fe26725cacc7253fc3c72c4574f26bc099 (patch) | |
tree | 90c426d54188ca226b29aaf8a308bba364a73d1a /ELF | |
parent | eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3 (diff) |
Notes
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/AArch64ErrataFix.cpp | 4 | ||||
-rw-r--r-- | ELF/Arch/ARM.cpp | 12 | ||||
-rw-r--r-- | ELF/Driver.cpp | 4 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 114 | ||||
-rw-r--r-- | ELF/InputFiles.h | 15 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 201 | ||||
-rw-r--r-- | ELF/InputSection.h | 14 | ||||
-rw-r--r-- | ELF/MarkLive.cpp | 4 | ||||
-rw-r--r-- | ELF/Relocations.cpp | 112 | ||||
-rw-r--r-- | ELF/ScriptParser.cpp | 2 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 100 | ||||
-rw-r--r-- | ELF/SymbolTable.h | 10 | ||||
-rw-r--r-- | ELF/Symbols.cpp | 16 | ||||
-rw-r--r-- | ELF/Symbols.h | 27 | ||||
-rw-r--r-- | ELF/SyntheticSections.cpp | 77 | ||||
-rw-r--r-- | ELF/SyntheticSections.h | 9 | ||||
-rw-r--r-- | ELF/Target.cpp | 2 | ||||
-rw-r--r-- | ELF/Target.h | 4 | ||||
-rw-r--r-- | ELF/Thunks.cpp | 32 | ||||
-rw-r--r-- | ELF/Writer.cpp | 118 | ||||
-rw-r--r-- | ELF/Writer.h | 2 |
21 files changed, 429 insertions, 450 deletions
diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp index 6cc68cc08e10c..9c0d536dea71e 100644 --- a/ELF/AArch64ErrataFix.cpp +++ b/ELF/AArch64ErrataFix.cpp @@ -400,8 +400,8 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) this->Parent = P->getParent(); PatchSym = addSyntheticLocal( Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, - getSize(), this); - addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, this); + getSize(), *this); + addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this); } uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp index 94a98e7679bdd..b9f551e4b3be8 100644 --- a/ELF/Arch/ARM.cpp +++ b/ELF/Arch/ARM.cpp @@ -37,8 +37,8 @@ public: void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override; - void addPltHeaderSymbols(InputSectionBase *ISD) const override; + void addPltSymbols(InputSection &IS, uint64_t Off) const override; + void addPltHeaderSymbols(InputSection &ISD) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; @@ -184,7 +184,7 @@ void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { write32le(Buf, S.getVA()); } -// Long form PLT Heade that does not have any restrictions on the displacement +// Long form PLT Header that does not have any restrictions on the displacement // of the .plt from the .plt.got. static void writePltHeaderLong(uint8_t *Buf) { const uint8_t PltData[] = { @@ -232,8 +232,7 @@ void ARM::writePltHeader(uint8_t *Buf) const { write32le(Buf + 28, TrapInstr); } -void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const { - auto *IS = cast<InputSection>(ISD); +void ARM::addPltHeaderSymbols(InputSection &IS) const { addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } @@ -282,8 +281,7 @@ void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary } -void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { - auto *IS = cast<InputSection>(ISD); +void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 2b6925031b07d..cc76fea2ad5e5 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -1056,7 +1056,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) - addReservedSymbols<ELFT>(); + addReservedSymbols(); // Apply version scripts. Symtab->scanVersionScript(); @@ -1111,7 +1111,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // before decompressAndMergeSections because the .comment section is a // mergeable section. if (!Config->Relocatable) - InputSections.push_back(createCommentSection<ELFT>()); + InputSections.push_back(createCommentSection()); // Do size optimizations: garbage collection, merging of SHF_MERGE sections // and identical code folding. diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 1f68340c94289..f514870ca84ab 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -32,6 +32,7 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::sys; using namespace llvm::sys::fs; using namespace lld; @@ -69,6 +70,50 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { return MBRef; } +// Concatenates arguments to construct a string representing an error location. +static std::string createFileLineMsg(StringRef Path, unsigned Line) { + std::string Filename = path::filename(Path); + std::string Lineno = ":" + std::to_string(Line); + if (Filename == Path) + return Filename + Lineno; + return Filename + Lineno + " (" + Path.str() + Lineno + ")"; +} + +template <class ELFT> +static std::string getSrcMsgAux(ObjFile<ELFT> &File, const Symbol &Sym, + InputSectionBase &Sec, uint64_t Offset) { + // In DWARF, functions and variables are stored to different places. + // First, lookup a function for a given offset. + if (Optional<DILineInfo> Info = File.getDILineInfo(&Sec, Offset)) + return createFileLineMsg(Info->FileName, Info->Line); + + // If it failed, lookup again as a variable. + if (Optional<std::pair<std::string, unsigned>> FileLine = + File.getVariableLoc(Sym.getName())) + return createFileLineMsg(FileLine->first, FileLine->second); + + // File.SourceFile contains STT_FILE symbol, and that is a last resort. + return File.SourceFile; +} + +std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset) { + if (kind() != ObjKind) + return ""; + switch (Config->EKind) { + default: + llvm_unreachable("Invalid kind"); + case ELF32LEKind: + return getSrcMsgAux(cast<ObjFile<ELF32LE>>(*this), Sym, Sec, Offset); + case ELF32BEKind: + return getSrcMsgAux(cast<ObjFile<ELF32BE>>(*this), Sym, Sec, Offset); + case ELF64LEKind: + return getSrcMsgAux(cast<ObjFile<ELF64LE>>(*this), Sym, Sec, Offset); + case ELF64BEKind: + return getSrcMsgAux(cast<ObjFile<ELF64BE>>(*this), Sym, Sec, Offset); + } +} + template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this)); const DWARFObject &Obj = Dwarf.getDWARFObj(); @@ -384,8 +429,8 @@ void ObjFile<ELFT>::initializeSections( // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. if (Sec.sh_flags & SHF_LINK_ORDER) { if (Sec.sh_link >= this->Sections.size()) - fatal(toString(this) + ": invalid sh_link index: " + - Twine(Sec.sh_link)); + fatal(toString(this) + + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( cast<InputSection>(this->Sections[I])); } @@ -454,11 +499,9 @@ InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { // Create a regular InputSection class that has the same contents // as a given section. -InputSectionBase *toRegularSection(MergeInputSection *Sec) { - auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment, - Sec->Data, Sec->Name); - Ret->File = Sec->File; - return Ret; +static InputSection *toRegularSection(MergeInputSection *Sec) { + return make<InputSection>(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, + Sec->Data, Sec->Name); } template <class ELFT> @@ -471,13 +514,13 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { break; ARMAttributeParser Attributes; ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec)); - Attributes.Parse(Contents, /*isLittle*/Config->EKind == ELF32LEKind); + Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind); updateSupportedARMFeatures(Attributes); // FIXME: Retain the first attribute section we see. The eglibc ARM // dynamic loaders require the presence of an attribute section for dlopen // to work. In a full implementation we would merge all attribute sections. if (InX::ARMAttributes == nullptr) { - InX::ARMAttributes = make<InputSection>(this, &Sec, Name); + InX::ARMAttributes = make<InputSection>(*this, Sec, Name); return InX::ARMAttributes; } return &InputSection::Discarded; @@ -496,7 +539,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. if (Config->Relocatable) - return make<InputSection>(this, &Sec, Name); + return make<InputSection>(*this, Sec, Name); if (Target->FirstRelocation) fatal(toString(this) + @@ -534,7 +577,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { // However, if -emit-relocs is given, we need to leave them in the output. // (Some post link analysis tools need this information.) if (Config->EmitRelocs) { - InputSection *RelocSec = make<InputSection>(this, &Sec, Name); + InputSection *RelocSec = make<InputSection>(*this, Sec, Name); // We will not emit relocation section if target was discarded. Target->DependentSections.push_back(RelocSec); return RelocSec; @@ -581,11 +624,11 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. if (Name == ".eh_frame" && !Config->Relocatable) - return make<EhInputSection>(this, &Sec, Name); + return make<EhInputSection>(*this, Sec, Name); if (shouldMerge(Sec)) - return make<MergeInputSection>(this, &Sec, Name); - return make<InputSection>(this, &Sec, Name); + return make<MergeInputSection>(*this, Sec, Name); + return make<InputSection>(*this, Sec, Name); } template <class ELFT> @@ -636,7 +679,7 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); - return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this); + return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this); } switch (Binding) { @@ -648,8 +691,8 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { if (Sec == &InputSection::Discarded) return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this); - return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding, - Sec, this); + return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, + this); } } @@ -660,7 +703,7 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) template <class ELFT> void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym)); + Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. @@ -841,14 +884,14 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { error(toString(this) + ": alignment too large: " + Name); if (!Hidden) - Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); + Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. if (Ver) { StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); - Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); + Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); } } } @@ -925,7 +968,7 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { template <class ELFT> static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, const lto::InputFile::Symbol &ObjSym, - BitcodeFile *F) { + BitcodeFile &F) { StringRef NameRef = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; @@ -936,11 +979,11 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + CanOmitFromDynSym, &F); if (ObjSym.isUndefined()) return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + CanOmitFromDynSym, &F); if (ObjSym.isCommon()) return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), @@ -958,7 +1001,7 @@ void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) - Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this)); + Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, *this)); } static ELFKind getELFKind(MemoryBufferRef MB) { @@ -981,10 +1024,10 @@ static ELFKind getELFKind(MemoryBufferRef MB) { return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } -template <class ELFT> void BinaryFile::parse() { +void BinaryFile::parse() { ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer()); - auto *Section = - make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); + auto *Section = make<InputSection>(nullptr, SHF_ALLOC | SHF_WRITE, + SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary @@ -996,12 +1039,12 @@ template <class ELFT> void BinaryFile::parse() { if (!isAlnum(S[I])) S[I] = '_'; - Symtab->addRegular<ELFT>(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, - 0, 0, STB_GLOBAL, Section, nullptr); - Symtab->addRegular<ELFT>(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, Section, nullptr); - Symtab->addRegular<ELFT>(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, nullptr, nullptr); + Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, + STB_GLOBAL, Section, nullptr); + Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { @@ -1145,8 +1188,3 @@ template class elf::SharedFile<ELF32LE>; template class elf::SharedFile<ELF32BE>; template class elf::SharedFile<ELF64LE>; template class elf::SharedFile<ELF64BE>; - -template void BinaryFile::parse<ELF32LE>(); -template void BinaryFile::parse<ELF32BE>(); -template void BinaryFile::parse<ELF64LE>(); -template void BinaryFile::parse<ELF64BE>(); diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 427f2fdea53ee..dda1de81570cc 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -72,6 +72,11 @@ public: Kind kind() const { return FileKind; } + bool isElf() const { + Kind K = kind(); + return K == ObjKind || K == SharedKind; + } + StringRef getName() const { return MB.getBufferIdentifier(); } MemoryBufferRef MB; @@ -104,6 +109,9 @@ public: // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; + std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset); + protected: InputFile(Kind K, MemoryBufferRef M); std::vector<InputSectionBase *> Sections; @@ -121,10 +129,7 @@ public: typedef typename ELFT::SymRange Elf_Sym_Range; ELFFileBase(Kind K, MemoryBufferRef M); - static bool classof(const InputFile *F) { - Kind K = F->kind(); - return K == ObjKind || K == SharedKind; - } + static bool classof(const InputFile *F) { return F->isElf(); } llvm::object::ELFFile<ELFT> getObj() const { return check(llvm::object::ELFFile<ELFT>::create(MB.getBuffer())); @@ -325,7 +330,7 @@ class BinaryFile : public InputFile { public: explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } - template <class ELFT> void parse(); + void parse(); }; InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 02cad56ca5088..93baefadce6e8 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -24,7 +24,6 @@ #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 "llvm/Support/xxhash.h" #include <mutex> @@ -73,11 +72,11 @@ DenseMap<SectionBase *, int> elf::buildSectionOrder() { } template <class ELFT> -static ArrayRef<uint8_t> getSectionContents(ObjFile<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)); +static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File, + const typename ELFT::Shdr &Hdr) { + if (Hdr.sh_type == SHT_NOBITS) + return makeArrayRef<uint8_t>(nullptr, Hdr.sh_size); + return check(File.getObj().getSectionContents(&Hdr)); } InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, @@ -88,6 +87,12 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, Link), File(File), Data(Data) { + // In order to reduce memory allocation, we assume that mergeable + // sections are smaller than 4 GiB, which is not an unreasonable + // assumption as of 2017. + if (SectionKind == SectionBase::Merge && Data.size() > UINT32_MAX) + error(toString(this) + ": section too large"); + NumRelocations = 0; AreRelocsRela = false; @@ -128,18 +133,18 @@ static uint64_t getType(uint64_t Type, StringRef Name) { } template <class ELFT> -InputSectionBase::InputSectionBase(ObjFile<ELFT> *File, - const typename ELFT::Shdr *Hdr, +InputSectionBase::InputSectionBase(ObjFile<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, + : 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 (Hdr->sh_addralign > UINT32_MAX) - fatal(toString(File) + ": section sh_addralign is too large"); + if (Hdr.sh_addralign > UINT32_MAX) + fatal(toString(&File) + ": section sh_addralign is too large"); } size_t InputSectionBase::getSize() const { @@ -211,8 +216,8 @@ void InputSectionBase::maybeUncompress() { fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); - this->Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size); - this->Flags &= ~(uint64_t)SHF_COMPRESSED; + Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size); + Flags &= ~(uint64_t)SHF_COMPRESSED; } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -257,40 +262,17 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); } -// Concatenates arguments to construct a string representing an error location. -static std::string createFileLineMsg(StringRef Path, unsigned Line) { - std::string Filename = path::filename(Path); - std::string Lineno = ":" + std::to_string(Line); - if (Filename == Path) - return Filename + Lineno; - return Filename + Lineno + " (" + Path.str() + Lineno + ")"; -} - // 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(const Symbol &Sym, uint64_t Offset) { // Synthetic sections don't have input files. - ObjFile<ELFT> *File = getFile<ELFT>(); if (!File) return ""; - - // In DWARF, functions and variables are stored to different places. - // First, lookup a function for a given offset. - if (Optional<DILineInfo> Info = File->getDILineInfo(this, Offset)) - return createFileLineMsg(Info->FileName, Info->Line); - - // If it failed, lookup again as a variable. - if (Optional<std::pair<std::string, unsigned>> FileLine = - File->getVariableLoc(Sym.getName())) - return createFileLineMsg(FileLine->first, FileLine->second); - - // File->SourceFile contains STT_FILE symbol, and that is a last resort. - return File->SourceFile; + return File->getSrcMsg(Sym, *this, Offset); } // Returns a filename string along with an optional section name. This @@ -323,16 +305,17 @@ std::string InputSectionBase::getObjMsg(uint64_t Off) { .str(); } -InputSection InputSection::Discarded(0, 0, 0, ArrayRef<uint8_t>(), ""); +InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), ""); -InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, - ArrayRef<uint8_t> Data, StringRef Name, Kind K) - : InputSectionBase(nullptr, Flags, Type, +InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type, + uint32_t Alignment, ArrayRef<uint8_t> Data, + StringRef Name, Kind K) + : InputSectionBase(F, Flags, Type, /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data, Name, K) {} template <class ELFT> -InputSection::InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, +InputSection::InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} @@ -357,15 +340,15 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) { // Adjust section numbers because section numbers in an input object // files are different in the output. - ArrayRef<InputSectionBase *> Sections = this->File->getSections(); + ArrayRef<InputSectionBase *> Sections = File->getSections(); for (uint32_t Idx : From.slice(1)) *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } InputSectionBase *InputSection::getRelocatedSection() { - assert(this->Type == SHT_RELA || this->Type == SHT_REL); - ArrayRef<InputSectionBase *> Sections = this->File->getSections(); - return Sections[this->Info]; + assert(Type == SHT_RELA || Type == SHT_REL); + ArrayRef<InputSectionBase *> Sections = File->getSections(); + return Sections[Info]; } // This is used for -r and --emit-relocs. We can't use memcpy to copy @@ -377,7 +360,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { for (const RelTy &Rel : Rels) { RelType Type = Rel.getType(Config->IsMips64EL); - Symbol &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); + Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); @@ -679,7 +662,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); - Symbol &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); + Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); if (Expr == R_NONE) continue; @@ -691,7 +674,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { if (Config->EMachine == EM_386 && Type == R_386_GOTPC) continue; - error(this->getLocation<ELFT>(Offset) + ": has non-ABS relocation " + + error(getLocation<ELFT>(Offset) + ": has non-ABS relocation " + toString(Type) + " against symbol '" + toString(Sym) + "'"); return; } @@ -765,7 +748,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { } template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { - if (this->Type == SHT_NOBITS) + if (Type == SHT_NOBITS) return; if (auto *S = dyn_cast<SyntheticSection>(this)) { @@ -775,19 +758,17 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { // If -r or --emit-relocs is given, then an InputSection // may be a relocation section. - if (this->Type == SHT_RELA) { - copyRelocations<ELFT>(Buf + OutSecOff, - this->template getDataAs<typename ELFT::Rela>()); + if (Type == SHT_RELA) { + copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rela>()); return; } - if (this->Type == SHT_REL) { - copyRelocations<ELFT>(Buf + OutSecOff, - this->template getDataAs<typename ELFT::Rel>()); + if (Type == SHT_REL) { + copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rel>()); return; } // If -r is given, we may have a SHT_GROUP section. - if (this->Type == SHT_GROUP) { + if (Type == SHT_GROUP) { copyShtGroup<ELFT>(Buf + OutSecOff); return; } @@ -796,18 +777,18 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); uint8_t *BufEnd = Buf + OutSecOff + Data.size(); - this->relocate<ELFT>(Buf, BufEnd); + relocate<ELFT>(Buf, BufEnd); } void InputSection::replace(InputSection *Other) { - this->Alignment = std::max(this->Alignment, Other->Alignment); - Other->Repl = this->Repl; + Alignment = std::max(Alignment, Other->Alignment); + Other->Repl = Repl; Other->Live = false; } template <class ELFT> -EhInputSection::EhInputSection(ObjFile<ELFT> *F, - const typename ELFT::Shdr *Header, +EhInputSection::EhInputSection(ObjFile<ELFT> &F, + const typename ELFT::Shdr &Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {} @@ -838,22 +819,21 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels, // This function splits an input section into records and returns them. template <class ELFT> void EhInputSection::split() { // Early exit if already split. - if (!this->Pieces.empty()) + if (!Pieces.empty()) return; - if (this->AreRelocsRela) - split<ELFT>(this->relas<ELFT>()); + if (AreRelocsRela) + split<ELFT>(relas<ELFT>()); else - split<ELFT>(this->rels<ELFT>()); + split<ELFT>(rels<ELFT>()); } 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;) { size_t Size = readEhRecordSize(this, Off); - this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); + Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); // The empty record is the end marker. if (Size == 4) break; @@ -882,7 +862,7 @@ SyntheticSection *MergeInputSection::getParent() const { // null-terminated strings. void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) { size_t Off = 0; - bool IsAlloc = this->Flags & SHF_ALLOC; + bool IsAlloc = Flags & SHF_ALLOC; StringRef S = toStringRef(Data); while (!S.empty()) { @@ -903,7 +883,7 @@ 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; + bool IsAlloc = Flags & SHF_ALLOC; for (size_t I = 0; I != Size; I += EntSize) Pieces.emplace_back(I, xxHash64(toStringRef(Data.slice(I, EntSize))), @@ -911,16 +891,16 @@ void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, } template <class ELFT> -MergeInputSection::MergeInputSection(ObjFile<ELFT> *F, - const typename ELFT::Shdr *Header, +MergeInputSection::MergeInputSection(ObjFile<ELFT> &F, + const typename ELFT::Shdr &Header, StringRef Name) - : InputSectionBase(F, Header, Name, InputSectionBase::Merge) { - // In order to reduce memory allocation, we assume that mergeable - // sections are smaller than 4 GiB, which is not an unreasonable - // assumption as of 2017. - if (Data.size() > UINT32_MAX) - error(toString(this) + ": section too large"); -} + : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} + +MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type, + uint64_t Entsize, ArrayRef<uint8_t> Data, + StringRef Name) + : InputSectionBase(nullptr, Flags, Type, Entsize, /*Link*/ 0, /*Info*/ 0, + /*Alignment*/ Entsize, Data, Name, SectionBase::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 @@ -931,14 +911,14 @@ MergeInputSection::MergeInputSection(ObjFile<ELFT> *F, void MergeInputSection::splitIntoPieces() { assert(Pieces.empty()); - if (this->Flags & SHF_STRINGS) + if (Flags & SHF_STRINGS) splitStrings(Data, Entsize); else splitNonStrings(Data, Entsize); - if (Config->GcSections && (this->Flags & SHF_ALLOC)) + if (Config->GcSections && (Flags & SHF_ALLOC)) for (uint64_t Off : LiveOffsets) - this->getSectionPiece(Off)->Live = true; + getSectionPiece(Off)->Live = true; } // Do binary search to get a section piece at a given input offset. @@ -993,7 +973,7 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // 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); + const SectionPiece &Piece = *getSectionPiece(Offset); if (!Piece.Live) return 0; @@ -1001,13 +981,13 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const { return Piece.OutputOff + Addend; } -template InputSection::InputSection(ObjFile<ELF32LE> *, const ELF32LE::Shdr *, +template InputSection::InputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &, StringRef); -template InputSection::InputSection(ObjFile<ELF32BE> *, const ELF32BE::Shdr *, +template InputSection::InputSection(ObjFile<ELF32BE> &, const ELF32BE::Shdr &, StringRef); -template InputSection::InputSection(ObjFile<ELF64LE> *, const ELF64LE::Shdr *, +template InputSection::InputSection(ObjFile<ELF64LE> &, const ELF64LE::Shdr &, StringRef); -template InputSection::InputSection(ObjFile<ELF64BE> *, const ELF64BE::Shdr *, +template InputSection::InputSection(ObjFile<ELF64BE> &, const ELF64BE::Shdr &, StringRef); template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t); @@ -1015,37 +995,28 @@ 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>(const Symbol &, - uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF32BE>(const Symbol &, - uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF64LE>(const Symbol &, - uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF64BE>(const Symbol &, - 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 MergeInputSection::MergeInputSection(ObjFile<ELF32LE> *, - const ELF32LE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> *, - const ELF32BE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> *, - const ELF64LE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> *, - const ELF64BE::Shdr *, StringRef); - -template EhInputSection::EhInputSection(ObjFile<ELF32LE> *, - const ELF32LE::Shdr *, StringRef); -template EhInputSection::EhInputSection(ObjFile<ELF32BE> *, - const ELF32BE::Shdr *, StringRef); -template EhInputSection::EhInputSection(ObjFile<ELF64LE> *, - const ELF64LE::Shdr *, StringRef); -template EhInputSection::EhInputSection(ObjFile<ELF64BE> *, - const ELF64BE::Shdr *, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &, + const ELF32LE::Shdr &, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> &, + const ELF32BE::Shdr &, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> &, + const ELF64LE::Shdr &, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> &, + const ELF64BE::Shdr &, StringRef); + +template EhInputSection::EhInputSection(ObjFile<ELF32LE> &, + const ELF32LE::Shdr &, StringRef); +template EhInputSection::EhInputSection(ObjFile<ELF32BE> &, + const ELF32BE::Shdr &, StringRef); +template EhInputSection::EhInputSection(ObjFile<ELF64LE> &, + const ELF64LE::Shdr &, StringRef); +template EhInputSection::EhInputSection(ObjFile<ELF64BE> &, + const ELF64BE::Shdr &, StringRef); template void EhInputSection::split<ELF32LE>(); template void EhInputSection::split<ELF32BE>(); diff --git a/ELF/InputSection.h b/ELF/InputSection.h index dfd78a8fb4588..8c114ae719481 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -93,7 +93,7 @@ protected: class InputSectionBase : public SectionBase { public: template <class ELFT> - InputSectionBase(ObjFile<ELFT> *File, const typename ELFT::Shdr *Header, + InputSectionBase(ObjFile<ELFT> &File, const typename ELFT::Shdr &Header, StringRef Name, Kind SectionKind); InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, @@ -168,7 +168,6 @@ public: // Returns a source location string. Used to construct an error message. template <class ELFT> std::string getLocation(uint64_t Offset); - template <class ELFT> std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); std::string getObjMsg(uint64_t Offset); @@ -216,8 +215,11 @@ static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); class MergeInputSection : public InputSectionBase { public: template <class ELFT> - MergeInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + MergeInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name); + MergeInputSection(uint64_t Flags, uint32_t Type, uint64_t Entsize, + ArrayRef<uint8_t> Data, StringRef Name); + static bool classof(const SectionBase *S) { return S->kind() == Merge; } void splitIntoPieces(); @@ -279,7 +281,7 @@ struct EhSectionPiece { class EhInputSection : public InputSectionBase { public: template <class ELFT> - EhInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + EhInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name); static bool classof(const SectionBase *S) { return S->kind() == EHFrame; } template <class ELFT> void split(); @@ -298,10 +300,10 @@ public: // .eh_frame. It also includes the synthetic sections themselves. class InputSection : public InputSectionBase { public: - InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, + InputSection(InputFile *F, uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular); template <class ELFT> - InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name); // Write this section to a mmap'ed file, assuming Buf is pointing to diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index 36f994f204903..88f558c7a3c6e 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -68,7 +68,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, B.Used = true; if (auto *SS = dyn_cast<SharedSymbol>(&B)) if (!SS->isWeak()) - SS->getFile<ELFT>()->IsNeeded = true; + SS->getFile<ELFT>().IsNeeded = true; if (auto *D = dyn_cast<Defined>(&B)) { auto *RelSec = dyn_cast_or_null<InputSectionBase>(D->Section); @@ -246,7 +246,7 @@ template <class ELFT> static void doGcSections() { // that point to .eh_frames. Otherwise, the garbage collector would drop // all of them. We also want to preserve personality routines and LSDA // referenced by .eh_frame sections, so we scan them for that here. - if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec)) { + if (auto *EH = dyn_cast<EhInputSection>(Sec)) { EH->Live = true; scanEhFrameSection<ELFT>(*EH, Enqueue); } diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 96e409578f5c2..94ea3e1557c48 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -70,12 +70,11 @@ using namespace lld::elf; // >>> defined in /home/alice/src/foo.o // >>> referenced by bar.c:12 (/home/alice/src/bar.c:12) // >>> /home/alice/src/bar.o:(.text+0x1) -template <class ELFT> static std::string getLocation(InputSectionBase &S, const Symbol &Sym, uint64_t Off) { std::string Msg = "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by "; - std::string Src = S.getSrcMsg<ELFT>(Sym, Off); + std::string Src = S.getSrcMsg(Sym, Off); if (!Src.empty()) Msg += Src + "\n>>> "; return Msg + S.getObjMsg(Off); @@ -365,7 +364,6 @@ static bool isRelExpr(RelExpr Expr) { // // If this function returns false, that means we need to emit a // dynamic relocation so that the relocation will be fixed at load-time. -template <class ELFT> static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant @@ -410,7 +408,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, return true; error("relocation " + toString(Type) + " cannot refer to absolute symbol: " + - toString(Sym) + getLocation<ELFT>(S, Sym, RelOff)); + toString(Sym) + getLocation(S, Sym, RelOff)); return true; } @@ -443,8 +441,8 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::Phdr Elf_Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. - const SharedFile<ELFT> *File = SS->getFile<ELFT>(); - for (const Elf_Phdr &Phdr : check(File->getObj().program_headers())) + const SharedFile<ELFT> &File = SS->getFile<ELFT>(); + for (const Elf_Phdr &Phdr : check(File.getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && SS->Value < Phdr.p_vaddr + Phdr.p_memsz) @@ -461,14 +459,14 @@ template <class ELFT> static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { typedef typename ELFT::Sym Elf_Sym; - SharedFile<ELFT> *File = SS->getFile<ELFT>(); + SharedFile<ELFT> &File = SS->getFile<ELFT>(); std::vector<SharedSymbol *> Ret; - for (const Elf_Sym &S : File->getGlobalELFSyms()) { + for (const Elf_Sym &S : File.getGlobalELFSyms()) { if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || S.st_value != SS->Value) continue; - StringRef Name = check(S.getName(File->getStringTable())); + StringRef Name = check(S.getName(File.getStringTable())); Symbol *Sym = Symtab->find(Name); if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) Ret.push_back(Alias); @@ -554,22 +552,57 @@ static void errorOrWarn(const Twine &Msg) { warn(Msg); } +// Returns PLT relocation expression. +// +// This handles a non PIC program call to function in a shared library. In +// an ideal world, we could just report an error saying the relocation can +// overflow at runtime. In the real world with glibc, crt1.o has a +// R_X86_64_PC32 pointing to libc.so. +// +// The general idea on how to handle such cases is to create a PLT entry and +// use that as the function value. +// +// For the static linking part, we just return a plt expr and everything +// else will use the the PLT entry as the address. +// +// The remaining problem is making sure pointer equality still works. We +// need the help of the dynamic linker for that. We let it know that we have +// a direct reference to a so symbol by creating an undefined symbol with a +// non zero st_value. Seeing that, the dynamic linker resolves the symbol to +// the value of the symbol we created. This is true even for got entries, so +// pointer equality is maintained. To avoid an infinite loop, the only entry +// that points to the real function is a dedicated got entry used by the +// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, +// R_386_JMP_SLOT, etc). +static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) { + Sym.NeedsPltAddr = true; + Sym.IsPreemptible = false; + IsConstant = true; + return toPlt(Expr); +} + template <class ELFT> static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, - InputSectionBase &S, uint64_t RelOff) { + InputSectionBase &S, uint64_t RelOff, + bool &IsConstant) { // We can create any dynamic relocation if a section is simply writable. if (S.Flags & SHF_WRITE) return Expr; // Or, if we are allowed to create dynamic relocations against - // read-only sections (i.e. unless "-z notext" is given), + // read-only sections (i.e. when "-z notext" is given), // we can create a dynamic relocation as we want, too. - if (!Config->ZText) + if (!Config->ZText) { + // We use PLT for relocations that may overflow in runtime, + // see comment for getPltExpr(). + if (Sym.isFunc() && !Target->isPicRel(Type)) + return getPltExpr(Sym, Expr, IsConstant); return Expr; + } // If a relocation can be applied at link-time, we don't need to // create a dynamic relocation in the first place. - if (isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, S, RelOff)) + if (IsConstant) return Expr; // If we got here we know that this relocation would require the dynamic @@ -579,6 +612,7 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, // non preemptible 0. if (Sym.isUndefWeak()) { Sym.IsPreemptible = false; + IsConstant = true; return Expr; } @@ -589,13 +623,13 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, "can't create dynamic relocation " + toString(Type) + " against " + (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + " in readonly segment; recompile object files with -fPIC" + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); return Expr; } if (Sym.getVisibility() != STV_DEFAULT) { error("cannot preempt symbol: " + toString(Sym) + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); return Expr; } @@ -607,38 +641,16 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, error("unresolvable relocation " + toString(Type) + " against symbol '" + toString(*B) + "'; recompile with -fPIC or remove '-z nocopyreloc'" + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); addCopyRelSymbol<ELFT>(B); } + IsConstant = true; return Expr; } - if (Sym.isFunc()) { - // This handles a non PIC program call to function in a shared library. In - // an ideal world, we could just report an error saying the relocation can - // overflow at runtime. In the real world with glibc, crt1.o has a - // R_X86_64_PC32 pointing to libc.so. - // - // The general idea on how to handle such cases is to create a PLT entry and - // use that as the function value. - // - // For the static linking part, we just return a plt expr and everything - // else will use the the PLT entry as the address. - // - // The remaining problem is making sure pointer equality still works. We - // need the help of the dynamic linker for that. We let it know that we have - // a direct reference to a so symbol by creating an undefined symbol with a - // non zero st_value. Seeing that, the dynamic linker resolves the symbol to - // the value of the symbol we created. This is true even for got entries, so - // pointer equality is maintained. To avoid an infinite loop, the only entry - // that points to the real function is a dedicated got entry used by the - // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, - // R_386_JMP_SLOT, etc). - Sym.NeedsPltAddr = true; - Sym.IsPreemptible = false; - return toPlt(Expr); - } + if (Sym.isFunc()) + return getPltExpr(Sym, Expr, IsConstant); errorOrWarn("symbol '" + toString(Sym) + "' defined in " + toString(Sym.File) + " has no type"); @@ -708,7 +720,6 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End, // Report an undefined symbol if necessary. // Returns true if this function printed out an error message. -template <class ELFT> static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) @@ -725,7 +736,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, std::string Msg = "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; - std::string Src = Sec.getSrcMsg<ELFT>(Sym, Offset); + std::string Src = Sec.getSrcMsg(Sym, Offset); if (!Src.empty()) Msg += Src + "\n>>> "; Msg += Sec.getObjMsg(Offset); @@ -846,7 +857,7 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // // This is ugly -- the difference between REL and RELA should be // handled in a better way. It's a TODO. - if (!Config->IsRela) + if (!Config->IsRela && !Preemptible) InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); } @@ -885,7 +896,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { continue; // Skip if the target symbol is an erroneous undefined symbol. - if (maybeReportUndefined<ELFT>(Sym, Sec, Rel.r_offset)) + if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) continue; RelExpr Expr = @@ -923,7 +934,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { else if (!Preemptible) Expr = fromPlt(Expr); - Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset); + bool IsConstant = + isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset); + + Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant); if (errorCount()) continue; @@ -980,7 +994,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { errorOrWarn( "relocation " + toString(Type) + " cannot be used against shared object; recompile with -fPIC" + - getLocation<ELFT>(Sec, Sym, Offset)); + getLocation(Sec, Sym, Offset)); InX::RelaDyn->addReloc( {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); @@ -1005,10 +1019,6 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { continue; } - // If the relocation points to something in the file, we can process it. - bool IsConstant = - isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, Sec, Rel.r_offset); - // The size is not going to change, so we fold it in here. if (Expr == R_SIZE) Addend += Sym.getSize(); diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index d56500ae7dd8f..c1176ccfa8d56 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -151,6 +151,8 @@ static ExprValue add(ExprValue A, ExprValue B) { } static ExprValue sub(ExprValue A, ExprValue B) { + if (!A.isAbsolute() && !B.isAbsolute()) + return A.getValue() - B.getValue(); return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc}; } diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 12509c9a17575..b6bf219988632 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -44,8 +44,8 @@ static InputFile *getFirstElf() { // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. -template <class ELFT> static bool isCompatible(InputFile *F) { - if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F)) +static bool isCompatible(InputFile *F) { + if (!F->isElf() && !isa<BitcodeFile>(F)) return true; if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) { @@ -64,13 +64,13 @@ template <class ELFT> static bool isCompatible(InputFile *F) { // Add symbols in File to the symbol table. template <class ELFT> void SymbolTable::addFile(InputFile *File) { - if (!isCompatible<ELFT>(File)) + if (!isCompatible(File)) return; // Binary file if (auto *F = dyn_cast<BinaryFile>(File)) { BinaryFiles.push_back(F); - F->parse<ELFT>(); + F->parse(); return; } @@ -135,11 +135,10 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() { } } -template <class ELFT> Defined *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility, uint8_t Binding) { - Symbol *Sym = addRegular<ELFT>(Name, Visibility, STT_NOTYPE, 0, 0, Binding, - nullptr, nullptr); + Symbol *Sym = + addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr); return cast<Defined>(Sym); } @@ -306,7 +305,7 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, if (Binding != STB_WEAK) { if (auto *SS = dyn_cast<SharedSymbol>(S)) if (!Config->GcSections) - SS->getFile<ELFT>()->IsNeeded = true; + SS->getFile<ELFT>().IsNeeded = true; } if (auto *L = dyn_cast<Lazy>(S)) { // An undefined weak will not fetch archive members. See comment on Lazy in @@ -377,19 +376,19 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile *File) { + InputFile &File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), - /*CanOmitFromDynSym*/ false, File); + /*CanOmitFromDynSym*/ false, &File); int Cmp = compareDefined(S, WasInserted, Binding, N); if (Cmp > 0) { auto *Bss = make<BssSection>("COMMON", Size, Alignment); - Bss->File = File; + Bss->File = &File; Bss->Live = !Config->GcSections; InputSections.push_back(Bss); - replaceSymbol<Defined>(S, File, N, Binding, StOther, Type, 0, Size, Bss); + replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss); } else if (Cmp == 0) { auto *D = cast<Defined>(S); auto *Bss = dyn_cast_or_null<BssSection>(D->Section); @@ -405,7 +404,7 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, Bss->Alignment = std::max(Bss->Alignment, Alignment); if (Size > Bss->Size) { - D->File = Bss->File = File; + D->File = Bss->File = &File; D->Size = Bss->Size = Size; } } @@ -424,9 +423,8 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile) { toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } -template <class ELFT> static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, - typename ELFT::uint ErrOffset) { + uint64_t ErrOffset) { Defined *D = cast<Defined>(Sym); if (!D->Section || !ErrSec) { reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr); @@ -441,9 +439,9 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, // >>> defined at baz.c:563 // >>> baz.o in archive libbaz.a auto *Sec1 = cast<InputSectionBase>(D->Section); - std::string Src1 = Sec1->getSrcMsg<ELFT>(*Sym, D->Value); + std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value); std::string Obj1 = Sec1->getObjMsg(D->Value); - std::string Src2 = ErrSec->getSrcMsg<ELFT>(*Sym, ErrOffset); + std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset); std::string Obj2 = ErrSec->getObjMsg(ErrOffset); std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; @@ -456,7 +454,6 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, warnOrError(Msg); } -template <typename ELFT> Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *Section, InputFile *File) { @@ -470,13 +467,12 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, Section); else if (Cmp == 0) - reportDuplicate<ELFT>(S, dyn_cast_or_null<InputSectionBase>(Section), - Value); + reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value); return S; } template <typename ELFT> -void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, +void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File, const typename ELFT::Sym &Sym, uint32_t Alignment, uint32_t VerdefIndex) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT @@ -485,7 +481,7 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT, - /*CanOmitFromDynSym*/ true, File); + /*CanOmitFromDynSym*/ true, &File); // Make sure we preempt DSO symbols with default visibility. if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; @@ -501,24 +497,24 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, if (!WasInserted) { S->Binding = Binding; if (!S->isWeak() && !Config->GcSections) - File->IsNeeded = true; + File.IsNeeded = true; } } } Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, BitcodeFile *F) { + bool CanOmitFromDynSym, BitcodeFile &F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = - insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); + insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, &F); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, /*IsAbs*/ false, /*Value*/ 0, Name); if (Cmp > 0) - replaceSymbol<Defined>(S, F, Name, Binding, StOther, Type, 0, 0, nullptr); + replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr); else if (Cmp == 0) - reportDuplicate(S, F); + reportDuplicate(S, &F); return S; } @@ -532,7 +528,7 @@ Symbol *SymbolTable::find(StringRef Name) { } template <class ELFT> -Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, +Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; @@ -551,9 +547,9 @@ Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, S->Binding = STB_WEAK; return S; } - std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym); + std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) - addFile<ELFT>(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); + addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second)); return S; } @@ -563,7 +559,7 @@ void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - replaceSymbol<LazyObject>(S, &Obj, Name, Symbol::UnknownType); + replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType); return; } if (!S->isUndefined()) @@ -571,7 +567,7 @@ void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { // See comment for addLazyArchive above. if (S->isWeak()) - replaceSymbol<LazyObject>(S, &Obj, Name, S->Type); + replaceSymbol<LazyObject>(S, Obj, Name, S->Type); else if (InputFile *F = Obj.fetch()) addFile<ELFT>(F); } @@ -582,7 +578,7 @@ template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) { // Mark the symbol not to be eliminated by LTO // even if it is a bitcode symbol. B->IsUsedInRegularObj = true; - if (auto *L = dyn_cast_or_null<Lazy>(B)) + if (auto *L = dyn_cast<Lazy>(B)) if (InputFile *File = L->fetch()) addFile<ELFT>(File); } @@ -797,39 +793,17 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>(); template void SymbolTable::addCombinedLTOObject<ELF64LE>(); template void SymbolTable::addCombinedLTOObject<ELF64BE>(); -template Symbol *SymbolTable::addRegular<ELF32LE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular<ELF32BE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular<ELF64LE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular<ELF64BE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); - -template Defined *SymbolTable::addAbsolute<ELF32LE>(StringRef, uint8_t, - uint8_t); -template Defined *SymbolTable::addAbsolute<ELF32BE>(StringRef, uint8_t, - uint8_t); -template Defined *SymbolTable::addAbsolute<ELF64LE>(StringRef, uint8_t, - uint8_t); -template Defined *SymbolTable::addAbsolute<ELF64BE>(StringRef, uint8_t, - uint8_t); - template Symbol * -SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * -SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * -SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * -SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &); @@ -837,16 +811,16 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); -template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> *, +template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &, const typename ELF32LE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> *, +template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> &, const typename ELF32BE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> *, +template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &, const typename ELF64LE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> *, +template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &, const typename ELF64BE::Sym &, uint32_t Alignment, uint32_t); diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 738311c089db7..e7341b05baf51 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -42,7 +42,6 @@ public: ArrayRef<Symbol *> getSymbols() const { return SymVector; } - template <class ELFT> Defined *addAbsolute(StringRef Name, uint8_t Visibility = llvm::ELF::STV_HIDDEN, uint8_t Binding = llvm::ELF::STB_GLOBAL); @@ -51,28 +50,27 @@ public: template <class ELFT> Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, InputFile *File); - template <class ELFT> Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *Section, InputFile *File); template <class ELFT> - void addShared(StringRef Name, SharedFile<ELFT> *F, + void addShared(StringRef Name, SharedFile<ELFT> &F, const typename ELFT::Sym &Sym, uint32_t Alignment, uint32_t VerdefIndex); template <class ELFT> - Symbol *addLazyArchive(StringRef Name, ArchiveFile *F, + Symbol *addLazyArchive(StringRef Name, ArchiveFile &F, const llvm::object::Archive::Symbol S); template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj); Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); + uint8_t Type, bool CanOmitFromDynSym, BitcodeFile &File); Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile *File); + InputFile &File); std::pair<Symbol *, bool> insert(StringRef Name); std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type, diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index ab42fcd51a81b..13a91aab80bb7 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -116,12 +116,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { llvm_unreachable("invalid symbol kind"); } -// Returns true if this is a weak undefined symbol. -bool Symbol::isUndefWeak() const { - // See comment on Lazy in Symbols.h for the details. - return isWeak() && (isUndefined() || isLazy()); -} - uint64_t Symbol::getVA(int64_t Addend) const { uint64_t OutVA = getSymVA(*this, Addend); return OutVA + Addend; @@ -224,21 +218,21 @@ InputFile *Lazy::fetch() { return cast<LazyObject>(this)->fetch(); } -ArchiveFile *LazyArchive::getFile() { return cast<ArchiveFile>(File); } +ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); } InputFile *LazyArchive::fetch() { - std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile()->getMember(&Sym); + std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBInfo.first.getBuffer().empty()) return nullptr; - return createObjectFile(MBInfo.first, getFile()->getName(), MBInfo.second); + return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second); } -LazyObjFile *LazyObject::getFile() { return cast<LazyObjFile>(File); } +LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); } -InputFile *LazyObject::fetch() { return getFile()->fetch(); } +InputFile *LazyObject::fetch() { return getFile().fetch(); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) diff --git a/ELF/Symbols.h b/ELF/Symbols.h index f4bb245f955d1..9b7207383345a 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -102,7 +102,10 @@ public: // True is this is an undefined weak symbol. This only works once // all input files have been added. - bool isUndefWeak() const; + bool isUndefWeak() const { + // See comment on Lazy the details. + return isWeak() && (isUndefined() || isLazy()); + } StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } @@ -208,14 +211,14 @@ class SharedSymbol : public Symbol { public: static bool classof(const Symbol *S) { return S->kind() == SharedKind; } - SharedSymbol(InputFile *File, StringRef Name, uint8_t Binding, + SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint32_t Alignment, uint32_t VerdefIndex) - : Symbol(SharedKind, File, Name, Binding, StOther, Type), Value(Value), + : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value), Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) { // GNU ifunc is a mechanism to allow user-supplied functions to // resolve PLT slot values at load-time. This is contrary to the - // regualr symbol resolution scheme in which symbols are resolved just + // regular symbol resolution scheme in which symbols are resolved just // by name. Using this hook, you can program how symbols are solved // for you program. For example, you can make "memcpy" to be resolved // to a SSE-enabled version of memcpy only when a machine running the @@ -233,8 +236,8 @@ public: this->Type = llvm::ELF::STT_FUNC; } - template <class ELFT> SharedFile<ELFT> *getFile() const { - return cast<SharedFile<ELFT>>(File); + template <class ELFT> SharedFile<ELFT> &getFile() const { + return *cast<SharedFile<ELFT>>(File); } // If not null, there is a copy relocation to this section. @@ -267,8 +270,8 @@ public: InputFile *fetch(); protected: - Lazy(Kind K, InputFile *File, StringRef Name, uint8_t Type) - : Symbol(K, File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, + Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type) + : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, Type) {} }; @@ -278,13 +281,13 @@ protected: // symbol. class LazyArchive : public Lazy { public: - LazyArchive(InputFile *File, const llvm::object::Archive::Symbol S, + LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S, uint8_t Type) : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {} static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } - ArchiveFile *getFile(); + ArchiveFile &getFile(); InputFile *fetch(); private: @@ -295,12 +298,12 @@ private: // --start-lib and --end-lib options. class LazyObject : public Lazy { public: - LazyObject(InputFile *File, StringRef Name, uint8_t Type) + LazyObject(InputFile &File, StringRef Name, uint8_t Type) : Lazy(LazyObjectKind, File, Name, Type) {} static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } - LazyObjFile *getFile(); + LazyObjFile &getFile(); InputFile *fetch(); }; diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index b408e653dfa04..a5e291b79a4db 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -81,17 +81,9 @@ static ArrayRef<uint8_t> getVersion() { // With this feature, you can identify LLD-generated binaries easily // by "readelf --string-dump .comment <file>". // The returned object is a mergeable string section. -template <class ELFT> MergeInputSection *elf::createCommentSection() { - typename ELFT::Shdr Hdr = {}; - Hdr.sh_flags = SHF_MERGE | SHF_STRINGS; - Hdr.sh_type = SHT_PROGBITS; - Hdr.sh_entsize = 1; - Hdr.sh_addralign = 1; - - auto *Ret = - make<MergeInputSection>((ObjFile<ELFT> *)nullptr, &Hdr, ".comment"); - Ret->Data = getVersion(); - return Ret; +MergeInputSection *elf::createCommentSection() { + return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1, + getVersion(), ".comment"); } // .MIPS.abiflags section. @@ -268,16 +260,16 @@ InputSection *elf::createInterpSection() { StringRef S = Saver.save(Config->DynamicLinker); ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1}; - auto *Sec = - make<InputSection>(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp"); + auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents, + ".interp"); Sec->Live = true; return Sec; } Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase *Section) { - auto *S = make<Defined>(Section->File, Name, STB_LOCAL, STV_DEFAULT, Type, - Value, Size, Section); + uint64_t Size, InputSectionBase &Section) { + auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, + Value, Size, &Section); if (InX::SymTab) InX::SymTab->addSymbol(S); return S; @@ -1893,10 +1885,10 @@ size_t PltSection::getSize() const { void PltSection::addSymbols() { // The PLT may have symbols defined for the Header, the IPLT has no header if (HeaderSize != 0) - Target->addPltHeaderSymbols(this); + Target->addPltHeaderSymbols(*this); size_t Off = HeaderSize; for (size_t I = 0; I < Entries.size(); ++I) { - Target->addPltSymbols(this, Off); + Target->addPltSymbols(*this, Off); Off += Target->PltEntrySize; } } @@ -2299,8 +2291,8 @@ VersionNeedSection<ELFT>::VersionNeedSection() template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { - SharedFile<ELFT> *File = SS->getFile<ELFT>(); - const typename ELFT::Verdef *Ver = File->Verdefs[SS->VerdefIndex]; + SharedFile<ELFT> &File = SS->getFile<ELFT>(); + const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; if (!Ver) { SS->VersionId = VER_NDX_GLOBAL; return; @@ -2309,14 +2301,14 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. - if (File->VerdefMap.empty()) - Needed.push_back({File, InX::DynStrTab->addString(File->SoName)}); - typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver]; + if (File.VerdefMap.empty()) + Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)}); + typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. if (NV.Index == 0) { - NV.StrTab = InX::DynStrTab->addString(File->getStringTable().data() + + NV.StrTab = InX::DynStrTab->addString(File.getStringTable().data() + Ver->getAux()->vda_name); NV.Index = NextIndex++; } @@ -2561,31 +2553,25 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // The sentinel must have the PREL31 value of an address higher than any // address described by any other table entry. void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { - // The Sections are sorted in order of ascending PREL31 address with the - // sentinel last. We need to find the InputSection that precedes the - // sentinel. - OutputSection *C = getParent(); - InputSection *Highest = nullptr; - unsigned Skip = 1; - for (const BaseCommand *Base : llvm::reverse(C->SectionCommands)) { - if (!isa<InputSectionDescription>(Base)) - continue; - auto L = cast<InputSectionDescription>(Base); - if (Skip >= L->Sections.size()) { - Skip -= L->Sections.size(); - continue; - } - Highest = L->Sections[L->Sections.size() - Skip - 1]; - break; - } assert(Highest); - InputSection *LS = Highest->getLinkOrderDep(); - uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize()); + uint64_t S = + Highest->getParent()->Addr + Highest->getOffset(Highest->getSize()); uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 1); } +// The sentinel has to be removed if there are no other .ARM.exidx entries. +bool ARMExidxSentinelSection::empty() const { + OutputSection *OS = getParent(); + for (auto *B : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) + for (auto *S : ISD->Sections) + if (!isa<ARMExidxSentinelSection>(S)) + return false; + return true; +} + ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { @@ -2655,11 +2641,6 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym); template void PltSection::addEntry<ELF64LE>(Symbol &Sym); template void PltSection::addEntry<ELF64BE>(Symbol &Sym); -template MergeInputSection *elf::createCommentSection<ELF32LE>(); -template MergeInputSection *elf::createCommentSection<ELF32BE>(); -template MergeInputSection *elf::createCommentSection<ELF64LE>(); -template MergeInputSection *elf::createCommentSection<ELF64BE>(); - template class elf::MipsAbiFlagsSection<ELF32LE>; template class elf::MipsAbiFlagsSection<ELF32BE>; template class elf::MipsAbiFlagsSection<ELF64LE>; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 5aaf479f3e35e..a990590513bb9 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -36,7 +36,7 @@ class SyntheticSection : public InputSection { public: SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, StringRef Name) - : InputSection(Flags, Type, Alignment, {}, Name, + : InputSection(nullptr, Flags, Type, Alignment, {}, Name, InputSectionBase::Synthetic) { this->Live = true; } @@ -785,6 +785,9 @@ public: ARMExidxSentinelSection(); size_t getSize() const override { return 8; } void writeTo(uint8_t *Buf) override; + bool empty() const override; + + InputSection *Highest = 0; }; // A container for one or more linker generated thunks. Instances of these @@ -809,12 +812,12 @@ private: }; InputSection *createInterpSection(); -template <class ELFT> MergeInputSection *createCommentSection(); +MergeInputSection *createCommentSection(); void decompressSections(); void mergeSections(); Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase *Section); + uint64_t Size, InputSectionBase &Section); // Linker generated sections which can be used as inputs. struct InX { diff --git a/ELF/Target.cpp b/ELF/Target.cpp index ddd408906d14f..b528fd583c1ae 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -89,7 +89,7 @@ TargetInfo *elf::getTarget() { template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) { for (InputSectionBase *D : InputSections) { - auto *IS = dyn_cast_or_null<InputSection>(D); + auto *IS = dyn_cast<InputSection>(D); if (!IS || !IS->getParent()) continue; diff --git a/ELF/Target.h b/ELF/Target.h index 2902dbc99149c..1f58adba18178 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -40,8 +40,8 @@ public: virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const {} - virtual void addPltHeaderSymbols(InputSectionBase *IS) const {} - virtual void addPltSymbols(InputSectionBase *IS, uint64_t Off) const {} + virtual void addPltHeaderSymbols(InputSection &IS) const {} + virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} // Returns true if a relocation only uses the low bits of a value such that // all those bits are in in the same page. For example, if the relocation diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index 91ca3b9b5bc2c..b0bbf6da705a5 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -164,9 +164,9 @@ void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, &IS); - addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); + addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS); } // This Thunk has a maximum range of 4Gb, this is sufficient for all programs @@ -192,8 +192,8 @@ void AArch64ADRPThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); } // ARM Target Thunks @@ -217,8 +217,8 @@ void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); } bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const { @@ -241,8 +241,8 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), &IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); + Offset | 0x1, size(), IS); + addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); } bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const { @@ -268,8 +268,8 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); } bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const { @@ -295,8 +295,8 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), &IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); + Offset | 0x1, size(), IS); + addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); } bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const { @@ -318,7 +318,7 @@ void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { void MipsThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), &IS); + STT_FUNC, Offset, size(), IS); } InputSection *MipsThunk::getTargetInputSection() const { @@ -342,7 +342,7 @@ void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { void MicroMipsThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), &IS); + STT_FUNC, Offset, size(), IS); ThunkSym->StOther |= STO_MIPS_MICROMIPS; } @@ -367,7 +367,7 @@ void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const { void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), &IS); + STT_FUNC, Offset, size(), IS); ThunkSym->StOther |= STO_MIPS_MICROMIPS; } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index c7a3cae49ae65..15f3821047560 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -54,7 +54,6 @@ private: void resolveShfLinkOrder(); void sortInputSections(); void finalizeSections(); - void addPredefinedSections(); void setReservedSymbolSections(); std::vector<PhdrEntry *> createPhdrs(); @@ -157,35 +156,34 @@ template <class ELFT> static void combineEhFrameSections() { V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } -template <class ELFT> static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) { Symbol *S = Symtab->find(Name); if (!S || S->isDefined()) return nullptr; - Symbol *Sym = Symtab->addRegular<ELFT>(Name, StOther, STT_NOTYPE, Val, - /*Size=*/0, Binding, Sec, - /*File=*/nullptr); + Symbol *Sym = Symtab->addRegular(Name, StOther, STT_NOTYPE, Val, + /*Size=*/0, Binding, Sec, + /*File=*/nullptr); return cast<Defined>(Sym); } // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. -template <class ELFT> void elf::addReservedSymbols() { +void elf::addReservedSymbols() { if (Config->EMachine == EM_MIPS) { // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which by default is relative // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - ElfSym::MipsGp = Symtab->addAbsolute<ELFT>("_gp", STV_HIDDEN, STB_GLOBAL); + ElfSym::MipsGp = Symtab->addAbsolute("_gp", STV_HIDDEN, STB_GLOBAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. if (Symtab->find("_gp_disp")) ElfSym::MipsGpDisp = - Symtab->addAbsolute<ELFT>("_gp_disp", STV_HIDDEN, STB_GLOBAL); + Symtab->addAbsolute("_gp_disp", STV_HIDDEN, STB_GLOBAL); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op @@ -193,10 +191,10 @@ template <class ELFT> void elf::addReservedSymbols() { // https://sourceware.org/ml/binutils/2004-12/msg00094.html if (Symtab->find("__gnu_local_gp")) ElfSym::MipsLocalGp = - Symtab->addAbsolute<ELFT>("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); + Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); } - ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( + ElfSym::GlobalOffsetTable = addOptionalRegular( "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff); // __ehdr_start is the location of ELF file headers. Note that we define @@ -210,14 +208,14 @@ template <class ELFT> void elf::addReservedSymbols() { // different in different DSOs, so we chose the start address of the DSO. for (const char *Name : {"__ehdr_start", "__executable_start", "__dso_handle"}) - addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN); + addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->HasSectionsCommand) return; auto Add = [](StringRef S, int64_t Pos) { - return addOptionalRegular<ELFT>(S, Out::ElfHeader, Pos, STV_DEFAULT); + return addOptionalRegular(S, Out::ElfHeader, Pos, STV_DEFAULT); }; ElfSym::Bss = Add("__bss_start", 0); @@ -390,6 +388,11 @@ template <class ELFT> static void createSyntheticSections() { Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); + + if (Config->EMachine == EM_ARM && !Config->Relocatable) + // Add a sentinel to terminate .ARM.exidx. It helps an unwinder + // to find the exact address range of the last entry. + Add(make<ARMExidxSentinelSection>()); } // The main function of the writer. @@ -830,10 +833,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { if (!Config->Static) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; - addOptionalRegular<ELFT>(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); + addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; - addOptionalRegular<ELFT>(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); + addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); } template <class ELFT> @@ -1145,10 +1148,10 @@ template <class ELFT> void Writer<ELFT>::sortSections() { } static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last + // Synthetic, i. e. a sentinel section, should go last. if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) - return false; + return A->kind() != InputSectionBase::Synthetic; InputSection *LA = A->getLinkOrderDep(); InputSection *LB = B->getLinkOrderDep(); OutputSection *AOut = LA->getParent(); @@ -1231,23 +1234,37 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { } std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); - if (Config->MergeArmExidx && !Config->Relocatable && - Config->EMachine == EM_ARM && Sec->Type == SHT_ARM_EXIDX) { - // The EHABI for the Arm Architecture permits consecutive identical - // table entries to be merged. We use a simple implementation that - // removes a .ARM.exidx Input Section if it can be merged into the - // previous one. This does not require any rewriting of InputSection - // contents but misses opportunities for fine grained deduplication where - // only a subset of the InputSection contents can be merged. - int Cur = 1; - int Prev = 0; - int N = Sections.size(); - while (Cur < N) { - if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) - Sections[Cur] = nullptr; - else - Prev = Cur; - ++Cur; + if (!Config->Relocatable && Config->EMachine == EM_ARM && + Sec->Type == SHT_ARM_EXIDX) { + + if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) { + assert(Sections.size() >= 2 && + "We should create a sentinel section only if there are " + "alive regular exidx sections."); + // The last executable section is required to fill the sentinel. + // Remember it here so that we don't have to find it again. + auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back()); + Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); + } + + if (Config->MergeArmExidx) { + // The EHABI for the Arm Architecture permits consecutive identical + // table entries to be merged. We use a simple implementation that + // removes a .ARM.exidx Input Section if it can be merged into the + // previous one. This does not require any rewriting of InputSection + // contents but misses opportunities for fine grained deduplication + // where only a subset of the InputSection contents can be merged. + int Cur = 1; + int Prev = 0; + // The last one is a sentinel entry which should not be removed. + int N = Sections.size() - 1; + while (Cur < N) { + if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) + Sections[Cur] = nullptr; + else + Prev = Cur; + ++Cur; + } } } @@ -1367,9 +1384,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (InX::DynSymTab) - Symtab->addRegular<ELFT>("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, - /*Size=*/0, STB_WEAK, InX::Dynamic, - /*File=*/nullptr); + Symtab->addRegular("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, + /*Size=*/0, STB_WEAK, InX::Dynamic, + /*File=*/nullptr); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); @@ -1413,7 +1430,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (errorCount()) return; - addPredefinedSections(); removeUnusedSyntheticSections(); sortSections(); @@ -1510,17 +1526,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { [](SyntheticSection *SS) { SS->postThunkContents(); }); } -template <class ELFT> void Writer<ELFT>::addPredefinedSections() { - // ARM ABI requires .ARM.exidx to be terminated by some piece of data. - // We have the terminater synthetic section class. Add that at the end. - OutputSection *Cmd = findSection(".ARM.exidx"); - if (!Cmd || !Cmd->Live || Config->Relocatable) - return; - - auto *Sentinel = make<ARMExidxSentinelSection>(); - Cmd->addSection(Sentinel); -} - // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { @@ -1528,13 +1533,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { // These symbols resolve to the image base if the section does not exist. // A special value -1 indicates end of the section. if (OS) { - addOptionalRegular<ELFT>(Start, OS, 0); - addOptionalRegular<ELFT>(End, OS, -1); + addOptionalRegular(Start, OS, 0); + addOptionalRegular(End, OS, -1); } else { if (Config->Pic) OS = Out::ElfHeader; - addOptionalRegular<ELFT>(Start, OS, 0); - addOptionalRegular<ELFT>(End, OS, 0); + addOptionalRegular(Start, OS, 0); + addOptionalRegular(End, OS, 0); } }; @@ -1556,8 +1561,8 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; - addOptionalRegular<ELFT>(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); - addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); + addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); + addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } static bool needsPtLoad(OutputSection *Sec) { @@ -2057,8 +2062,3 @@ template void elf::writeResult<ELF32LE>(); template void elf::writeResult<ELF32BE>(); template void elf::writeResult<ELF64LE>(); template void elf::writeResult<ELF64BE>(); - -template void elf::addReservedSymbols<ELF32LE>(); -template void elf::addReservedSymbols<ELF32BE>(); -template void elf::addReservedSymbols<ELF64LE>(); -template void elf::addReservedSymbols<ELF64BE>(); diff --git a/ELF/Writer.h b/ELF/Writer.h index 32d3c23047ddd..d247068bab232 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -46,7 +46,7 @@ struct PhdrEntry { bool HasLMA = false; }; -template <class ELFT> void addReservedSymbols(); +void addReservedSymbols(); llvm::StringRef getOutputSectionName(InputSectionBase *S); template <class ELFT> uint32_t calcMipsEFlags(); |