diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-13 20:06:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-13 20:06:04 +0000 |
commit | b289257c7f3ed78b7d3971c596d7c60a9050c705 (patch) | |
tree | d6b57e29a5a86347a020d6f0cae76cc2d0f3bf8d /ELF | |
parent | fba2c04f31e119eacf142fcbbaabd5a9e63a39ed (diff) | |
download | src-b289257c7f3ed78b7d3971c596d7c60a9050c705.tar.gz src-b289257c7f3ed78b7d3971c596d7c60a9050c705.zip |
Vendor import of lld trunk r257626:vendor/lld/lld-trunk-r257626
Notes
Notes:
svn path=/vendor/lld/dist/; revision=293846
svn path=/vendor/lld/lld-trunk-r257626/; revision=293847; tag=vendor/lld/lld-trunk-r257626
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ELF/Driver.cpp | 62 | ||||
-rw-r--r-- | ELF/Driver.h | 8 | ||||
-rw-r--r-- | ELF/DriverUtils.cpp | 10 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 15 | ||||
-rw-r--r-- | ELF/InputFiles.h | 7 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 33 | ||||
-rw-r--r-- | ELF/InputSection.h | 9 | ||||
-rw-r--r-- | ELF/LinkerScript.cpp | 2 | ||||
-rw-r--r-- | ELF/MarkLive.cpp | 15 | ||||
-rw-r--r-- | ELF/Options.td | 4 | ||||
-rw-r--r-- | ELF/OutputSections.cpp | 174 | ||||
-rw-r--r-- | ELF/OutputSections.h | 23 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 49 | ||||
-rw-r--r-- | ELF/SymbolTable.h | 28 | ||||
-rw-r--r-- | ELF/Symbols.cpp | 24 | ||||
-rw-r--r-- | ELF/Symbols.h | 11 | ||||
-rw-r--r-- | ELF/Target.cpp | 178 | ||||
-rw-r--r-- | ELF/Target.h | 10 | ||||
-rw-r--r-- | ELF/Writer.cpp | 124 |
20 files changed, 515 insertions, 273 deletions
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 763275e30caa..3dcb65ff8957 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -2,7 +2,7 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(ELFOptionsTableGen) -add_llvm_library(lldELF2 +add_lld_library(lldELF2 Driver.cpp DriverUtils.cpp Error.cpp diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 2a3ecfa61586..f00d97851e4a 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -26,10 +26,10 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf2; -Configuration *lld::elf2::Config; -LinkerDriver *lld::elf2::Driver; +Configuration *elf2::Config; +LinkerDriver *elf2::Driver; -void lld::elf2::link(ArrayRef<const char *> Args) { +void elf2::link(ArrayRef<const char *> Args) { Configuration C; LinkerDriver D; Config = &C; @@ -42,9 +42,9 @@ static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) { return {ELF32BEKind, EM_MIPS}; if (S == "elf32ltsmip") return {ELF32LEKind, EM_MIPS}; - if (S == "elf32ppc") + if (S == "elf32ppc" || S == "elf32ppc_fbsd") return {ELF32BEKind, EM_PPC}; - if (S == "elf64ppc") + if (S == "elf64ppc" || S == "elf64ppc_fbsd") return {ELF64BEKind, EM_PPC64}; if (S == "elf_i386") return {ELF32LEKind, EM_386}; @@ -107,6 +107,24 @@ void LinkerDriver::addFile(StringRef Path) { } } +// Some command line options or some combinations of them are not allowed. +// This function checks for such errors. +static void checkOptions(opt::InputArgList &Args) { + // Traditional linkers can generate re-linkable object files instead + // of executables or DSOs. We don't support that since the feature + // does not seem to provide more value than the static archiver. + if (Args.hasArg(OPT_relocatable)) + error("-r option is not supported. Use 'ar' command instead."); + + // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup + // table which is a relatively new feature. + if (Config->EMachine == EM_MIPS && Config->GnuHash) + error("The .gnu.hash section is not compatible with the MIPS target."); + + if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) + error("-e option is not valid for AMDGPU."); +} + static StringRef getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { if (auto *Arg = Args.getLastArg(Key)) @@ -125,13 +143,9 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { initSymbols(); opt::InputArgList Args = parseArgs(&Alloc, ArgsArr); + readConfigs(Args); createFiles(Args); - - // Traditional linkers can generate re-linkable object files instead - // of executables or DSOs. We don't support that since the feature - // does not seem to provide more value than the static archiver. - if (Args.hasArg(OPT_relocatable)) - error("-r option is not supported. Use 'ar' command instead."); + checkOptions(Args); switch (Config->EKind) { case ELF32LEKind: @@ -151,7 +165,8 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { } } -void LinkerDriver::createFiles(opt::InputArgList &Args) { +// Initializes Config members by the command line options. +void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) Config->SearchPaths.push_back(Arg->getValue()); @@ -162,10 +177,9 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); if (auto *Arg = Args.getLastArg(OPT_m)) { + // Parse ELF{32,64}{LE,BE} and CPU type. StringRef S = Arg->getValue(); - std::pair<ELFKind, uint16_t> P = parseEmulation(S); - Config->EKind = P.first; - Config->EMachine = P.second; + std::tie(Config->EKind, Config->EMachine) = parseEmulation(S); Config->Emulation = S; } @@ -217,7 +231,9 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); +} +void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_l: @@ -250,9 +266,6 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { if (Files.empty()) error("no input files."); - - if (Config->GnuHash && Config->EMachine == EM_MIPS) - error("The .gnu.hash section is not compatible with the MIPS target."); } template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { @@ -261,7 +274,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { if (!Config->Shared) { // Add entry symbol. - if (Config->Entry.empty()) + // + // There is no entry symbol for AMDGPU binaries, so skip adding one to avoid + // having and undefined symbol. + if (Config->Entry.empty() && Config->EMachine != EM_AMDGPU) Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol @@ -288,8 +304,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { if (Config->EMachine == EM_MIPS) { // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between - // start of function and gp pointer into GOT. - Config->MipsGpDisp = Symtab.addIgnored("_gp_disp"); + // start of function and gp pointer into GOT. Use 'strong' variant of + // the addIgnored to prevent '_gp_disp' substitution. + Config->MipsGpDisp = Symtab.addIgnoredStrong("_gp_disp"); // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which is relative to GOT. @@ -304,6 +321,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { for (StringRef S : Config->Undefined) Symtab.addUndefinedOpt(S); + for (auto *Arg : Args.filtered(OPT_wrap)) + Symtab.wrap(Arg->getValue()); + if (Config->OutputFile.empty()) Config->OutputFile = "a.out"; diff --git a/ELF/Driver.h b/ELF/Driver.h index bfae2b3f4dfa..720ef46dc710 100644 --- a/ELF/Driver.h +++ b/ELF/Driver.h @@ -26,14 +26,12 @@ void link(ArrayRef<const char *> Args); class LinkerDriver { public: void main(ArrayRef<const char *> Args); - void createFiles(llvm::opt::InputArgList &Args); - template <class ELFT> void link(llvm::opt::InputArgList &Args); - void addFile(StringRef Path); private: - template <template <class> class T> - std::unique_ptr<InputFile> createELFInputFile(MemoryBufferRef MB); + void readConfigs(llvm::opt::InputArgList &Args); + void createFiles(llvm::opt::InputArgList &Args); + template <class ELFT> void link(llvm::opt::InputArgList &Args); llvm::BumpPtrAllocator Alloc; bool WholeArchive = false; diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp index 51b500bebf49..965ed4f00a61 100644 --- a/ELF/DriverUtils.cpp +++ b/ELF/DriverUtils.cpp @@ -51,8 +51,8 @@ public: }; // Parses a given list of options. -opt::InputArgList lld::elf2::parseArgs(llvm::BumpPtrAllocator *A, - ArrayRef<const char *> Argv) { +opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A, + ArrayRef<const char *> Argv) { // Make InputArgList from string vectors. ELFOptTable Table; unsigned MissingIndex; @@ -79,7 +79,7 @@ opt::InputArgList lld::elf2::parseArgs(llvm::BumpPtrAllocator *A, return Args; } -std::string lld::elf2::findFromSearchPaths(StringRef Path) { +std::string elf2::findFromSearchPaths(StringRef Path) { for (StringRef Dir : Config->SearchPaths) { std::string FullPath = buildSysrootedPath(Dir, Path); if (sys::fs::exists(FullPath)) @@ -90,7 +90,7 @@ std::string lld::elf2::findFromSearchPaths(StringRef Path) { // Searches a given library from input search paths, which are filled // from -L command line switches. Returns a path to an existent library file. -std::string lld::elf2::searchLibrary(StringRef Path) { +std::string elf2::searchLibrary(StringRef Path) { std::vector<std::string> Names; if (Path[0] == ':') { Names.push_back(Path.drop_front()); @@ -110,7 +110,7 @@ std::string lld::elf2::searchLibrary(StringRef Path) { // Makes a path by concatenating Dir and File. // If Dir starts with '=' the result will be preceded by Sysroot, // which can be set with --sysroot command line switch. -std::string lld::elf2::buildSysrootedPath(StringRef Dir, StringRef File) { +std::string elf2::buildSysrootedPath(StringRef Dir, StringRef File) { SmallString<128> Path; if (Dir.startswith("=")) sys::path::append(Path, Config->Sysroot, Dir.substr(1), File); diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index d9df6abbf233..6a908d450f60 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -92,7 +92,9 @@ typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() { } template <class ELFT> uint32_t ObjectFile<ELFT>::getMipsGp0() const { - return MipsReginfo ? MipsReginfo->getGp0() : 0; + if (MipsReginfo) + return MipsReginfo->Reginfo->ri_gp_value; + return 0; } template <class ELFT> @@ -132,13 +134,13 @@ StringRef ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) { } template <class ELFT> -ArrayRef<typename ObjectFile<ELFT>::GroupEntryType> +ArrayRef<typename ObjectFile<ELFT>::uint32_X> ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->ELFObj; - ErrorOr<ArrayRef<GroupEntryType>> EntriesOrErr = - Obj.template getSectionContentsAsArray<GroupEntryType>(&Sec); + ErrorOr<ArrayRef<uint32_X>> EntriesOrErr = + Obj.template getSectionContentsAsArray<uint32_X>(&Sec); error(EntriesOrErr); - ArrayRef<GroupEntryType> Entries = *EntriesOrErr; + ArrayRef<uint32_X> Entries = *EntriesOrErr; if (Entries.empty() || Entries[0] != GRP_COMDAT) error("Unsupported SHT_GROUP format"); return Entries.slice(1); @@ -187,8 +189,7 @@ void ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &ComdatGroups) { Sections[I] = &InputSection<ELFT>::Discarded; if (ComdatGroups.insert(getShtGroupSignature(Sec)).second) continue; - for (GroupEntryType E : getShtGroupEntries(Sec)) { - uint32_t SecIndex = E; + for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) error("Invalid section index in group"); Sections[SecIndex] = &InputSection<ELFT>::Discarded; diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 9c54a9328f80..45d403c0125c 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -91,10 +91,13 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> { typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + // uint32 in ELFT's byte order typedef llvm::support::detail::packed_endian_specific_integral< - uint32_t, ELFT::TargetEndianness, 2> GroupEntryType; + uint32_t, ELFT::TargetEndianness, 2> + uint32_X; + StringRef getShtGroupSignature(const Elf_Shdr &Sec); - ArrayRef<GroupEntryType> getShtGroupEntries(const Elf_Shdr &Sec); + ArrayRef<uint32_X> getShtGroupEntries(const Elf_Shdr &Sec); public: static bool classof(const InputFile *F) { diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 2548200feb65..f6aa51b47b98 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -52,7 +52,9 @@ InputSectionBase<ELFT>::getOffset(uintX_t Offset) { case Merge: return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset); case MipsReginfo: - return cast<MipsReginfoInputSection<ELFT>>(this)->getOffset(Offset); + // MIPS .reginfo sections are consumed by the linker, + // so it should never be copied to output. + llvm_unreachable("MIPS .reginfo reached writeTo()."); } llvm_unreachable("Invalid section kind"); } @@ -209,7 +211,6 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd, uintX_t SymVA = getSymVA<ELFT>(*Body); if (Target->relocNeedsPlt(Type, *Body)) { SymVA = Out<ELFT>::Plt->getEntryAddr(*Body); - Type = Target->getPltRefReloc(Type); } else if (Target->relocNeedsGot(Type, *Body)) { SymVA = Out<ELFT>::Got->getEntryAddr(*Body); if (Body->isTls()) @@ -217,8 +218,13 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd, } else if (!Target->needsCopyRel(Type, *Body) && isa<SharedSymbol<ELFT>>(*Body)) { continue; - } else if (Target->isTlsDynReloc(Type, *Body) || - Target->isSizeDynReloc(Type, *Body)) { + } else if (Target->isTlsDynReloc(Type, *Body)) { + continue; + } else if (Target->isSizeReloc(Type) && canBePreempted(Body, false)) { + // A SIZE relocation is supposed to set a symbol size, but if a symbol + // can be preempted, the size at runtime may be different than link time. + // If that's the case, we leave the field alone rather than filling it + // with a possibly incorrect value. continue; } else if (Config->EMachine == EM_MIPS) { if (Type == R_MIPS_HI16 && Body == Config->MipsGpDisp) @@ -346,22 +352,13 @@ MergeInputSection<ELFT>::getOffset(uintX_t Offset) { template <class ELFT> MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(ObjectFile<ELFT> *F, - const Elf_Shdr *Header) - : InputSectionBase<ELFT>(F, Header, InputSectionBase<ELFT>::MipsReginfo) {} - -template <class ELFT> -uint32_t MipsReginfoInputSection<ELFT>::getGeneralMask() const { - ArrayRef<uint8_t> D = this->getSectionData(); - if (D.size() != sizeof(Elf_Mips_RegInfo)) - error("Invalid size of .reginfo section"); - return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gprmask; -} - -template <class ELFT> uint32_t MipsReginfoInputSection<ELFT>::getGp0() const { + const Elf_Shdr *Hdr) + : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) { + // Initialize this->Reginfo. ArrayRef<uint8_t> D = this->getSectionData(); - if (D.size() != sizeof(Elf_Mips_RegInfo)) + if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) error("Invalid size of .reginfo section"); - return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gp_value; + Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data()); } template <class ELFT> diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 24491a2e17c0..26956c72a960 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -177,16 +177,13 @@ public: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf template <class ELFT> class MipsReginfoInputSection : public InputSectionBase<ELFT> { - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; public: - MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); - - uint32_t getGeneralMask() const; - uint32_t getGp0() const; - + MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr); static bool classof(const InputSectionBase<ELFT> *S); + + const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo; }; } // namespace elf2 diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 883b623f9e2c..a6df9ed48cdc 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -312,7 +312,7 @@ static bool isUnderSysroot(StringRef Path) { } // Entry point. The other functions or classes are private to this file. -void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) { +void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) { StringRef Path = MB.getBufferIdentifier(); LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run(); } diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index b719b1a09c25..f682f3b8b473 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -79,7 +79,7 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) { // This is the main function of the garbage collector. // Starting from GC-root sections, this function visits all reachable // sections to set their "Live" bits. -template <class ELFT> void lld::elf2::markLive(SymbolTable<ELFT> *Symtab) { +template <class ELFT> void elf2::markLive(SymbolTable<ELFT> *Symtab) { SmallVector<InputSection<ELFT> *, 256> Q; auto Enqueue = [&](InputSectionBase<ELFT> *Sec) { @@ -116,16 +116,15 @@ template <class ELFT> void lld::elf2::markLive(SymbolTable<ELFT> *Symtab) { // Preserve special sections. for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab->getObjectFiles()) for (InputSectionBase<ELFT> *Sec : F->getSections()) - if (Sec && Sec != &InputSection<ELFT>::Discarded) - if (isReserved(Sec)) - Enqueue(Sec); + if (Sec && Sec != &InputSection<ELFT>::Discarded && isReserved(Sec)) + Enqueue(Sec); // Mark all reachable sections. while (!Q.empty()) forEachSuccessor<ELFT>(Q.pop_back_val(), Enqueue); } -template void lld::elf2::markLive<ELF32LE>(SymbolTable<ELF32LE> *); -template void lld::elf2::markLive<ELF32BE>(SymbolTable<ELF32BE> *); -template void lld::elf2::markLive<ELF64LE>(SymbolTable<ELF64LE> *); -template void lld::elf2::markLive<ELF64BE>(SymbolTable<ELF64BE> *); +template void elf2::markLive<ELF32LE>(SymbolTable<ELF32LE> *); +template void elf2::markLive<ELF32BE>(SymbolTable<ELF32BE> *); +template void elf2::markLive<ELF64LE>(SymbolTable<ELF64LE> *); +template void elf2::markLive<ELF64BE>(SymbolTable<ELF64BE> *); diff --git a/ELF/Options.td b/ELF/Options.td index 622cbb93bf11..1b02c5c8b795 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -109,6 +109,9 @@ def verbose : Flag<["--"], "verbose">; def whole_archive : Flag<["--", "-"], "whole-archive">, HelpText<"Force load of all members in a static library">; +def wrap : Separate<["--", "-"], "wrap">, MetaVarName<"<symbol>">, + HelpText<"Use wrapper functions for symbol">; + def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; @@ -136,6 +139,7 @@ def alias_soname_soname : Separate<["-"], "soname">, Alias<soname>; def alias_script_T : Separate<["-"], "T">, Alias<script>; def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>; def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>; +def alias_wrap_wrap : Joined<["--", "-"], "wrap=">, Alias<wrap>; // Our symbol resolution algorithm handles symbols in archive files differently // than traditional linkers, so we don't need --start-group and --end-group. diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 30ec83f4d3b1..2aa814524d6b 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -21,21 +21,20 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf2; -bool lld::elf2::HasGotOffRel = false; +bool elf2::HasGotOffRel = false; template <class ELFT> -OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t sh_type, - uintX_t sh_flags) +OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type, + uintX_t Flags) : Name(Name) { memset(&Header, 0, sizeof(Elf_Shdr)); - Header.sh_type = sh_type; - Header.sh_flags = sh_flags; + Header.sh_type = Type; + Header.sh_flags = Flags; } template <class ELFT> GotPltSection<ELFT>::GotPltSection() - : OutputSectionBase<ELFT>(".got.plt", llvm::ELF::SHT_PROGBITS, - llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE) { + : OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { this->Header.sh_addralign = sizeof(uintX_t); } @@ -70,10 +69,9 @@ template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) { template <class ELFT> GotSection<ELFT>::GotSection() - : OutputSectionBase<ELFT>(".got", llvm::ELF::SHT_PROGBITS, - llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE) { + : OutputSectionBase<ELFT>(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { if (Config->EMachine == EM_MIPS) - this->Header.sh_flags |= llvm::ELF::SHF_MIPS_GPREL; + this->Header.sh_flags |= SHF_MIPS_GPREL; this->Header.sh_addralign = sizeof(uintX_t); } @@ -120,7 +118,7 @@ const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const { template <class ELFT> unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const { - // TODO: Update when the suppoort of GOT entries for local symbols is added. + // TODO: Update when the support of GOT entries for local symbols is added. return Target->getGotHeaderEntriesNum(); } @@ -151,8 +149,7 @@ template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) { template <class ELFT> PltSection<ELFT>::PltSection() - : OutputSectionBase<ELFT>(".plt", llvm::ELF::SHT_PROGBITS, - llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR) { + : OutputSectionBase<ELFT>(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) { this->Header.sh_addralign = 16; } @@ -199,9 +196,7 @@ template <class ELFT> void PltSection<ELFT>::finalize() { template <class ELFT> RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela) - : OutputSectionBase<ELFT>(Name, - IsRela ? llvm::ELF::SHT_RELA : llvm::ELF::SHT_REL, - llvm::ELF::SHF_ALLOC), + : OutputSectionBase<ELFT>(Name, IsRela ? SHT_RELA : SHT_REL, SHF_ALLOC), IsRela(IsRela) { this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; @@ -328,15 +323,14 @@ template <class ELFT> void RelocationSection<ELFT>::finalize() { template <class ELFT> InterpSection<ELFT>::InterpSection() - : OutputSectionBase<ELFT>(".interp", llvm::ELF::SHT_PROGBITS, - llvm::ELF::SHF_ALLOC) { + : OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) { this->Header.sh_size = Config->DynamicLinker.size() + 1; this->Header.sh_addralign = 1; } template <class ELFT> void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) { - Header.sh_name = Out<ELFT>::ShStrTab->getOffset(Name); + Header.sh_name = Out<ELFT>::ShStrTab->addString(Name); *SHdr = Header; } @@ -346,8 +340,7 @@ template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) { template <class ELFT> HashTableSection<ELFT>::HashTableSection() - : OutputSectionBase<ELFT>(".hash", llvm::ELF::SHT_HASH, - llvm::ELF::SHF_ALLOC) { + : OutputSectionBase<ELFT>(".hash", SHT_HASH, SHF_ALLOC) { this->Header.sh_entsize = sizeof(Elf_Word); this->Header.sh_addralign = sizeof(Elf_Word); } @@ -404,8 +397,7 @@ static uint32_t hashGnu(StringRef Name) { template <class ELFT> GnuHashTableSection<ELFT>::GnuHashTableSection() - : OutputSectionBase<ELFT>(".gnu.hash", llvm::ELF::SHT_GNU_HASH, - llvm::ELF::SHF_ALLOC) { + : OutputSectionBase<ELFT>(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) { this->Header.sh_entsize = ELFT::Is64Bits ? 0 : 4; this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; } @@ -545,8 +537,7 @@ void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolBody *> &Symbols) { template <class ELFT> DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab) - : OutputSectionBase<ELFT>(".dynamic", llvm::ELF::SHT_DYNAMIC, - llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), + : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE), SymTab(SymTab) { Elf_Shdr &Header = this->Header; Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; @@ -556,7 +547,7 @@ DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab) // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Config->EMachine == EM_MIPS) - Header.sh_flags = llvm::ELF::SHF_ALLOC; + Header.sh_flags = SHF_ALLOC; } template <class ELFT> void DynamicSection<ELFT>::finalize() { @@ -590,12 +581,12 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { if (!Config->RPath.empty()) { ++NumEntries; // DT_RUNPATH / DT_RPATH - Out<ELFT>::DynStrTab->add(Config->RPath); + Out<ELFT>::DynStrTab->reserve(Config->RPath); } if (!Config->SoName.empty()) { ++NumEntries; // DT_SONAME - Out<ELFT>::DynStrTab->add(Config->SoName); + Out<ELFT>::DynStrTab->reserve(Config->SoName); } if (PreInitArraySec) @@ -608,7 +599,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) { if (!F->isNeeded()) continue; - Out<ELFT>::DynStrTab->add(F->getSoName()); + Out<ELFT>::DynStrTab->reserve(F->getSoName()); ++NumEntries; } @@ -696,7 +687,7 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { WritePtr(DT_SYMTAB, Out<ELFT>::DynSymTab->getVA()); WritePtr(DT_SYMENT, sizeof(Elf_Sym)); WritePtr(DT_STRTAB, Out<ELFT>::DynStrTab->getVA()); - WriteVal(DT_STRSZ, Out<ELFT>::DynStrTab->data().size()); + WriteVal(DT_STRSZ, Out<ELFT>::DynStrTab->getSize()); if (Out<ELFT>::GnuHashTab) WritePtr(DT_GNU_HASH, Out<ELFT>::GnuHashTab->getVA()); if (Out<ELFT>::HashTab) @@ -712,10 +703,10 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { // DT_RPATH is used for indirect dependencies as well. if (!Config->RPath.empty()) WriteVal(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - Out<ELFT>::DynStrTab->getOffset(Config->RPath)); + Out<ELFT>::DynStrTab->addString(Config->RPath)); if (!Config->SoName.empty()) - WriteVal(DT_SONAME, Out<ELFT>::DynStrTab->getOffset(Config->SoName)); + WriteVal(DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)); auto WriteArray = [&](int32_t T1, int32_t T2, const OutputSectionBase<ELFT> *Sec) { @@ -730,7 +721,7 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) if (F->isNeeded()) - WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->getOffset(F->getSoName())); + WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())); if (InitSym) WritePtr(DT_INIT, getSymVA<ELFT>(*InitSym)); @@ -765,9 +756,9 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { } template <class ELFT> -OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t sh_type, - uintX_t sh_flags) - : OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {} +OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, + uintX_t Flags) + : OutputSectionBase<ELFT>(Name, Type, Flags) {} template <class ELFT> void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { @@ -779,14 +770,14 @@ void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { this->Header.sh_addralign = Align; uintX_t Off = this->Header.sh_size; - Off = RoundUpToAlignment(Off, Align); + Off = align(Off, Align); S->OutSecOff = Off; Off += S->getSize(); this->Header.sh_size = Off; } template <class ELFT> -typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) { +typename ELFFile<ELFT>::uintX_t elf2::getSymVA(const SymbolBody &S) { switch (S.kind()) { case SymbolBody::DefinedSyntheticKind: { auto &D = cast<DefinedSynthetic<ELFT>>(S); @@ -797,6 +788,11 @@ typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) { InputSectionBase<ELFT> *SC = DR.Section; if (!SC) return DR.Sym.st_value; + + // Symbol offsets for AMDGPU need to be the offset in bytes of the symbol + // from the beginning of the section. + if (Config->EMachine == EM_AMDGPU) + return SC->getOffset(DR.Sym); if (DR.Sym.getType() == STT_TLS) return SC->OutSec->getVA() + SC->getOffset(DR.Sym) - Out<ELFT>::TlsPhdr->p_vaddr; @@ -824,9 +820,9 @@ typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) { // For non-local symbols, use getSymVA instead. template <class ELFT, bool IsRela> typename ELFFile<ELFT>::uintX_t -lld::elf2::getLocalRelTarget(const ObjectFile<ELFT> &File, - const Elf_Rel_Impl<ELFT, IsRela> &RI, - typename ELFFile<ELFT>::uintX_t Addend) { +elf2::getLocalRelTarget(const ObjectFile<ELFT> &File, + const Elf_Rel_Impl<ELFT, IsRela> &RI, + typename ELFFile<ELFT>::uintX_t Addend) { typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym; typedef typename ELFFile<ELFT>::uintX_t uintX_t; @@ -868,7 +864,7 @@ lld::elf2::getLocalRelTarget(const ObjectFile<ELFT> &File, // 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. -bool lld::elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) { +bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) { if (!Body) return false; // Body is a local symbol. if (Body->isShared()) @@ -910,9 +906,9 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) { } template <class ELFT> -EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t sh_type, - uintX_t sh_flags) - : OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {} +EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t Type, + uintX_t Flags) + : OutputSectionBase<ELFT>(Name, Type, Flags) {} template <class ELFT> EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index) @@ -980,7 +976,7 @@ void EHOutputSection<ELFT>::addSectionAux( auto P = CieMap.insert(std::make_pair(CieInfo, Cies.size())); if (P.second) { Cies.push_back(C); - this->Header.sh_size += RoundUpToAlignment(Length, sizeof(uintX_t)); + this->Header.sh_size += align(Length, sizeof(uintX_t)); } OffsetToIndex[Offset] = P.first->second; } else { @@ -993,7 +989,7 @@ void EHOutputSection<ELFT>::addSectionAux( if (I == OffsetToIndex.end()) error("Invalid CIE reference"); Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index)); - this->Header.sh_size += RoundUpToAlignment(Length, sizeof(uintX_t)); + this->Header.sh_size += align(Length, sizeof(uintX_t)); } } @@ -1046,7 +1042,7 @@ static typename ELFFile<ELFT>::uintX_t writeAlignedCieOrFde(StringRef Data, uint8_t *Buf) { typedef typename ELFFile<ELFT>::uintX_t uintX_t; const endianness E = ELFT::TargetEndianness; - uint64_t Len = RoundUpToAlignment(Data.size(), sizeof(uintX_t)); + uint64_t Len = align(Data.size(), sizeof(uintX_t)); write32<E>(Buf, Len - 4); memcpy(Buf + 4, Data.data() + 4, Data.size() - 4); return Len; @@ -1083,9 +1079,9 @@ template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) { } template <class ELFT> -MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t sh_type, - uintX_t sh_flags) - : OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {} +MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type, + uintX_t Flags) + : OutputSectionBase<ELFT>(Name, Type, Flags) {} template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) { if (shouldTailMerge()) { @@ -1165,21 +1161,50 @@ template <class ELFT> void MergeOutputSection<ELFT>::finalize() { template <class ELFT> StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic) - : OutputSectionBase<ELFT>(Name, llvm::ELF::SHT_STRTAB, - Dynamic ? (uintX_t)llvm::ELF::SHF_ALLOC : 0), + : OutputSectionBase<ELFT>(Name, SHT_STRTAB, + Dynamic ? (uintX_t)SHF_ALLOC : 0), Dynamic(Dynamic) { this->Header.sh_addralign = 1; } +// String tables are created in two phases. First you call reserve() +// to reserve room in the string table, and then call addString() to actually +// add that string. +// +// Why two phases? We want to know the size of the string table as early as +// possible to fix file layout. So we have separated finalize(), which +// determines the size of the section, from writeTo(), which writes the section +// contents to the output buffer. If we merge reserve() with addString(), +// we need a plumbing work for finalize() and writeTo() so that offsets +// we obtained in the former function can be written in the latter. +// This design eliminated that need. +template <class ELFT> void StringTableSection<ELFT>::reserve(StringRef S) { + Reserved += S.size() + 1; // +1 for NUL +} + +// Adds a string to the string table. You must call reserve() with the +// same string before calling addString(). +template <class ELFT> size_t StringTableSection<ELFT>::addString(StringRef S) { + size_t Pos = Used; + Strings.push_back(S); + Used += S.size() + 1; + Reserved -= S.size() + 1; + assert((int64_t)Reserved >= 0); + return Pos; +} + template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) { - StringRef Data = StrTabBuilder.data(); - memcpy(Buf, Data.data(), Data.size()); + // ELF string tables start with NUL byte, so advance the pointer by one. + ++Buf; + for (StringRef S : Strings) { + memcpy(Buf, S.data(), S.size()); + Buf += S.size() + 1; + } } template <class ELFT> -bool lld::elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File, - StringRef SymName, - const typename ELFFile<ELFT>::Elf_Sym &Sym) { +bool elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File, StringRef SymName, + const typename ELFFile<ELFT>::Elf_Sym &Sym) { if (Sym.getType() == STT_SECTION) return false; @@ -1208,16 +1233,12 @@ bool lld::elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File, template <class ELFT> SymbolTableSection<ELFT>::SymbolTableSection( SymbolTable<ELFT> &Table, StringTableSection<ELFT> &StrTabSec) - : OutputSectionBase<ELFT>( - StrTabSec.isDynamic() ? ".dynsym" : ".symtab", - StrTabSec.isDynamic() ? llvm::ELF::SHT_DYNSYM : llvm::ELF::SHT_SYMTAB, - StrTabSec.isDynamic() ? (uintX_t)llvm::ELF::SHF_ALLOC : 0), + : OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab", + StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, + StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0), Table(Table), StrTabSec(StrTabSec) { - typedef OutputSectionBase<ELFT> Base; - typename Base::Elf_Shdr &Header = this->Header; - - Header.sh_entsize = sizeof(Elf_Sym); - Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; + this->Header.sh_entsize = sizeof(Elf_Sym); + this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; } // Orders symbols according to their positions in the GOT, @@ -1259,14 +1280,14 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() { template <class ELFT> void SymbolTableSection<ELFT>::addLocalSymbol(StringRef Name) { - StrTabSec.add(Name); + StrTabSec.reserve(Name); ++NumVisible; ++NumLocals; } template <class ELFT> void SymbolTableSection<ELFT>::addSymbol(SymbolBody *Body) { - StrTabSec.add(Body->getName()); + StrTabSec.reserve(Body->getName()); Symbols.push_back(Body); ++NumVisible; } @@ -1306,9 +1327,13 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) { continue; const OutputSectionBase<ELFT> *OutSec = Section->OutSec; ESym->st_shndx = OutSec->SectionIndex; - VA += OutSec->getVA() + Section->getOffset(Sym); + VA = Section->getOffset(Sym); + // Symbol offsets for AMDGPU need to be the offset in bytes of the + // symbol from the beginning of the section. + if (Config->EMachine != EM_AMDGPU) + VA += OutSec->getVA(); } - ESym->st_name = StrTabSec.getOffset(SymName); + ESym->st_name = StrTabSec.addString(SymName); ESym->st_size = Sym.st_size; ESym->setBindingAndType(Sym.getBinding(), Sym.getType()); ESym->st_value = VA; @@ -1363,7 +1388,7 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) { } StringRef Name = Body->getName(); - ESym->st_name = StrTabSec.getOffset(Name); + ESym->st_name = StrTabSec.addString(Name); unsigned char Type = STT_NOTYPE; uintX_t Size = 0; @@ -1413,13 +1438,14 @@ template <class ELFT> void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) { auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf); R->ri_gp_value = getMipsGpAddr<ELFT>(); - R->ri_gprmask = GeneralMask; + R->ri_gprmask = GprMask; } template <class ELFT> void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) { + // Copy input object file's .reginfo gprmask to output. auto *S = cast<MipsReginfoInputSection<ELFT>>(C); - GeneralMask |= S->getGeneralMask(); + GprMask |= S->Reginfo->ri_gprmask; } namespace lld { diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 6dca2b570308..d7109c580cdc 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -329,21 +329,18 @@ class StringTableSection final : public OutputSectionBase<ELFT> { public: typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; StringTableSection(StringRef Name, bool Dynamic); - void add(StringRef S) { StrTabBuilder.add(S); } - size_t getOffset(StringRef S) const { return StrTabBuilder.getOffset(S); } - StringRef data() const { return StrTabBuilder.data(); } + void reserve(StringRef S); + size_t addString(StringRef S); void writeTo(uint8_t *Buf) override; - - void finalize() override { - StrTabBuilder.finalize(); - this->Header.sh_size = StrTabBuilder.data().size(); - } - + size_t getSize() const { return Used + Reserved; } + void finalize() override { this->Header.sh_size = getSize(); } bool isDynamic() const { return Dynamic; } private: const bool Dynamic; - llvm::StringTableBuilder StrTabBuilder{llvm::StringTableBuilder::ELF}; + std::vector<StringRef> Strings; + size_t Used = 1; // ELF string tables start with a NUL byte, so 1. + size_t Reserved = 0; }; template <class ELFT> @@ -429,9 +426,13 @@ public: void addSection(InputSectionBase<ELFT> *S) override; private: - uint32_t GeneralMask = 0; + uint32_t GprMask = 0; }; +inline uint64_t align(uint64_t Value, uint64_t Align) { + return llvm::RoundUpToAlignment(Value, Align); +} + // All output sections that are hadnled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 74951bad410f..65f5dff9d7a3 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -18,6 +18,7 @@ #include "Config.h" #include "Error.h" #include "Symbols.h" +#include "llvm/Support/StringSaver.h" using namespace llvm; using namespace llvm::object; @@ -26,8 +27,6 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf2; -template <class ELFT> SymbolTable<ELFT>::SymbolTable() {} - // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. @@ -64,7 +63,7 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) { if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); - if (!IncludedSoNames.insert(F->getSoName()).second) + if (!SoNames.insert(F->getSoName()).second) return; SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release())); @@ -100,17 +99,20 @@ SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) { } template <class ELFT> -void SymbolTable<ELFT>::addAbsolute(StringRef Name, - typename ELFFile<ELFT>::Elf_Sym &ESym) { - resolve(new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr)); +SymbolBody *SymbolTable<ELFT>::addAbsolute(StringRef Name, Elf_Sym &ESym) { + // Pass nullptr because absolute symbols have no corresponding input sections. + auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr); + resolve(Sym); + return Sym; } template <class ELFT> -void SymbolTable<ELFT>::addSynthetic(StringRef Name, - OutputSectionBase<ELFT> &Section, - typename ELFFile<ELFT>::uintX_t Value) { +SymbolBody *SymbolTable<ELFT>::addSynthetic(StringRef Name, + OutputSectionBase<ELFT> &Section, + uintX_t Value) { auto *Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, Value, Section); resolve(Sym); + return Sym; } // Add Name as an "ignored" symbol. An ignored symbol is a regular @@ -118,10 +120,27 @@ void SymbolTable<ELFT>::addSynthetic(StringRef Name, // file's symbol table. Such symbols are useful for some linker-defined symbols. template <class ELFT> SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) { - auto *Sym = new (Alloc) - DefinedRegular<ELFT>(Name, ElfSym<ELFT>::IgnoreUndef, nullptr); - resolve(Sym); - return Sym; + return addAbsolute(Name, ElfSym<ELFT>::IgnoredWeak); +} + +// The 'strong' variant of the addIgnored. Adds symbol which has a global +// binding and cannot be substituted. +template <class ELFT> +SymbolBody *SymbolTable<ELFT>::addIgnoredStrong(StringRef Name) { + return addAbsolute(Name, ElfSym<ELFT>::Ignored); +} + +// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. +// Used to implement --wrap. +template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) { + if (Symtab.count(Name) == 0) + return; + StringSaver Saver(Alloc); + Symbol *Sym = addUndefined(Name)->getSymbol(); + Symbol *Real = addUndefined(Saver.save("__real_" + Name))->getSymbol(); + Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->getSymbol(); + Real->Body = Sym->Body; + Sym->Body = Wrap->Body; } // Returns a file from which symbol B was created. @@ -136,6 +155,8 @@ ELFFileBase<ELFT> *SymbolTable<ELFT>::findFile(SymbolBody *B) { return nullptr; } +// Construct a string in the form of "Sym in File1 and File2". +// Used to construct an error message. template <class ELFT> std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) { ELFFileBase<ELFT> *OldFile = findFile(Old); @@ -184,8 +205,8 @@ template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) { Sym->Body = New; } +// Find an existing symbol or create and insert a new one. template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) { - // Find an existing Symbol or create and insert a new one. StringRef Name = New->getName(); Symbol *&Sym = Symtab[Name]; if (!Sym) diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 4f8f5afa420a..16ed821bf01a 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -31,9 +31,10 @@ class Undefined; // undefined, it'll read an archive member to read a real definition // to replace the lazy symbol. The logic is implemented in resolve(). template <class ELFT> class SymbolTable { -public: - SymbolTable(); + typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; +public: void addFile(std::unique_ptr<InputFile> File); const llvm::MapVector<StringRef, Symbol *> &getSymbols() const { @@ -50,13 +51,15 @@ public: SymbolBody *addUndefined(StringRef Name); SymbolBody *addUndefinedOpt(StringRef Name); - void addAbsolute(StringRef Name, - typename llvm::object::ELFFile<ELFT>::Elf_Sym &ESym); - void addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section, - typename llvm::object::ELFFile<ELFT>::uintX_t Value); + SymbolBody *addAbsolute(StringRef Name, Elf_Sym &ESym); + SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section, + uintX_t Value); SymbolBody *addIgnored(StringRef Name); + SymbolBody *addIgnoredStrong(StringRef Name); + void scanShlibUndefined(); SymbolBody *find(StringRef Name); + void wrap(StringRef Name); ELFFileBase<ELFT> *findFile(SymbolBody *B); private: @@ -66,8 +69,6 @@ private: void resolve(SymbolBody *Body); std::string conflictMsg(SymbolBody *Old, SymbolBody *New); - std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles; - // The order the global symbols are in is not defined. We can use an arbitrary // order, but it has to be reproducible. That is true even when cross linking. // The default hashing of StringRef produces different results on 32 and 64 @@ -78,13 +79,18 @@ private: llvm::MapVector<StringRef, Symbol *> Symtab; llvm::BumpPtrAllocator Alloc; + // Comdat groups define "link once" sections. If two comdat groups have the + // same name, only one of them is linked, and the other is ignored. This set + // is used to uniquify them. llvm::DenseSet<StringRef> ComdatGroups; - // The writer needs to infer the machine type from the object files. + // The symbol table owns all file objects. + std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles; std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles; - std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles; - llvm::DenseSet<StringRef> IncludedSoNames; + + // Set of .so files to not link the same shared object file more than once. + llvm::DenseSet<StringRef> SoNames; }; } // namespace elf2 diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 4af1b88e79ad..3c864cbe2b67 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -120,11 +120,13 @@ std::unique_ptr<InputFile> Lazy::getMember() { template <class ELFT> static void doInitSymbols() { ElfSym<ELFT>::End.setBinding(STB_GLOBAL); - ElfSym<ELFT>::IgnoreUndef.setBinding(STB_WEAK); - ElfSym<ELFT>::IgnoreUndef.setVisibility(STV_HIDDEN); + ElfSym<ELFT>::IgnoredWeak.setBinding(STB_WEAK); + ElfSym<ELFT>::IgnoredWeak.setVisibility(STV_HIDDEN); + ElfSym<ELFT>::Ignored.setBinding(STB_GLOBAL); + ElfSym<ELFT>::Ignored.setVisibility(STV_HIDDEN); } -void lld::elf2::initSymbols() { +void elf2::initSymbols() { doInitSymbols<ELF32LE>(); doInitSymbols<ELF32BE>(); doInitSymbols<ELF64LE>(); @@ -136,12 +138,12 @@ template int SymbolBody::compare<ELF32BE>(SymbolBody *Other); template int SymbolBody::compare<ELF64LE>(SymbolBody *Other); template int SymbolBody::compare<ELF64BE>(SymbolBody *Other); -template class lld::elf2::UndefinedElf<ELF32LE>; -template class lld::elf2::UndefinedElf<ELF32BE>; -template class lld::elf2::UndefinedElf<ELF64LE>; -template class lld::elf2::UndefinedElf<ELF64BE>; +template class elf2::UndefinedElf<ELF32LE>; +template class elf2::UndefinedElf<ELF32BE>; +template class elf2::UndefinedElf<ELF64LE>; +template class elf2::UndefinedElf<ELF64BE>; -template class lld::elf2::DefinedSynthetic<ELF32LE>; -template class lld::elf2::DefinedSynthetic<ELF32BE>; -template class lld::elf2::DefinedSynthetic<ELF64LE>; -template class lld::elf2::DefinedSynthetic<ELF64BE>; +template class elf2::DefinedSynthetic<ELF32LE>; +template class elf2::DefinedSynthetic<ELF32BE>; +template class elf2::DefinedSynthetic<ELF64LE>; +template class elf2::DefinedSynthetic<ELF64BE>; diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 16a3b338b3cd..6f65ea1a72e4 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -105,6 +105,7 @@ public: // you can access P->Backref->Body to get the resolver's result. void setBackref(Symbol *P) { Backref = P; } SymbolBody *repl() { return Backref ? Backref->Body : this; } + Symbol *getSymbol() { return Backref; } // Decides which symbol should "win" in the symbol table, this or // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if @@ -299,8 +300,11 @@ template <class ELFT> struct ElfSym { typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; // Used to represent an undefined symbol which we don't want - // to add to the output file's symbol table. - static Elf_Sym IgnoreUndef; + // to add to the output file's symbol table. The `IgnoredWeak` + // has weak binding and can be substituted. The `Ignore` has + // global binding and gets priority over symbols from shared libs. + static Elf_Sym IgnoredWeak; + static Elf_Sym Ignored; // The content for _end and end symbols. static Elf_Sym End; @@ -314,7 +318,8 @@ template <class ELFT> struct ElfSym { static Elf_Sym RelaIpltEnd; }; -template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::IgnoreUndef; +template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::IgnoredWeak; +template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::Ignored; template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::End; template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::MipsGp; template <class ELFT> diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 8d54c93570fa..6d42dbe86e54 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -122,7 +122,6 @@ private: class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); - unsigned getPltRefReloc(unsigned Type) const override; bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; void writeGotPltHeaderEntries(uint8_t *Buf) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; @@ -139,7 +138,7 @@ public: uint8_t *PairedLoc = nullptr) const override; bool isRelRelative(uint32_t Type) const override; bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override; - bool isSizeDynReloc(uint32_t Type, const SymbolBody &S) const override; + bool isSizeReloc(uint32_t Type) const override; unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, const SymbolBody &S) const override; @@ -155,6 +154,23 @@ private: uint64_t SA) const; }; +class PPCTargetInfo final : public TargetInfo { +public: + PPCTargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; + void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; + void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, + uint64_t SA, uint64_t ZA = 0, + uint8_t *PairedLoc = nullptr) const override; + bool isRelRelative(uint32_t Type) const override; +}; + class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); @@ -176,13 +192,14 @@ class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); unsigned getDynReloc(unsigned Type) const override; - unsigned getPltRefReloc(unsigned Type) const override; void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr) const override; void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; + unsigned getTlsGotReloc(unsigned Type = -1) const override; + bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; @@ -191,6 +208,22 @@ public: uint8_t *PairedLoc = nullptr) const override; }; +class AMDGPUTargetInfo final : public TargetInfo { +public: + AMDGPUTargetInfo(); + void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override; + void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const override; + void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const override; + bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override; + bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override; + void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, + uint64_t SA, uint64_t ZA = 0, + uint8_t *PairedLoc = nullptr) const override; +}; + template <class ELFT> class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); @@ -216,6 +249,8 @@ TargetInfo *createTarget() { return new X86TargetInfo(); case EM_AARCH64: return new AArch64TargetInfo(); + case EM_AMDGPU: + return new AMDGPUTargetInfo(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: @@ -225,6 +260,8 @@ TargetInfo *createTarget() { default: error("Unsupported MIPS target"); } + case EM_PPC: + return new PPCTargetInfo(); case EM_PPC64: return new PPC64TargetInfo(); case EM_X86_64: @@ -247,13 +284,9 @@ bool TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { bool TargetInfo::isGotRelative(uint32_t Type) const { return false; } -unsigned TargetInfo::getPltRefReloc(unsigned Type) const { return PCRelReloc; } - bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } -bool TargetInfo::isSizeDynReloc(uint32_t Type, const SymbolBody &S) const { - return false; -} +bool TargetInfo::isSizeReloc(uint32_t Type) const { return false; } unsigned TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, @@ -639,12 +672,6 @@ bool X86_64TargetInfo::isTlsDynReloc(unsigned Type, const SymbolBody &S) const { return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD; } -unsigned X86_64TargetInfo::getPltRefReloc(unsigned Type) const { - if (Type == R_X86_64_PLT32) - return R_X86_64_PC32; - return Type; -} - bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { if (needsCopyRel(Type, S)) return false; @@ -698,16 +725,12 @@ bool X86_64TargetInfo::isRelRelative(uint32_t Type) const { case R_X86_64_PC32: case R_X86_64_PC64: case R_X86_64_PLT32: - case R_X86_64_SIZE32: - case R_X86_64_SIZE64: return true; } } -bool X86_64TargetInfo::isSizeDynReloc(uint32_t Type, - const SymbolBody &S) const { - return (Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64) && - canBePreempted(&S, false); +bool X86_64TargetInfo::isSizeReloc(uint32_t Type) const { + return Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64; } bool X86_64TargetInfo::isTlsOptimized(unsigned Type, @@ -909,6 +932,37 @@ static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } +PPCTargetInfo::PPCTargetInfo() {} +void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {} +void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const {} +void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, + uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const {} +bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { + return false; +} +bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { + return false; +} +bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; } + +void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, + uint64_t P, uint64_t SA, uint64_t ZA, + uint8_t *PairedLoc) const { + switch (Type) { + case R_PPC_ADDR16_HA: + write16be(Loc, applyPPCHa(SA)); + break; + case R_PPC_ADDR16_LO: + write16be(Loc, applyPPCLo(SA)); + break; + default: + error("unrecognized reloc " + Twine(Type)); + } +} + PPC64TargetInfo::PPC64TargetInfo() { PCRelReloc = R_PPC64_REL24; GotReloc = R_PPC64_GLOB_DAT; @@ -1124,8 +1178,10 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, AArch64TargetInfo::AArch64TargetInfo() { CopyReloc = R_AARCH64_COPY; + IRelativeReloc = R_AARCH64_IRELATIVE; GotReloc = R_AARCH64_GLOB_DAT; PltReloc = R_AARCH64_JUMP_SLOT; + TlsGotReloc = R_AARCH64_TLS_TPREL64; LazyRelocations = true; PltEntrySize = 16; PltZeroEntrySize = 32; @@ -1139,8 +1195,6 @@ unsigned AArch64TargetInfo::getDynReloc(unsigned Type) const { "recompile with -fPIC."); } -unsigned AArch64TargetInfo::getPltRefReloc(unsigned Type) const { return Type; } - void AArch64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { write64le(Buf, Out<ELF64LE>::Plt->getVA()); } @@ -1187,6 +1241,19 @@ void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, GotEntryAddr); } +unsigned AArch64TargetInfo::getTlsGotReloc(unsigned Type) const { + if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || + Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) + return Type; + return TlsGotReloc; +} + +bool AArch64TargetInfo::isTlsDynReloc(unsigned Type, + const SymbolBody &S) const { + return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || + Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; +} + bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { if (Config->Shared) return false; @@ -1210,17 +1277,28 @@ bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { bool AArch64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { - return Type == R_AARCH64_ADR_GOT_PAGE || Type == R_AARCH64_LD64_GOT_LO12_NC || - relocNeedsPlt(Type, S); + switch (Type) { + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + return true; + default: + return relocNeedsPlt(Type, S); + } } bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { + if (isGnuIFunc<ELF64LE>(S)) + return true; switch (Type) { default: return false; case R_AARCH64_CALL26: + case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: + case R_AARCH64_TSTBR14: return canBePreempted(&S, true); } } @@ -1273,7 +1351,8 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, updateAArch64Adr(Loc, X & 0x1FFFFF); break; } - case R_AARCH64_ADR_PREL_PG_HI21: { + case R_AARCH64_ADR_PREL_PG_HI21: + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: { uint64_t X = getAArch64Page(SA) - getAArch64Page(P); checkInt<33>(X, Type); updateAArch64Adr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] @@ -1286,7 +1365,14 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, or32le(Loc, (X & 0x0FFFFFFC) >> 2); break; } + case R_AARCH64_CONDBR19: { + uint64_t X = SA - P; + checkInt<21>(X, Type); + or32le(Loc, (X & 0x1FFFFC) << 3); + break; + } case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: checkAlignment<8>(SA, Type); or32le(Loc, (SA & 0xFF8) << 7); break; @@ -1310,11 +1396,53 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, case R_AARCH64_PREL64: write64le(Loc, SA - P); break; + case R_AARCH64_TSTBR14: { + uint64_t X = SA - P; + checkInt<16>(X, Type); + or32le(Loc, (X & 0xFFFC) << 3); + break; + } default: error("unrecognized reloc " + Twine(Type)); } } +AMDGPUTargetInfo::AMDGPUTargetInfo() {} + +void AMDGPUTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const { + llvm_unreachable("not implemented"); +} + +void AMDGPUTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr) const { + llvm_unreachable("not implemented"); +} + +void AMDGPUTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr, + uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + llvm_unreachable("not implemented"); +} + +bool AMDGPUTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const { + return false; +} + +bool AMDGPUTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const { + return false; +} + +// Implementing relocations for AMDGPU is low priority since most +// programs don't use relocations now. Thus, this function is not +// actually called (relocateOne is called for each relocation). +// That's why the AMDGPU port works without implementing this function. +void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, + uint64_t P, uint64_t SA, uint64_t ZA, + uint8_t *PairedLoc) const { + llvm_unreachable("not implemented"); +} + template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() { PageSize = 65536; GotHeaderEntriesNum = 2; diff --git a/ELF/Target.h b/ELF/Target.h index 52c2697dc60d..e9c5f4b31ae4 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -45,7 +45,6 @@ public: virtual bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const { return false; } - virtual unsigned getPltRefReloc(unsigned Type) const; virtual unsigned getTlsGotReloc(unsigned Type = -1) const { return TlsGotReloc; } @@ -57,8 +56,15 @@ public: virtual void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const = 0; + + // Returns true if a relocation is relative to the place being relocated, + // such as relocations used for PC-relative instructions. Such relocations + // need not be fixed up if an image is loaded to a different address than + // the link-time address. So we don't have to emit a relocation for the + // dynamic linker if isRelRelative returns true. virtual bool isRelRelative(uint32_t Type) const; - virtual bool isSizeDynReloc(uint32_t Type, const SymbolBody &S) const; + + virtual bool isSizeReloc(uint32_t Type) const; virtual bool relocNeedsDynRelative(unsigned Type) const { return false; } virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0; virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 2437a435657c..fbecfc601ac1 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -98,12 +98,9 @@ private: }; } // anonymous namespace -template <class ELFT> static bool shouldUseRela() { - ELFKind K = cast<ELFFileBase<ELFT>>(Config->FirstElf)->getELFKind(); - return K == ELF64LEKind || K == ELF64BEKind; -} +template <class ELFT> static bool shouldUseRela() { return ELFT::Is64Bits; } -template <class ELFT> void lld::elf2::writeResult(SymbolTable<ELFT> *Symtab) { +template <class ELFT> void elf2::writeResult(SymbolTable<ELFT> *Symtab) { // Initialize output sections that are handled by Writer specially. // Don't reorder because the order of initialization matters. InterpSection<ELFT> Interp; @@ -290,18 +287,31 @@ void Writer<ELFT>::scanRelocs( continue; } - if (Config->EMachine == EM_MIPS && NeedsGot) { - // MIPS ABI has special rules to process GOT entries - // and doesn't require relocation entries for them. - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Body->setUsedInDynamicReloc(); - continue; + if (Config->EMachine == EM_MIPS) { + if (NeedsGot) { + // MIPS ABI has special rules to process GOT entries + // and doesn't require relocation entries for them. + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Body->setUsedInDynamicReloc(); + continue; + } + if (Body == Config->MipsGpDisp) + // MIPS _gp_disp designates offset between start of function and gp + // pointer into GOT therefore any relocations against it do not require + // dynamic relocation. + continue; } + + // Here we are creating a relocation for the dynamic linker based on + // a relocation from an object file, but some relocations need no + // load-time fixup. Skip such relocation. bool CBP = canBePreempted(Body, NeedsGot); - if (!CBP && (!Config->Shared || Target->isRelRelative(Type))) + bool NoDynrel = Target->isRelRelative(Type) || Target->isSizeReloc(Type); + if (!CBP && (NoDynrel || !Config->Shared)) continue; + if (CBP) Body->setUsedInDynamicReloc(); if (NeedsPlt && Target->supportsLazyRelocations()) @@ -490,8 +500,7 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) { uintX_t Off = getBss()->getSize(); for (DefinedCommon *C : Syms) { - uintX_t Align = C->MaxAlignment; - Off = RoundUpToAlignment(Off, Align); + Off = align(Off, C->MaxAlignment); C->OffsetInBss = Off; Off += C->Size; } @@ -514,7 +523,7 @@ void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) { countTrailingZeros((uintX_t)Sym.st_value)); uintX_t Align = 1 << TrailingZeros; Out<ELFT>::Bss->updateAlign(Align); - Off = RoundUpToAlignment(Off, Align); + Off = align(Off, Align); C->OffsetInBss = Off; Off += Sym.st_size; } @@ -597,7 +606,8 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) { // Don't include synthetic symbols like __init_array_start in every output. if (auto *U = dyn_cast<DefinedRegular<ELFT>>(&B)) - if (&U->Sym == &ElfSym<ELFT>::IgnoreUndef) + if (&U->Sym == &ElfSym<ELFT>::IgnoredWeak || + &U->Sym == &ElfSym<ELFT>::Ignored) return false; return true; @@ -630,8 +640,6 @@ public: private: SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C, StringRef OutsecName); - OutputSectionBase<ELFT> *createAux(InputSectionBase<ELFT> *C, - const SectionKey<ELFT::Is64Bits> &Key); SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map; }; @@ -645,25 +653,22 @@ OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C, OutputSectionBase<ELFT> *&Sec = Map[Key]; if (Sec) return {Sec, false}; - Sec = createAux(C, Key); - return {Sec, true}; -} -template <class ELFT> -OutputSectionBase<ELFT> * -OutputSectionFactory<ELFT>::createAux(InputSectionBase<ELFT> *C, - const SectionKey<ELFT::Is64Bits> &Key) { switch (C->SectionKind) { case InputSectionBase<ELFT>::Regular: - return new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + break; case InputSectionBase<ELFT>::EHFrame: - return new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + Sec = new EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + break; case InputSectionBase<ELFT>::Merge: - return new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); + break; case InputSectionBase<ELFT>::MipsReginfo: - return new MipsReginfoOutputSection<ELFT>(); + Sec = new MipsReginfoOutputSection<ELFT>(); + break; } - llvm_unreachable("Unknown output section type"); + return {Sec, true}; } template <class ELFT> @@ -832,7 +837,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { } for (OutputSectionBase<ELFT> *Sec : OutputSections) - Out<ELFT>::ShStrTab->add(Sec->getName()); + Out<ELFT>::ShStrTab->reserve(Sec->getName()); // Finalizers fix each section's size. // .dynamic section's finalizer may add strings to .dynstr, @@ -976,6 +981,18 @@ static uint32_t toPhdrFlags(uint64_t Flags) { return Ret; } +/// For AMDGPU we need to use custom segment kinds in order to specify which +/// address space data should be loaded into. +template <class ELFT> +static uint32_t getAmdgpuPhdr(OutputSectionBase<ELFT> *Sec) { + uint32_t Flags = Sec->getFlags(); + if (Flags & SHF_AMDGPU_HSA_CODE) + return PT_AMDGPU_HSA_LOAD_CODE_AGENT; + if ((Flags & SHF_AMDGPU_HSA_GLOBAL) && !(Flags & SHF_AMDGPU_HSA_AGENT)) + return PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM; + return PT_LOAD; +} + template <class ELFT> void Writer<ELFT>::updateRelro(Elf_Phdr *Cur, Elf_Phdr *GnuRelroPhdr, uintX_t VA) { @@ -1024,8 +1041,8 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { bool InRelRo = Config->ZRelro && (Flags & PF_W) && isRelroSection(Sec); bool FirstNonRelRo = GnuRelroPhdr.p_type && !InRelRo && !RelroAligned; if (FirstNonRelRo || PH->p_flags != Flags) { - VA = RoundUpToAlignment(VA, Target->getPageSize()); - FileOff = RoundUpToAlignment(FileOff, Target->getPageSize()); + VA = align(VA, Target->getPageSize()); + FileOff = align(FileOff, Target->getPageSize()); if (FirstNonRelRo) RelroAligned = true; } @@ -1033,15 +1050,17 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { if (PH->p_flags != Flags) { // Flags changed. Create a new PT_LOAD. PH = &Phdrs[++PhdrIdx]; - setPhdr(PH, PT_LOAD, Flags, FileOff, VA, 0, Target->getPageSize()); + uint32_t PTType = (Config->EMachine != EM_AMDGPU) ? (uint32_t)PT_LOAD + : getAmdgpuPhdr(Sec); + setPhdr(PH, PTType, Flags, FileOff, VA, 0, Target->getPageSize()); } if (Sec->getFlags() & SHF_TLS) { if (!TlsPhdr.p_vaddr) setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign()); if (Sec->getType() != SHT_NOBITS) - VA = RoundUpToAlignment(VA, Sec->getAlign()); - uintX_t TVA = RoundUpToAlignment(VA + ThreadBssOffset, Sec->getAlign()); + VA = align(VA, Sec->getAlign()); + uintX_t TVA = align(VA + ThreadBssOffset, Sec->getAlign()); Sec->setVA(TVA); TlsPhdr.p_memsz += Sec->getSize(); if (Sec->getType() == SHT_NOBITS) { @@ -1052,7 +1071,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { } TlsPhdr.p_align = std::max<uintX_t>(TlsPhdr.p_align, Sec->getAlign()); } else { - VA = RoundUpToAlignment(VA, Sec->getAlign()); + VA = align(VA, Sec->getAlign()); Sec->setVA(VA); VA += Sec->getSize(); if (InRelRo) @@ -1060,7 +1079,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { } } - FileOff = RoundUpToAlignment(FileOff, Sec->getAlign()); + FileOff = align(FileOff, Sec->getAlign()); Sec->setFileOffset(FileOff); if (Sec->getType() != SHT_NOBITS) FileOff += Sec->getSize(); @@ -1073,7 +1092,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { if (TlsPhdr.p_vaddr) { // The TLS pointer goes after PT_TLS. At least glibc will align it, // so round up the size to make sure the offsets are correct. - TlsPhdr.p_memsz = RoundUpToAlignment(TlsPhdr.p_memsz, TlsPhdr.p_align); + TlsPhdr.p_memsz = align(TlsPhdr.p_memsz, TlsPhdr.p_align); Phdrs[++PhdrIdx] = TlsPhdr; Out<ELFT>::TlsPhdr = &Phdrs[PhdrIdx]; } @@ -1105,7 +1124,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { } // Add space for section headers. - SectionHeaderOff = RoundUpToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); + SectionHeaderOff = align(FileOff, ELFT::Is64Bits ? 8 : 4); FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); // Update "_end" and "end" symbols so that they @@ -1146,7 +1165,7 @@ static uint32_t getELFFlags() { if (Config->EMachine != EM_MIPS) return 0; // FIXME: In fact ELF flags depends on ELF flags of input object files - // and selected emulation. For now just use hadr coded values. + // and selected emulation. For now just use hard coded values. uint32_t V = EF_MIPS_ABI_O32 | EF_MIPS_CPIC | EF_MIPS_ARCH_32R2; if (Config->Shared) V |= EF_MIPS_PIC; @@ -1238,8 +1257,17 @@ template <class ELFT> void Writer<ELFT>::writeSections() { Sec->writeTo(Buf + Sec->getFileOff()); } + // Write all sections but string table sections. We know the sizes of the + // string tables already, but they may not have actual strings yet (only + // room may be reserved), because writeTo() is allowed to add actual + // strings to the string tables. + for (OutputSectionBase<ELFT> *Sec : OutputSections) + if (Sec != Out<ELFT>::Opd && Sec->getType() != SHT_STRTAB) + Sec->writeTo(Buf + Sec->getFileOff()); + + // Write string table sections. for (OutputSectionBase<ELFT> *Sec : OutputSections) - if (Sec != Out<ELFT>::Opd) + if (Sec != Out<ELFT>::Opd && Sec->getType() == SHT_STRTAB) Sec->writeTo(Buf + Sec->getFileOff()); } @@ -1275,7 +1303,7 @@ template <class ELFT> void Writer<ELFT>::buildSectionMap() { InputToOutputSection[Name] = OutSec.first; } -template void lld::elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab); -template void lld::elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab); -template void lld::elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab); -template void lld::elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab); +template void elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab); +template void elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab); +template void elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab); +template void elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab); |