summaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Driver.cpp3
-rw-r--r--ELF/Error.cpp4
-rw-r--r--ELF/Error.h7
-rw-r--r--ELF/InputFiles.cpp4
-rw-r--r--ELF/InputSection.cpp73
-rw-r--r--ELF/InputSection.h10
-rw-r--r--ELF/LinkerScript.cpp33
-rw-r--r--ELF/OutputSections.cpp7
-rw-r--r--ELF/OutputSections.h2
-rw-r--r--ELF/Relocations.cpp34
-rw-r--r--ELF/SymbolTable.cpp30
-rw-r--r--ELF/Symbols.cpp32
-rw-r--r--ELF/Symbols.h12
-rw-r--r--ELF/SyntheticSections.cpp33
-rw-r--r--ELF/Target.cpp22
-rw-r--r--ELF/Writer.cpp63
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();