diff options
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/Driver.cpp | 3 | ||||
-rw-r--r-- | ELF/Error.cpp | 4 | ||||
-rw-r--r-- | ELF/Error.h | 7 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 4 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 73 | ||||
-rw-r--r-- | ELF/InputSection.h | 10 | ||||
-rw-r--r-- | ELF/LinkerScript.cpp | 33 | ||||
-rw-r--r-- | ELF/OutputSections.cpp | 7 | ||||
-rw-r--r-- | ELF/OutputSections.h | 2 | ||||
-rw-r--r-- | ELF/Relocations.cpp | 34 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 30 | ||||
-rw-r--r-- | ELF/Symbols.cpp | 32 | ||||
-rw-r--r-- | ELF/Symbols.h | 12 | ||||
-rw-r--r-- | ELF/SyntheticSections.cpp | 33 | ||||
-rw-r--r-- | ELF/Target.cpp | 22 | ||||
-rw-r--r-- | ELF/Writer.cpp | 63 |
16 files changed, 192 insertions, 177 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index c8ea821ec522..b4544d78f725 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -24,6 +24,7 @@ #include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Object/Decompressor.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" @@ -815,7 +816,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { [](InputSectionBase<ELFT> *S) { if (!S->Live) return; - if (S->isCompressed()) + if (Decompressor::isCompressedELFSection(S->Flags, S->Name)) S->uncompress(); if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) MS->splitIntoPieces(); diff --git a/ELF/Error.cpp b/ELF/Error.cpp index 6e30f08143ed..d9b41f9c599e 100644 --- a/ELF/Error.cpp +++ b/ELF/Error.cpp @@ -103,4 +103,8 @@ void elf::fatal(std::error_code EC, const Twine &Prefix) { fatal(Prefix + ": " + EC.message()); } +void elf::fatal(Error &E, const Twine &Prefix) { + fatal(Prefix + ": " + llvm::toString(std::move(E))); +} + } // namespace lld diff --git a/ELF/Error.h b/ELF/Error.h index 1ec683595cf4..f18cf456da6d 100644 --- a/ELF/Error.h +++ b/ELF/Error.h @@ -44,6 +44,7 @@ void error(std::error_code EC, const Twine &Prefix); LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); +LLVM_ATTRIBUTE_NORETURN void fatal(Error &E, const Twine &Prefix); // check() functions are convenient functions to strip errors // from error-or-value objects. @@ -55,11 +56,7 @@ template <class T> T check(ErrorOr<T> E) { template <class T> T check(Expected<T> E) { if (!E) - handleAllErrors(std::move(E.takeError()), - [](llvm::ErrorInfoBase &EIB) -> Error { - fatal(EIB.message()); - return Error::success(); - }); + fatal(llvm::toString(E.takeError())); return std::move(*E); } diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 1fddf40f5b22..f3afb1c34562 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -857,8 +857,8 @@ template <class ELFT> void BinaryFile::parse() { StringRef EndName = Saver.save(Twine(Filename) + "_end"); StringRef SizeName = Saver.save(Twine(Filename) + "_size"); - auto *Section = - make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 8, Data, ".data"); + auto *Section = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + 8, Data, ".data"); Sections.push_back(Section); elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0, diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index e87d92aa207c..358004248373 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -19,6 +19,7 @@ #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> @@ -35,7 +36,10 @@ using namespace lld::elf; // Returns a string to construct an error message. template <class ELFT> std::string lld::toString(const InputSectionBase<ELFT> *Sec) { - return (Sec->getFile()->getName() + ":(" + Sec->Name + ")").str(); + // 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> @@ -102,11 +106,6 @@ template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const { return Data.size(); } -// Returns a string for an error message. -template <class SectionT> static std::string getName(SectionT *Sec) { - return (Sec->getFile()->getName() + ":(" + Sec->Name + ")").str(); -} - template <class ELFT> typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { switch (kind()) { @@ -128,71 +127,23 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { llvm_unreachable("invalid section kind"); } -template <class ELFT> bool InputSectionBase<ELFT>::isCompressed() const { - return (Flags & SHF_COMPRESSED) || Name.startswith(".zdebug"); -} - -// Returns compressed data and its size when uncompressed. -template <class ELFT> -std::pair<ArrayRef<uint8_t>, uint64_t> -InputSectionBase<ELFT>::getElfCompressedData(ArrayRef<uint8_t> Data) { - // Compressed section with Elf_Chdr is the ELF standard. - if (Data.size() < sizeof(Elf_Chdr)) - fatal(toString(this) + ": corrupted compressed section"); - auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data()); - if (Hdr->ch_type != ELFCOMPRESS_ZLIB) - fatal(toString(this) + ": unsupported compression type"); - return {Data.slice(sizeof(*Hdr)), Hdr->ch_size}; -} - -// Returns compressed data and its size when uncompressed. -template <class ELFT> -std::pair<ArrayRef<uint8_t>, uint64_t> -InputSectionBase<ELFT>::getRawCompressedData(ArrayRef<uint8_t> Data) { - // Compressed sections without Elf_Chdr header contain this header - // instead. This is a GNU extension. - struct ZlibHeader { - char Magic[4]; // Should be "ZLIB" - char Size[8]; // Uncompressed size in big-endian - }; - - if (Data.size() < sizeof(ZlibHeader)) - fatal(toString(this) + ": corrupted compressed section"); - auto *Hdr = reinterpret_cast<const ZlibHeader *>(Data.data()); - if (memcmp(Hdr->Magic, "ZLIB", 4)) - fatal(toString(this) + ": broken ZLIB-compressed section"); - return {Data.slice(sizeof(*Hdr)), read64be(Hdr->Size)}; -} - // 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(toString(this) + - ": build lld with zlib to enable compressed sections support"); - - // This section is compressed. Here we decompress it. Ideally, all - // compressed sections have SHF_COMPRESSED bit and their contents - // start with headers of Elf_Chdr type. However, sections whose - // names start with ".zdebug_" don't have the bit and contains a raw - // ZLIB-compressed data (which is a bad thing because section names - // shouldn't be significant in ELF.) We need to be able to read both. - ArrayRef<uint8_t> Buf; // Compressed data - size_t Size; // Uncompressed size - if (Flags & SHF_COMPRESSED) - std::tie(Buf, Size) = getElfCompressedData(Data); - else - std::tie(Buf, Size) = getRawCompressedData(Data); + Decompressor Decompressor = check(Decompressor::create( + Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little, + ELFT::Is64Bits)); - // Uncompress Buf. + size_t Size = Decompressor.getDecompressedSize(); char *OutputBuf; { static std::mutex Mu; std::lock_guard<std::mutex> Lock(Mu); OutputBuf = BAlloc.Allocate<char>(Size); } - if (zlib::uncompress(toStringRef(Buf), OutputBuf, Size) != zlib::StatusOK) - fatal(toString(this) + ": error while uncompressing section"); + + if (Error E = Decompressor.decompress({OutputBuf, Size})) + fatal(E, toString(this)); Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); } diff --git a/ELF/InputSection.h b/ELF/InputSection.h index fc7a7fb60973..3f3a055dcc33 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -138,22 +138,12 @@ public: // section. uintX_t getOffset(uintX_t Offset) const; - // ELF supports ZLIB-compressed section. - // Returns true if the section is compressed. - bool isCompressed() const; void uncompress(); // Returns a source location string. Used to construct an error message. std::string getLocation(uintX_t Offset); void relocate(uint8_t *Buf, uint8_t *BufEnd); - -private: - std::pair<ArrayRef<uint8_t>, uint64_t> - getElfCompressedData(ArrayRef<uint8_t> Data); - - std::pair<ArrayRef<uint8_t>, uint64_t> - getRawCompressedData(ArrayRef<uint8_t> Data); }; // SectionPiece represents a piece of splittable section contents. diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 59ef36c87de5..887ca12537ad 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -1014,6 +1014,7 @@ private: void readAnonymousDeclaration(); void readVersionDeclaration(StringRef VerStr); std::vector<SymbolVersion> readSymbols(); + void readLocals(); ScriptConfiguration &Opt = *ScriptConfig; bool IsUnderSysroot; @@ -1861,17 +1862,22 @@ void ScriptParser::readAnonymousDeclaration() { if (consume("global:") || peek() != "local:") Config->VersionScriptGlobals = readSymbols(); - // Next, read local symbols. - if (consume("local:")) { - if (consume("*")) { + readLocals(); + expect("}"); + expect(";"); +} + +void ScriptParser::readLocals() { + if (!consume("local:")) + return; + std::vector<SymbolVersion> Locals = readSymbols(); + for (SymbolVersion V : Locals) { + if (V.Name == "*") { Config->DefaultSymbolVersion = VER_NDX_LOCAL; - expect(";"); - } else { - setError("local symbol list for anonymous version is not supported"); + continue; } + Config->VersionScriptLocals.push_back(V); } - expect("}"); - expect(";"); } // Reads a list of symbols, e.g. "VerStr { global: foo; bar; local: *; };". @@ -1885,16 +1891,7 @@ void ScriptParser::readVersionDeclaration(StringRef VerStr) { if (consume("global:") || peek() != "local:") Config->VersionDefinitions.back().Globals = readSymbols(); - // Read local symbols. - if (consume("local:")) { - if (consume("*")) { - Config->DefaultSymbolVersion = VER_NDX_LOCAL; - expect(";"); - } else { - for (SymbolVersion V : readSymbols()) - Config->VersionScriptLocals.push_back(V); - } - } + readLocals(); expect("}"); // Each version may have a parent version. For example, "Ver2" diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index a9d951dcc745..7c708ce4ed67 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -636,7 +636,12 @@ OutputSectionFactory<ELFT>::create(const SectionKey &Key, if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags)) error("Section has flags incompatible with others with the same name " + toString(C)); - if (Sec->Type != C->Type) + // Convert notbits to progbits if they are mixed. This happens is some + // linker scripts. + if (Sec->Type == SHT_NOBITS && C->Type == SHT_PROGBITS) + Sec->Type = SHT_PROGBITS; + if (Sec->Type != C->Type && + !(Sec->Type == SHT_PROGBITS && C->Type == SHT_NOBITS)) error("Section has different type from others with the same name " + toString(C)); Sec->Flags |= Flags; diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 45e1a232e2a9..5c494bba977a 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -206,6 +206,7 @@ template <class ELFT> struct Out { static uint8_t First; static EhOutputSection<ELFT> *EhFrame; static OutputSection<ELFT> *Bss; + static OutputSection<ELFT> *BssRelRo; static OutputSectionBase *Opd; static uint8_t *OpdBuf; static PhdrEntry *TlsPhdr; @@ -252,6 +253,7 @@ template <class ELFT> uint64_t getHeaderSize() { template <class ELFT> uint8_t Out<ELFT>::First; template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame; template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss; +template <class ELFT> OutputSection<ELFT> *Out<ELFT>::BssRelRo; template <class ELFT> OutputSectionBase *Out<ELFT>::Opd; template <class ELFT> uint8_t *Out<ELFT>::OpdBuf; template <class ELFT> PhdrEntry *Out<ELFT>::TlsPhdr; diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index f7dcc5d24e93..cecd11e90790 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -399,7 +399,21 @@ template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) { return 1 << TrailingZeros; } -// Reserve space in .bss for copy relocation. +template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) { + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Phdr Elf_Phdr; + + // Determine if the symbol is read-only by scanning the DSO's program headers. + uintX_t Value = SS->Sym.st_value; + for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers())) + if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && + !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr && + Value < Phdr.p_vaddr + Phdr.p_memsz) + return true; + return false; +} + +// Reserve space in .bss or .bss.rel.ro for copy relocation. template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { typedef typename ELFT::uint uintX_t; typedef typename ELFT::Sym Elf_Sym; @@ -409,10 +423,16 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { if (SymSize == 0) fatal("cannot create a copy relocation for symbol " + toString(*SS)); + // See if this symbol is in a read-only segment. If so, preserve the symbol's + // memory protection by reserving space in the .bss.rel.ro section. + bool IsReadOnly = isReadOnly(SS); + OutputSection<ELFT> *CopySec = + IsReadOnly ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss; + uintX_t Alignment = getAlignment(SS); - uintX_t Off = alignTo(Out<ELFT>::Bss->Size, Alignment); - Out<ELFT>::Bss->Size = Off + SymSize; - Out<ELFT>::Bss->updateAlignment(Alignment); + uintX_t Off = alignTo(CopySec->Size, Alignment); + CopySec->Size = Off + SymSize; + CopySec->updateAlignment(Alignment); uintX_t Shndx = SS->Sym.st_shndx; uintX_t Value = SS->Sym.st_value; // Look through the DSO's dynamic symbol table for aliases and create a @@ -425,12 +445,12 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) { Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable())))); if (!Alias) continue; - Alias->OffsetInBss = Off; + Alias->CopyIsInBssRelRo = IsReadOnly; + Alias->CopyOffset = Off; Alias->NeedsCopyOrPltAddr = true; Alias->symbol()->IsUsedInRegularObj = true; } - In<ELFT>::RelaDyn->addReloc( - {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0}); + In<ELFT>::RelaDyn->addReloc({Target->CopyRel, CopySec, Off, false, SS, 0}); } template <class ELFT> diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index f08fa6229c1a..6afe3dde9bab 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -605,19 +605,16 @@ SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) { // If there's only one anonymous version definition in a version // script file, the script does not actually define any symbol version, -// but just specifies symbols visibilities. We assume that the script was -// in the form of { global: foo; bar; local *; }. So, local is default. -// In this function, we make specified symbols global. +// but just specifies symbols visibilities. template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() { - for (SymbolVersion &Ver : Config->VersionScriptGlobals) { - if (Ver.HasWildcard) { - for (SymbolBody *B : findAllByVersion(Ver)) - B->symbol()->VersionId = VER_NDX_GLOBAL; - continue; - } - for (SymbolBody *B : findByVersion(Ver)) - B->symbol()->VersionId = VER_NDX_GLOBAL; - } + for (SymbolVersion &Ver : Config->VersionScriptGlobals) + assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); + for (SymbolVersion &Ver : Config->VersionScriptGlobals) + assignWildcardVersion(Ver, VER_NDX_GLOBAL); + for (SymbolVersion &Ver : Config->VersionScriptLocals) + assignExactVersion(Ver, VER_NDX_LOCAL, "local"); + for (SymbolVersion &Ver : Config->VersionScriptLocals) + assignWildcardVersion(Ver, VER_NDX_LOCAL); } // Set symbol versions to symbols. This function handles patterns @@ -673,10 +670,7 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { Sym->body()->parseSymbolVersion(); // Handle edge cases first. - if (!Config->VersionScriptGlobals.empty()) { - handleAnonymousVersion(); - return; - } + handleAnonymousVersion(); if (Config->VersionDefinitions.empty()) return; @@ -687,8 +681,6 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { // First, we assign versions to exact matching symbols, // i.e. version definitions not containing any glob meta-characters. - for (SymbolVersion &Ver : Config->VersionScriptLocals) - assignExactVersion(Ver, VER_NDX_LOCAL, "local"); for (VersionDefinition &V : Config->VersionDefinitions) for (SymbolVersion &Ver : V.Globals) assignExactVersion(Ver, V.Id, V.Name); @@ -697,8 +689,6 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { // i.e. version definitions containing glob meta-characters. // Note that because the last match takes precedence over previous matches, // we iterate over the definitions in the reverse order. - for (SymbolVersion &Ver : Config->VersionScriptLocals) - assignWildcardVersion(Ver, VER_NDX_LOCAL); for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) for (SymbolVersion &Ver : V.Globals) assignWildcardVersion(Ver, V.Id); diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index f3edafaf4b78..289bc18487a8 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -81,7 +81,7 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body, return 0; if (SS.isFunc()) return Body.getPltVA<ELFT>(); - return Out<ELFT>::Bss->Addr + SS.OffsetInBss; + return SS.getBssSectionForCopy()->Addr + SS.CopyOffset; } case SymbolBody::UndefinedKind: return 0; @@ -97,7 +97,8 @@ SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} + IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther), + Name(Name) {} // Returns true if a symbol can be replaced at load-time by a symbol // with the same name defined in other ELF executable or DSO. @@ -245,6 +246,12 @@ Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, this->File = File; } +template <typename ELFT> +OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const { + assert(needsCopy()); + return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss; +} + DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File) : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, @@ -287,10 +294,22 @@ InputFile *LazyObject::fetch() { return createObjectFile(MBRef); } -bool Symbol::includeInDynsym() const { +uint8_t Symbol::computeBinding() const { + if (Config->Relocatable) + return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) + return STB_LOCAL; + if (VersionId == VER_NDX_LOCAL && !body()->isUndefined()) + return STB_LOCAL; + if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) + return STB_GLOBAL; + return Binding; +} + +bool Symbol::includeInDynsym() const { + if (computeBinding() == STB_LOCAL) return false; - return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() || + return ExportDynamic || body()->isShared() || (body()->isUndefined() && Config->Shared); } @@ -366,6 +385,11 @@ template class elf::Undefined<ELF32BE>; template class elf::Undefined<ELF64LE>; template class elf::Undefined<ELF64BE>; +template class elf::SharedSymbol<ELF32LE>; +template class elf::SharedSymbol<ELF32BE>; +template class elf::SharedSymbol<ELF64LE>; +template class elf::SharedSymbol<ELF64BE>; + template class elf::DefinedRegular<ELF32LE>; template class elf::DefinedRegular<ELF32BE>; template class elf::DefinedRegular<ELF64LE>; diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 38889571679c..af85dc2b121d 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -123,6 +123,11 @@ public: // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; + // True if this is a shared symbol in a read-only segment which requires a + // copy relocation. This causes space for the symbol to be allocated in the + // .bss.rel.ro section. + unsigned CopyIsInBssRelRo : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value @@ -282,13 +287,15 @@ public: // This field is a pointer to the symbol's version definition. const Elf_Verdef *Verdef; - // OffsetInBss is significant only when needsCopy() is true. - uintX_t OffsetInBss = 0; + // CopyOffset is significant only when needsCopy() is true. + uintX_t CopyOffset = 0; // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. Thunk<ELFT> *ThunkData = nullptr; bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); } + + OutputSection<ELFT> *getBssSectionForCopy() const; }; // This class represents a symbol defined in an archive file. It is @@ -413,6 +420,7 @@ struct Symbol { unsigned InVersionScript : 1; bool includeInDynsym() const; + uint8_t computeBinding() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } // This field is used to store the Symbol's SymbolBody. This instantiation of diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 3c8a439ba308..5486b38eec10 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1060,18 +1060,6 @@ static bool sortMipsSymbols(const SymbolBody *L, const SymbolBody *R) { return L->GotIndex < R->GotIndex; } -static uint8_t getSymbolBinding(SymbolBody *Body) { - Symbol *S = Body->symbol(); - if (Config->Relocatable) - return S->Binding; - uint8_t Visibility = S->Visibility; - if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) - return STB_LOCAL; - if (Config->NoGnuUnique && S->Binding == STB_GNU_UNIQUE) - return STB_GLOBAL; - return S->Binding; -} - template <class ELFT> void SymbolTableSection<ELFT>::finalize() { this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; this->OutSec->Info = this->Info = NumLocals + 1; @@ -1085,11 +1073,12 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() { } if (!StrTabSec.isDynamic()) { - std::stable_sort(Symbols.begin(), Symbols.end(), - [](const SymbolTableEntry &L, const SymbolTableEntry &R) { - return getSymbolBinding(L.Symbol) == STB_LOCAL && - getSymbolBinding(R.Symbol) != STB_LOCAL; - }); + std::stable_sort( + Symbols.begin(), Symbols.end(), + [](const SymbolTableEntry &L, const SymbolTableEntry &R) { + return L.Symbol->symbol()->computeBinding() == STB_LOCAL && + R.Symbol->symbol()->computeBinding() != STB_LOCAL; + }); return; } if (In<ELFT>::GnuHashTab) @@ -1159,7 +1148,7 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) { uint8_t Type = Body->Type; uintX_t Size = Body->getSize<ELFT>(); - ESym->setBindingAndType(getSymbolBinding(Body), Type); + ESym->setBindingAndType(Body->symbol()->computeBinding(), Type); ESym->st_size = Size; ESym->st_name = StrOff; ESym->setVisibility(Body->symbol()->Visibility); @@ -1201,10 +1190,12 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) { } case SymbolBody::DefinedCommonKind: return In<ELFT>::Common->OutSec; - case SymbolBody::SharedKind: - if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy()) - return Out<ELFT>::Bss; + case SymbolBody::SharedKind: { + auto &SS = cast<SharedSymbol<ELFT>>(*Sym); + if (SS.needsCopy()) + return SS.getBssSectionForCopy(); break; + } case SymbolBody::UndefinedKind: case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: diff --git a/ELF/Target.cpp b/ELF/Target.cpp index cb2b178fa849..55fcf1734d1f 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -356,7 +356,9 @@ X86TargetInfo::X86TargetInfo() { RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { switch (Type) { - default: + case R_386_16: + case R_386_32: + case R_386_TLS_LDO_32: return R_ABS; case R_386_TLS_GD: return R_TLSGD; @@ -381,6 +383,12 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const { return R_TLS; case R_386_TLS_LE_32: return R_NEG_TLS; + case R_386_NONE: + return R_HINT; + default: + error("do not know how to handle relocation '" + toString(Type) + "' (" + + Twine(Type) + ")"); + return R_HINT; } } @@ -623,7 +631,11 @@ template <class ELFT> RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S) const { switch (Type) { - default: + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_64: + case R_X86_64_DTPOFF32: + case R_X86_64_DTPOFF64: return R_ABS; case R_X86_64_TPOFF32: return R_TLS; @@ -649,6 +661,10 @@ RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, return R_GOT_PC; case R_X86_64_NONE: return R_HINT; + default: + error("do not know how to handle relocation '" + toString(Type) + "' (" + + Twine(Type) + ")"); + return R_HINT; } } @@ -870,7 +886,7 @@ void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, write64le(Loc, Val); break; default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + llvm_unreachable("unexpected relocation"); } } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 154de8cf6d18..bddc42e1acf9 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -250,6 +250,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { // Create singleton output sections. Out<ELFT>::Bss = make<OutputSection<ELFT>>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); + Out<ELFT>::BssRelRo = make<OutputSection<ELFT>>(".bss.rel.ro", SHT_NOBITS, + SHF_ALLOC | SHF_WRITE); In<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true); In<ELFT>::Dynamic = make<DynamicSection<ELFT>>(); Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>(); @@ -498,6 +500,8 @@ template <class ELFT> bool elf::isRelroSection(const OutputSectionBase *Sec) { return true; if (In<ELFT>::MipsGot && Sec == In<ELFT>::MipsGot->OutSec) return true; + if (Sec == Out<ELFT>::BssRelRo) + return true; StringRef S = Sec->getName(); return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || S == ".eh_frame" || S == ".openbsd.randomdata"; @@ -557,30 +561,38 @@ static bool compareSectionsNonScript(const OutputSectionBase *A, // If we got here we know that both A and B are in the same PT_LOAD. - // The TLS initialization block needs to be a single contiguous block in a R/W - // PT_LOAD, so stick TLS sections directly before R/W sections. The TLS NOBITS - // sections are placed here as they don't take up virtual address space in the - // PT_LOAD. bool AIsTls = A->Flags & SHF_TLS; bool BIsTls = B->Flags & SHF_TLS; - if (AIsTls != BIsTls) - return AIsTls; - - // The next requirement we have is to put nobits sections last. The - // reason is that the only thing the dynamic linker will see about - // them is a p_memsz that is larger than p_filesz. Seeing that it - // zeros the end of the PT_LOAD, so that has to correspond to the - // nobits sections. bool AIsNoBits = A->Type == SHT_NOBITS; bool BIsNoBits = B->Type == SHT_NOBITS; - if (AIsNoBits != BIsNoBits) - return BIsNoBits; - // We place RelRo section before plain r/w ones. + // The first requirement we have is to put (non-TLS) nobits sections last. The + // reason is that the only thing the dynamic linker will see about them is a + // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the + // PT_LOAD, so that has to correspond to the nobits sections. + bool AIsNonTlsNoBits = AIsNoBits && !AIsTls; + bool BIsNonTlsNoBits = BIsNoBits && !BIsTls; + if (AIsNonTlsNoBits != BIsNonTlsNoBits) + return BIsNonTlsNoBits; + + // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo + // sections after r/w ones, so that the RelRo sections are contiguous. bool AIsRelRo = isRelroSection<ELFT>(A); bool BIsRelRo = isRelroSection<ELFT>(B); if (AIsRelRo != BIsRelRo) - return AIsRelRo; + return AIsNonTlsNoBits ? AIsRelRo : BIsRelRo; + + // The TLS initialization block needs to be a single contiguous block in a R/W + // PT_LOAD, so stick TLS sections directly before the other RelRo R/W + // sections. The TLS NOBITS sections are placed here as they don't take up + // virtual address space in the PT_LOAD. + if (AIsTls != BIsTls) + return AIsTls; + + // Within the TLS initialization block, the non-nobits sections need to appear + // first. + if (AIsNoBits != BIsNoBits) + return BIsNoBits; // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. @@ -1071,6 +1083,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { template <class ELFT> void Writer<ELFT>::addPredefinedSections() { if (Out<ELFT>::Bss->Size > 0) OutputSections.push_back(Out<ELFT>::Bss); + if (Out<ELFT>::BssRelRo->Size > 0) + OutputSections.push_back(Out<ELFT>::BssRelRo); auto OS = dyn_cast_or_null<OutputSection<ELFT>>(findSection(".ARM.exidx")); if (OS && !OS->Sections.empty() && !Config->Relocatable) @@ -1272,8 +1286,9 @@ void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) { Phdrs.push_back(ARMExidx); } -// The first section of each PT_LOAD and the first section after PT_GNU_RELRO -// have to be page aligned so that the dynamic linker can set the permissions. +// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the +// first section after PT_GNU_RELRO have to be page aligned so that the dynamic +// linker can set the permissions. template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { for (const PhdrEntry &P : Phdrs) if (P.p_type == PT_LOAD && P.First) @@ -1282,6 +1297,8 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { for (const PhdrEntry &P : Phdrs) { if (P.p_type != PT_GNU_RELRO) continue; + if (P.First) + P.First->PageAlign = true; // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we // have to align it to a page. auto End = OutputSections.end(); @@ -1635,10 +1652,12 @@ static void unlinkAsync(StringRef Path) { // Path as a new file. If we do that in a different thread, the new // thread can remove the new file. SmallString<128> TempPath; - if (auto EC = sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) - fatal(EC, "createUniqueFile failed"); - if (auto EC = sys::fs::rename(Path, TempPath)) - fatal(EC, "rename failed"); + if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) + return; + if (sys::fs::rename(Path, TempPath)) { + sys::fs::remove(TempPath); + return; + } // Remove TempPath in background. std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); |