aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-13 20:06:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-13 20:06:04 +0000
commitb289257c7f3ed78b7d3971c596d7c60a9050c705 (patch)
treed6b57e29a5a86347a020d6f0cae76cc2d0f3bf8d /ELF
parentfba2c04f31e119eacf142fcbbaabd5a9e63a39ed (diff)
downloadsrc-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.txt2
-rw-r--r--ELF/Driver.cpp62
-rw-r--r--ELF/Driver.h8
-rw-r--r--ELF/DriverUtils.cpp10
-rw-r--r--ELF/InputFiles.cpp15
-rw-r--r--ELF/InputFiles.h7
-rw-r--r--ELF/InputSection.cpp33
-rw-r--r--ELF/InputSection.h9
-rw-r--r--ELF/LinkerScript.cpp2
-rw-r--r--ELF/MarkLive.cpp15
-rw-r--r--ELF/Options.td4
-rw-r--r--ELF/OutputSections.cpp174
-rw-r--r--ELF/OutputSections.h23
-rw-r--r--ELF/SymbolTable.cpp49
-rw-r--r--ELF/SymbolTable.h28
-rw-r--r--ELF/Symbols.cpp24
-rw-r--r--ELF/Symbols.h11
-rw-r--r--ELF/Target.cpp178
-rw-r--r--ELF/Target.h10
-rw-r--r--ELF/Writer.cpp124
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);