diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-26 20:33:45 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-26 20:33:45 +0000 |
commit | 4ea16835ba66f2240d050ffcaee44cee6c97cab9 (patch) | |
tree | d2f3d66f3352a3ec22362de0b7a5c1366fc25df8 /ELF | |
parent | 15f7a1a3796209b21af2817fdf11ca9932165c70 (diff) | |
download | src-4ea16835ba66f2240d050ffcaee44cee6c97cab9.tar.gz src-4ea16835ba66f2240d050ffcaee44cee6c97cab9.zip |
Vendor import of lld trunk r306325:vendor/lld/lld-trunk-r306325
Notes
Notes:
svn path=/vendor/lld/dist/; revision=320382
svn path=/vendor/lld/lld-trunk-r306325/; revision=320383; tag=vendor/lld/lld-trunk-r306325
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/Arch/AArch64.cpp | 6 | ||||
-rw-r--r-- | ELF/Arch/AMDGPU.cpp | 6 | ||||
-rw-r--r-- | ELF/Arch/ARM.cpp | 7 | ||||
-rw-r--r-- | ELF/Arch/AVR.cpp | 6 | ||||
-rw-r--r-- | ELF/Arch/Mips.cpp | 15 | ||||
-rw-r--r-- | ELF/Arch/MipsArchTree.cpp (renamed from ELF/Mips.cpp) | 2 | ||||
-rw-r--r-- | ELF/Arch/PPC.cpp | 8 | ||||
-rw-r--r-- | ELF/Arch/PPC64.cpp | 6 | ||||
-rw-r--r-- | ELF/Arch/X86.cpp | 11 | ||||
-rw-r--r-- | ELF/Arch/X86_64.cpp | 17 | ||||
-rw-r--r-- | ELF/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ELF/Config.h | 2 | ||||
-rw-r--r-- | ELF/Driver.cpp | 53 | ||||
-rw-r--r-- | ELF/Driver.h | 2 | ||||
-rw-r--r-- | ELF/DriverUtils.cpp | 6 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 3 | ||||
-rw-r--r-- | ELF/InputFiles.h | 2 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 27 | ||||
-rw-r--r-- | ELF/LinkerScript.cpp | 36 | ||||
-rw-r--r-- | ELF/MarkLive.cpp | 2 | ||||
-rw-r--r-- | ELF/Options.td | 4 | ||||
-rw-r--r-- | ELF/OutputSections.cpp | 4 | ||||
-rw-r--r-- | ELF/Relocations.cpp | 2 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 35 | ||||
-rw-r--r-- | ELF/SymbolTable.h | 2 | ||||
-rw-r--r-- | ELF/Symbols.cpp | 1 | ||||
-rw-r--r-- | ELF/Symbols.h | 6 | ||||
-rw-r--r-- | ELF/Target.cpp | 28 | ||||
-rw-r--r-- | ELF/Target.h | 26 | ||||
-rw-r--r-- | ELF/Writer.cpp | 31 |
30 files changed, 240 insertions, 118 deletions
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp index 113d0960d5f5..b26cf0815109 100644 --- a/ELF/Arch/AArch64.cpp +++ b/ELF/Arch/AArch64.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -371,4 +370,7 @@ void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); } -TargetInfo *elf::createAArch64TargetInfo() { return make<AArch64>(); } +TargetInfo *elf::getAArch64TargetInfo() { + static AArch64 Target; + return &Target; +} diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp index 68e516f9e6cf..de566c617ac0 100644 --- a/ELF/Arch/AMDGPU.cpp +++ b/ELF/Arch/AMDGPU.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "Target.h" #include "llvm/Object/ELF.h" @@ -79,4 +78,7 @@ RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S, } } -TargetInfo *elf::createAMDGPUTargetInfo() { return make<AMDGPU>(); } +TargetInfo *elf::getAMDGPUTargetInfo() { + static AMDGPU Target; + return &Target; +} diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp index b245cbd7005a..e4b06ade4487 100644 --- a/ELF/Arch/ARM.cpp +++ b/ELF/Arch/ARM.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -58,6 +57,7 @@ ARM::ARM() { GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 20; + TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; @@ -429,4 +429,7 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { } } -TargetInfo *elf::createARMTargetInfo() { return make<ARM>(); } +TargetInfo *elf::getARMTargetInfo() { + static ARM Target; + return &Target; +} diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp index 86343a6faa16..3853248f8fbd 100644 --- a/ELF/Arch/AVR.cpp +++ b/ELF/Arch/AVR.cpp @@ -28,7 +28,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "Target.h" #include "llvm/Object/ELF.h" @@ -75,4 +74,7 @@ void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -TargetInfo *elf::createAVRTargetInfo() { return make<AVR>(); } +TargetInfo *elf::getAVRTargetInfo() { + static AVR Target; + return &Target; +} diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp index 79642df8a885..b8d796f5897a 100644 --- a/ELF/Arch/Mips.cpp +++ b/ELF/Arch/Mips.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -55,6 +54,7 @@ template <class ELFT> MIPS<ELFT>::MIPS() { CopyRel = R_MIPS_COPY; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; + TrapInstr = 0xefefefef; if (ELFT::Is64Bits) { RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; @@ -412,11 +412,12 @@ bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; } -template <class ELFT> TargetInfo *elf::createMipsTargetInfo() { - return make<MIPS<ELFT>>(); +template <class ELFT> TargetInfo *elf::getMipsTargetInfo() { + static MIPS<ELFT> Target; + return &Target; } -template TargetInfo *elf::createMipsTargetInfo<ELF32LE>(); -template TargetInfo *elf::createMipsTargetInfo<ELF32BE>(); -template TargetInfo *elf::createMipsTargetInfo<ELF64LE>(); -template TargetInfo *elf::createMipsTargetInfo<ELF64BE>(); +template TargetInfo *elf::getMipsTargetInfo<ELF32LE>(); +template TargetInfo *elf::getMipsTargetInfo<ELF32BE>(); +template TargetInfo *elf::getMipsTargetInfo<ELF64LE>(); +template TargetInfo *elf::getMipsTargetInfo<ELF64BE>(); diff --git a/ELF/Mips.cpp b/ELF/Arch/MipsArchTree.cpp index af92fb9d24fd..ed183e9a3061 100644 --- a/ELF/Mips.cpp +++ b/ELF/Arch/MipsArchTree.cpp @@ -1,4 +1,4 @@ -//===- Mips.cpp ----------------------------------------------------------===// +//===- MipsArchTree.cpp --------------------------------------------------===// // // The LLVM Linker // diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp index b5f0d5b4c687..19e10729a00e 100644 --- a/ELF/Arch/PPC.cpp +++ b/ELF/Arch/PPC.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "Target.h" #include "llvm/Support/Endian.h" @@ -22,7 +21,7 @@ using namespace lld::elf; namespace { class PPC final : public TargetInfo { public: - PPC() {} + PPC() { GotBaseSymOff = 0x8000; } void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; @@ -60,4 +59,7 @@ RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S, } } -TargetInfo *elf::createPPCTargetInfo() { return make<PPC>(); } +TargetInfo *elf::getPPCTargetInfo() { + static PPC Target; + return &Target; +} diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp index eb1e917d5790..bf414d75bec7 100644 --- a/ELF/Arch/PPC64.cpp +++ b/ELF/Arch/PPC64.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -212,4 +211,7 @@ void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -TargetInfo *elf::createPPC64TargetInfo() { return make<PPC64>(); } +TargetInfo *elf::getPPC64TargetInfo() { + static PPC64 Target; + return &Target; +} diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp index bc0d2b81a613..a1e9bcaf1b12 100644 --- a/ELF/Arch/X86.cpp +++ b/ELF/Arch/X86.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -47,6 +46,7 @@ public: } // namespace X86::X86() { + GotBaseSymOff = -1; CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; @@ -60,9 +60,7 @@ X86::X86() { PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; - - // 0xCC is the "int3" (call debug exception handler) instruction. - TrapInstr = 0xcccccccc; + TrapInstr = 0xcccccccc; // 0xcc = INT3 } RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S, @@ -360,4 +358,7 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { memcpy(Loc - 2, Inst, sizeof(Inst)); } -TargetInfo *elf::createX86TargetInfo() { return make<X86>(); } +TargetInfo *elf::getX86TargetInfo() { + static X86 Target; + return &Target; +} diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp index b790868c7125..10179f57ee93 100644 --- a/ELF/Arch/X86_64.cpp +++ b/ELF/Arch/X86_64.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -52,6 +51,7 @@ private: } // namespace template <class ELFT> X86_64<ELFT>::X86_64() { + GotBaseSymOff = -1; CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; @@ -65,13 +65,11 @@ template <class ELFT> X86_64<ELFT>::X86_64() { PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; + TrapInstr = 0xcccccccc; // 0xcc = INT3 // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x200000; - - // 0xCC is the "int3" (call debug exception handler) instruction. - TrapInstr = 0xcccccccc; } template <class ELFT> @@ -464,5 +462,12 @@ void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const { write32le(Loc - 1, Val + 1); } -TargetInfo *elf::createX32TargetInfo() { return make<X86_64<ELF32LE>>(); } -TargetInfo *elf::createX86_64TargetInfo() { return make<X86_64<ELF64LE>>(); } +TargetInfo *elf::getX32TargetInfo() { + static X86_64<ELF32LE> Target; + return &Target; +} + +TargetInfo *elf::getX86_64TargetInfo() { + static X86_64<ELF64LE> Target; + return &Target; +} diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 09a19fee14b2..b4bc215a77eb 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -12,6 +12,7 @@ add_lld_library(lldELF Arch/ARM.cpp Arch/AVR.cpp Arch/Mips.cpp + Arch/MipsArchTree.cpp Arch/PPC.cpp Arch/PPC64.cpp Arch/X86.cpp @@ -29,7 +30,6 @@ add_lld_library(lldELF LinkerScript.cpp MapFile.cpp MarkLive.cpp - Mips.cpp OutputSections.cpp Relocations.cpp ScriptLexer.cpp diff --git a/ELF/Config.h b/ELF/Config.h index 9c73b4c9c068..32e86b0ec7b6 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -70,7 +70,7 @@ struct VersionDefinition { // Structure for mapping renamed symbols struct RenamedSymbol { Symbol *Target; - uint8_t OrigBinding; + uint8_t OriginalBinding; }; // This struct contains the global configuration for the linker. diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index f24c941fe773..5fb33caea46f 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -200,6 +200,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { error("attempted static link of dynamic object " + Path); return; } + // DSOs usually have DT_SONAME tags in their ELF headers, and the // sonames are used to identify DSOs. But if they are missing, // they are identified by filenames. We don't know whether the new @@ -210,8 +211,8 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. - Files.push_back(createSharedFile( - MBRef, WithLOption ? sys::path::filename(Path) : Path)); + Files.push_back( + createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); return; default: if (InLib) @@ -301,7 +302,7 @@ static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, for (auto *Arg : Args.filtered(OPT_z)) { std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('='); if (KV.first == Key) { - uint64_t Result; + uint64_t Result = Default; if (!to_integer(KV.second, Result)) error("invalid " + Key + ": " + KV.second); return Result; @@ -907,12 +908,47 @@ getDefsym(opt::InputArgList &Args) { return Ret; } +// Parses `--exclude-libs=lib,lib,...`. +// The library names may be delimited by commas or colons. +static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { + DenseSet<StringRef> Ret; + for (auto *Arg : Args.filtered(OPT_exclude_libs)) { + StringRef S = Arg->getValue(); + for (;;) { + size_t Pos = S.find_first_of(",:"); + if (Pos == StringRef::npos) + break; + Ret.insert(S.substr(0, Pos)); + S = S.substr(Pos + 1); + } + Ret.insert(S); + } + return Ret; +} + +// Handles the -exclude-libs option. If a static library file is specified +// by the -exclude-libs option, all public symbols from the archive become +// private unless otherwise specified by version scripts or something. +// A special library name "ALL" means all archive files. +// +// This is not a popular option, but some programs such as bionic libc use it. +static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) { + DenseSet<StringRef> Libs = getExcludeLibs(Args); + bool All = Libs.count("ALL"); + + for (InputFile *File : Files) + if (auto *F = dyn_cast<ArchiveFile>(File)) + if (All || Libs.count(path::filename(F->getName()))) + for (Symbol *Sym : F->getSymbols()) + Sym->VersionId = VER_NDX_LOCAL; +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable<ELFT> Symtab; elf::Symtab<ELFT>::X = &Symtab; - Target = createTarget(); + Target = getTarget(); Config->MaxPageSize = getMaxPageSize(Args); Config->ImageBase = getImageBase(Args); @@ -958,8 +994,17 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { if (ErrorCount) return; + // Handle the `--undefined <sym>` options. Symtab.scanUndefinedFlags(); + + // Handle undefined symbols in DSOs. Symtab.scanShlibUndefined(); + + // Handle the -exclude-libs option. + if (Args.hasArg(OPT_exclude_libs)) + excludeLibs(Args, Files); + + // Apply version scripts. Symtab.scanVersionScript(); // Create wrapped symbols for -wrap option. diff --git a/ELF/Driver.h b/ELF/Driver.h index af88341632f4..076dda7730ac 100644 --- a/ELF/Driver.h +++ b/ELF/Driver.h @@ -58,7 +58,7 @@ public: // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp index f4eadeee9e43..5adb09176a3a 100644 --- a/ELF/DriverUtils.cpp +++ b/ELF/DriverUtils.cpp @@ -42,9 +42,9 @@ using namespace lld::elf; // Create table mapping all options defined in Options.td static const opt::OptTable::Info OptInfo[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \ - X8, X7, OPT_##GROUP, OPT_##ALIAS, X6}, +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ + {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ + X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, #include "Options.inc" #undef OPTION }; diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 3d11239bf88f..1ff0b4224e70 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -632,8 +632,9 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) File(std::move(File)) {} template <class ELFT> void ArchiveFile::parse() { + Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symtab<ELFT>::X->addLazyArchive(this, Sym); + Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 2eec78444837..544a0b009b39 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -251,6 +251,7 @@ public: explicit ArchiveFile(std::unique_ptr<Archive> &&File); static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template <class ELFT> void parse(); + ArrayRef<Symbol *> getSymbols() { return Symbols; } // Returns a memory buffer for a given symbol and the offset in the archive // for the member. An empty memory buffer and an offset of zero @@ -261,6 +262,7 @@ public: private: std::unique_ptr<Archive> File; llvm::DenseSet<uint64_t> Seen; + std::vector<Symbol *> Symbols; }; class BitcodeFile : public InputFile { diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 9aae82bc2992..b1d5e1349460 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -399,9 +399,16 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { } } +// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak +// references specially. The general rule is that the value of the symbol in +// this context is the address of the place P. A further special case is that +// branch relocations to an undefined weak reference resolve to the next +// instruction. static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, uint32_t P) { switch (Type) { + // Unresolved branch relocations to weak references resolve to next + // instruction, this will be either 2 or 4 bytes on from P. case R_ARM_THM_JUMP11: return P + 2 + A; case R_ARM_CALL: @@ -415,22 +422,38 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, case R_ARM_THM_CALL: // We don't want an interworking BLX to ARM return P + 5 + A; - default: + // Unresolved non branch pc-relative relocations + // R_ARM_TARGET2 which can be resolved relatively is not present as it never + // targets a weak-reference. + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_REL32: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: return P + A; } + llvm_unreachable("ARM pc-relative relocation expected\n"); } +// The comment above getARMUndefinedRelativeWeakVA applies to this function. static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, uint64_t P) { switch (Type) { + // Unresolved branch relocations to weak references resolve to next + // instruction, this is 4 bytes on from P. case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return P + 4 + A; - default: + // Unresolved non branch pc-relative relocations + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + case R_AARCH64_ADR_PREL_LO21: return P + A; } + llvm_unreachable("AArch64 pc-relative relocation expected\n"); } // ARM SBREL relocations are of the form S + A - B where B is the static base diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index f5a59f0c8c4d..d369a6f978a2 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -338,8 +338,9 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { void LinkerScript::discard(ArrayRef<InputSectionBase *> V) { for (InputSectionBase *S : V) { S->Live = false; - if (S == InX::ShStrTab) - error("discarding .shstrtab section is not allowed"); + if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || + S == InX::DynStrTab) + error("discarding " + S->Name + " section is not allowed"); discard(S->DependentSections); } } @@ -463,11 +464,6 @@ void LinkerScript::fabricateDefaultCommands() { OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; - // Prefer user supplied address over additional alignment constraint - auto I = Config->SectionStartMap.find(Sec->Name); - if (I != Config->SectionStartMap.end()) - OSCmd->AddrExpr = [=] { return I->second; }; - Commands.push_back(OSCmd); if (Sec->Sections.size()) { auto *ISD = make<InputSectionDescription>(""); @@ -953,6 +949,8 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) { template <class ELFT> static void finalizeShtGroup(OutputSection *OS, ArrayRef<InputSection *> Sections) { + assert(Config->Relocatable && Sections.size() == 1); + // sh_link field for SHT_GROUP sections should contain the section index of // the symbol table. OS->Link = InX::SymTab->getParent()->SectionIndex; @@ -960,7 +958,6 @@ static void finalizeShtGroup(OutputSection *OS, // sh_info then contain index of an entry in symbol table section which // provides signature of the section group. elf::ObjectFile<ELFT> *Obj = Sections[0]->getFile<ELFT>(); - assert(Config->Relocatable && Sections.size() == 1); ArrayRef<SymbolBody *> Symbols = Obj->getSymbols(); OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); } @@ -1044,8 +1041,9 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { Sec->Loc = Buf; - // We may have already rendered compressed content when using - // -compress-debug-sections option. Write it together with header. + // If -compress-debug-section is specified and if this is a debug seciton, + // we've already compressed section contents. If that's the case, + // just write it down. if (!Sec->CompressedData.empty()) { memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), @@ -1109,18 +1107,27 @@ ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } +static const size_t NoPhdr = -1; + // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Sec) { if (OutputSectionCommand *Cmd = getCmd(Sec)) { std::vector<size_t> Ret; - for (StringRef PhdrName : Cmd->Phdrs) - Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName)); + for (StringRef PhdrName : Cmd->Phdrs) { + size_t Index = getPhdrIndex(Cmd->Location, PhdrName); + if (Index != NoPhdr) + Ret.push_back(Index); + } return Ret; } return {}; } +// Returns the index of the segment named PhdrName if found otherwise +// NoPhdr. When not found, if PhdrName is not the special case value 'NONE' +// (which can be used to explicitly specify that a section isn't assigned to a +// segment) then error. size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { size_t I = 0; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { @@ -1128,8 +1135,9 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { return I; ++I; } - error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); - return 0; + if (PhdrName != "NONE") + error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); + return NoPhdr; } template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf); diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index 0b4a78f8da6b..bde3eefc6d5f 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -78,7 +78,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, typename ELFT::uint Offset = D->Value; if (D->isSection()) Offset += getAddend<ELFT>(Sec, Rel); - Fn({cast<InputSectionBase>(D->Section)->Repl, Offset}); + Fn({cast<InputSectionBase>(D->Section), Offset}); } else if (auto *U = dyn_cast<Undefined>(&B)) { for (InputSectionBase *Sec : CNamedSections.lookup(U->getName())) Fn({Sec, 0}); diff --git a/ELF/Options.td b/ELF/Options.td index 335c7ade6db2..29e14c530c6a 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -92,6 +92,9 @@ def error_limit: S<"error-limit">, def error_unresolved_symbols: F<"error-unresolved-symbols">, HelpText<"Report unresolved symbols as errors">; +def exclude_libs: S<"exclude-libs">, + HelpText<"Exclude static libraries from automatic export">; + def export_dynamic: F<"export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; @@ -298,6 +301,7 @@ def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>; def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; def alias_entry_entry: J<"entry=">, Alias<entry>; def alias_error_limit: J<"error-limit=">, Alias<error_limit>; +def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>; def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>; def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, Alias<export_dynamic_symbol>; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 6f04a04be8d0..c0bf6b32e6e2 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -273,7 +273,7 @@ void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; message("removing unused section from '" + IS->Name + "' in file '" + - IS->File->getName()); + IS->File->getName() + "'"); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, @@ -305,7 +305,7 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; - return addInputSec(IS, OutsecName, Sec); + addInputSec(IS, OutsecName, Sec); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 1ac3bce769ee..fd823fe0ed42 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -361,7 +361,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, // These expressions always compute a constant if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, - R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, + R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD, R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) return true; diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index a223aec98624..ab8802c86d8e 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -167,8 +167,8 @@ template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) { // Tell LTO not to eliminate this symbol Wrap->IsUsedInRegularObj = true; - Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding}; - Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding}; + Config->RenamedSymbols[Real] = {Sym, Real->Binding}; + Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding}; } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. @@ -184,7 +184,7 @@ template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, // Tell LTO not to eliminate this symbol Sym->IsUsedInRegularObj = true; - Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding}; + Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding}; } // Apply symbol renames created by -wrap and -defsym. The renames are created @@ -193,14 +193,16 @@ template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, // symbols are finalized, we can perform the replacement. template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() { for (auto &KV : Config->RenamedSymbols) { - Symbol *Sym = KV.first; - Symbol *Rename = KV.second.Target; - Sym->Binding = KV.second.OrigBinding; - - // We rename symbols by replacing the old symbol's SymbolBody with the new - // symbol's SymbolBody. This causes all SymbolBody pointers referring to the - // old symbol to instead refer to the new symbol. - memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body)); + Symbol *Dst = KV.first; + Symbol *Src = KV.second.Target; + Dst->Binding = KV.second.OriginalBinding; + + // We rename symbols by replacing the old symbol's SymbolBody with + // the new symbol's SymbolBody. The only attribute we want to keep + // is the symbol name, so that two symbols don't have the same name. + StringRef S = Dst->body()->getName(); + memcpy(Dst->Body.buffer, Src->Body.buffer, sizeof(Symbol::Body)); + Dst->body()->setName(S); } } @@ -518,18 +520,18 @@ SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) { } template <class ELFT> -void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, - const object::Archive::Symbol Sym) { +Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, + const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; StringRef Name = Sym.getName(); std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType); - return; + return S; } if (!S->body()->isUndefined()) - return; + return S; // Weak undefined symbols should not fetch members from archives. If we were // to keep old symbol we would not know that an archive member was available @@ -540,11 +542,12 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, // to preserve its type. FIXME: Move the Type field to Symbol. if (S->isWeak()) { replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type); - return; + return S; } std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); + return S; } template <class ELFT> diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index f38d09760c7e..316d9c9bf373 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -66,7 +66,7 @@ public: void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef); - void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); + Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); void addLazyObject(StringRef Name, LazyObjectFile &Obj); Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 8f9b20477b29..5dce71a32c9c 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -35,6 +35,7 @@ DefinedRegular *ElfSym::Edata1; DefinedRegular *ElfSym::Edata2; DefinedRegular *ElfSym::End1; DefinedRegular *ElfSym::End2; +DefinedRegular *ElfSym::GlobalOffsetTable; DefinedRegular *ElfSym::MipsGp; DefinedRegular *ElfSym::MipsGpDisp; DefinedRegular *ElfSym::MipsLocalGp; diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 030527f63744..406fd8e0f57b 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -69,6 +69,7 @@ public: bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } + void setName(StringRef S) { Name = S; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); @@ -317,6 +318,11 @@ struct ElfSym { static DefinedRegular *End1; static DefinedRegular *End2; + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to + // be at some offset from the base of the .got section, usually 0 or + // the end of the .got. + static DefinedRegular *GlobalOffsetTable; + // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS. static DefinedRegular *MipsGp; static DefinedRegular *MipsGpDisp; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index df3f4d6773f0..c1a85e165258 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -47,40 +47,40 @@ std::string lld::toString(uint32_t Type) { return S; } -TargetInfo *elf::createTarget() { +TargetInfo *elf::getTarget() { switch (Config->EMachine) { case EM_386: case EM_IAMCU: - return createX86TargetInfo(); + return getX86TargetInfo(); case EM_AARCH64: - return createAArch64TargetInfo(); + return getAArch64TargetInfo(); case EM_AMDGPU: - return createAMDGPUTargetInfo(); + return getAMDGPUTargetInfo(); case EM_ARM: - return createARMTargetInfo(); + return getARMTargetInfo(); case EM_AVR: - return createAVRTargetInfo(); + return getAVRTargetInfo(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: - return createMipsTargetInfo<ELF32LE>(); + return getMipsTargetInfo<ELF32LE>(); case ELF32BEKind: - return createMipsTargetInfo<ELF32BE>(); + return getMipsTargetInfo<ELF32BE>(); case ELF64LEKind: - return createMipsTargetInfo<ELF64LE>(); + return getMipsTargetInfo<ELF64LE>(); case ELF64BEKind: - return createMipsTargetInfo<ELF64BE>(); + return getMipsTargetInfo<ELF64BE>(); default: fatal("unsupported MIPS target"); } case EM_PPC: - return createPPCTargetInfo(); + return getPPCTargetInfo(); case EM_PPC64: - return createPPC64TargetInfo(); + return getPPC64TargetInfo(); case EM_X86_64: if (Config->EKind == ELF32LEKind) - return createX32TargetInfo(); - return createX86_64TargetInfo(); + return getX32TargetInfo(); + return getX86_64TargetInfo(); } fatal("unknown target machine"); } diff --git a/ELF/Target.h b/ELF/Target.h index 79b03f876d0d..bf703fd0086a 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -66,6 +66,10 @@ public: // Given that, the smallest value that can be used in here is 0x10000. uint64_t DefaultImageBase = 0x10000; + // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for + // end of .got + uint64_t GotBaseSymOff = 0; + uint32_t CopyRel; uint32_t GotRel; uint32_t PltRel; @@ -102,16 +106,16 @@ public: virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; }; -TargetInfo *createAArch64TargetInfo(); -TargetInfo *createAMDGPUTargetInfo(); -TargetInfo *createARMTargetInfo(); -TargetInfo *createAVRTargetInfo(); -TargetInfo *createPPC64TargetInfo(); -TargetInfo *createPPCTargetInfo(); -TargetInfo *createX32TargetInfo(); -TargetInfo *createX86TargetInfo(); -TargetInfo *createX86_64TargetInfo(); -template <class ELFT> TargetInfo *createMipsTargetInfo(); +TargetInfo *getAArch64TargetInfo(); +TargetInfo *getAMDGPUTargetInfo(); +TargetInfo *getARMTargetInfo(); +TargetInfo *getAVRTargetInfo(); +TargetInfo *getPPC64TargetInfo(); +TargetInfo *getPPCTargetInfo(); +TargetInfo *getX32TargetInfo(); +TargetInfo *getX86TargetInfo(); +TargetInfo *getX86_64TargetInfo(); +template <class ELFT> TargetInfo *getMipsTargetInfo(); std::string getErrorLocation(const uint8_t *Loc); @@ -119,7 +123,7 @@ uint64_t getPPC64TocBase(); uint64_t getAArch64Page(uint64_t Expr); extern TargetInfo *Target; -TargetInfo *createTarget(); +TargetInfo *getTarget(); template <unsigned N> static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) { diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 4ff06388ec78..4c12b18836bf 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -87,6 +87,8 @@ private: uint64_t FileSize; uint64_t SectionHeaderOff; + + bool HasGotBaseSym = false; }; } // anonymous namespace @@ -815,19 +817,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } - // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol - // is magical and is used to produce a R_386_GOTPC relocation. - // The R_386_GOTPC relocation value doesn't actually depend on the - // symbol value, so it could use an index of STN_UNDEF which, according - // to the spec, means the symbol value is 0. - // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in - // the object file. - // The situation is even stranger on x86_64 where the assembly doesn't - // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as - // an undefined symbol in the .o files. - // Given that the symbol is effectively unused, we just create a dummy - // hidden one to avoid the undefined symbol error. - Symtab<ELFT>::X->addIgnored("_GLOBAL_OFFSET_TABLE_"); + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to + // be at some offset from the base of the .got section, usually 0 or the end + // of the .got + InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) + : cast<InputSection>(InX::Got); + ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( + "_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to @@ -1147,6 +1143,8 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { OutputSection *OS = SS->getParent(); if (!SS->empty() || !OS) continue; + if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable) + continue; OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); SS->Live = false; // If there are no other sections in the output section, remove it from the @@ -1231,6 +1229,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) OutputSectionCommands.push_back(Cmd); + // Prefer command line supplied address over other constraints. + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + auto I = Config->SectionStartMap.find(Cmd->Name); + if (I != Config->SectionStartMap.end()) + Cmd->AddrExpr = [=] { return I->second; }; + } + // This is a bit of a hack. A value of 0 means undef, so we set it // to 1 t make __ehdr_start defined. The section number is not // particularly relevant. |