aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-02 18:31:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-02 18:31:09 +0000
commit274c9ff5404582ff22769d9599ab10ed216ceec3 (patch)
tree8eccb2d5ca32dbec2ab6a1a3b8ac6a593f0e1b6f /ELF
parente06a19b85dfce9ea18be97247d4ca315963edc5c (diff)
downloadsrc-274c9ff5404582ff22769d9599ab10ed216ceec3.tar.gz
src-274c9ff5404582ff22769d9599ab10ed216ceec3.zip
Vendor import of lld trunk r301939:vendor/lld/lld-trunk-r301939
Notes
Notes: svn path=/vendor/lld/dist/; revision=317690 svn path=/vendor/lld/lld-trunk-r301939/; revision=317691; tag=vendor/lld/lld-trunk-r301939
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Config.h2
-rw-r--r--ELF/Driver.cpp93
-rw-r--r--ELF/Driver.h1
-rw-r--r--ELF/Error.cpp1
-rw-r--r--ELF/InputFiles.cpp187
-rw-r--r--ELF/InputFiles.h2
-rw-r--r--ELF/InputSection.cpp4
-rw-r--r--ELF/LTO.cpp5
-rw-r--r--ELF/LinkerScript.cpp133
-rw-r--r--ELF/LinkerScript.h5
-rw-r--r--ELF/MapFile.cpp165
-rw-r--r--ELF/Options.td41
-rw-r--r--ELF/OutputSections.cpp12
-rw-r--r--ELF/OutputSections.h2
-rw-r--r--ELF/Strings.h4
-rw-r--r--ELF/SymbolTable.cpp3
-rw-r--r--ELF/SyntheticSections.cpp13
-rw-r--r--ELF/Writer.cpp6
18 files changed, 392 insertions, 287 deletions
diff --git a/ELF/Config.h b/ELF/Config.h
index d25c63c3c0d2..1ace4aa26fdb 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -89,7 +89,7 @@ struct Configuration {
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringRef ThinLTOCacheDir;
- std::string RPath;
+ std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> SearchPaths;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 68eb5616a5c6..6a71eb3ee490 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -124,7 +124,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
std::vector<MemoryBufferRef>
-LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
+static getArchiveMembers(MemoryBufferRef MB) {
std::unique_ptr<Archive> File =
check(Archive::create(MB),
MB.getBufferIdentifier() + ": failed to parse archive");
@@ -242,6 +242,9 @@ static void checkOptions(opt::InputArgList &Args) {
if (Config->Pie && Config->Shared)
error("-shared and -pie may not be used together");
+ if (!Config->Shared && !Config->AuxiliaryList.empty())
+ error("-f may not be used without -shared");
+
if (Config->Relocatable) {
if (Config->Shared)
error("-r and -shared may not be used together");
@@ -396,7 +399,7 @@ static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
return V;
}
-static std::string getRPath(opt::InputArgList &Args) {
+static std::string getRpath(opt::InputArgList &Args) {
std::vector<StringRef> V = getArgs(Args, OPT_rpath);
return llvm::join(V.begin(), V.end(), ":");
}
@@ -444,16 +447,14 @@ static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
}
static Target2Policy getTarget2(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_target2)) {
- StringRef S = Arg->getValue();
- if (S == "rel")
- return Target2Policy::Rel;
- if (S == "abs")
- return Target2Policy::Abs;
- if (S == "got-rel")
- return Target2Policy::GotRel;
- error("unknown --target2 option: " + S);
- }
+ StringRef S = getString(Args, OPT_target2, "got-rel");
+ if (S == "rel")
+ return Target2Policy::Rel;
+ if (S == "abs")
+ return Target2Policy::Abs;
+ if (S == "got-rel")
+ return Target2Policy::GotRel;
+ error("unknown --target2 option: " + S);
return Target2Policy::GotRel;
}
@@ -550,6 +551,29 @@ static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
return {true, true};
}
+// Parse --build-id or --build-id=<style>. We handle "tree" as a
+// synonym for "sha1" because all our hash functions including
+// -build-id=sha1 are actually tree hashes for performance reasons.
+static std::pair<BuildIdKind, std::vector<uint8_t>>
+getBuildId(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_build_id))
+ return {BuildIdKind::Fast, {}};
+
+ StringRef S = getString(Args, OPT_build_id_eq, "none");
+ if (S == "md5")
+ return {BuildIdKind::Md5, {}};
+ if (S == "sha1" || S == "tree")
+ return {BuildIdKind::Sha1, {}};
+ if (S == "uuid")
+ return {BuildIdKind::Uuid, {}};
+ if (S.startswith("0x"))
+ return {BuildIdKind::Hexstring, parseHex(S.substr(2))};
+
+ if (S != "none")
+ error("unknown --build-id style: " + S);
+ return {BuildIdKind::None, {}};
+}
+
static std::vector<StringRef> getLines(MemoryBufferRef MB) {
SmallVector<StringRef, 0> Arr;
MB.getBuffer().split(Arr, '\n');
@@ -564,14 +588,14 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
}
static bool getCompressDebugSections(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_compress_debug_sections)) {
- StringRef S = Arg->getValue();
- if (S == "zlib")
- return zlib::isAvailable();
- if (S != "none")
- error("unknown --compress-debug-sections value: " + S);
- }
- return false;
+ StringRef S = getString(Args, OPT_compress_debug_sections, "none");
+ if (S == "none")
+ return false;
+ if (S != "zlib")
+ error("unknown --compress-debug-sections value: " + S);
+ if (!zlib::isAvailable())
+ error("--compress-debug-sections: zlib is not available");
+ return true;
}
// Initializes Config members by the command line options.
@@ -616,7 +640,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->OutputFile = getString(Args, OPT_o);
Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
- Config->RPath = getRPath(Args);
+ Config->Rpath = getRpath(Args);
Config->Relocatable = Args.hasArg(OPT_relocatable);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
Config->SearchPaths = getArgs(Args, OPT_L);
@@ -679,32 +703,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->ZRelro = false;
std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args);
-
- // Parse --build-id or --build-id=<style>. We handle "tree" as a
- // synonym for "sha1" because all of our hash functions including
- // -build-id=sha1 are tree hashes for performance reasons.
- if (Args.hasArg(OPT_build_id))
- Config->BuildId = BuildIdKind::Fast;
- if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
- StringRef S = Arg->getValue();
- if (S == "md5") {
- Config->BuildId = BuildIdKind::Md5;
- } else if (S == "sha1" || S == "tree") {
- Config->BuildId = BuildIdKind::Sha1;
- } else if (S == "uuid") {
- Config->BuildId = BuildIdKind::Uuid;
- } else if (S == "none") {
- Config->BuildId = BuildIdKind::None;
- } else if (S.startswith("0x")) {
- Config->BuildId = BuildIdKind::Hexstring;
- Config->BuildIdVector = parseHex(S.substr(2));
- } else {
- error("unknown --build-id style: " + S);
- }
- }
-
- if (!Config->Shared && !Config->AuxiliaryList.empty())
- error("-f may not be used without -shared");
+ std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 6a75a8942ca0..58bd2ab52195 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -31,7 +31,6 @@ public:
void addLibrary(StringRef Name);
private:
- std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);
void readConfigs(llvm::opt::InputArgList &Args);
void createFiles(llvm::opt::InputArgList &Args);
void inferMachineType();
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
index 2c61b58dfed5..7a58668bdcc0 100644
--- a/ELF/Error.cpp
+++ b/ELF/Error.cpp
@@ -60,6 +60,7 @@ void elf::log(const Twine &Msg) {
if (Config->Verbose) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Argv0 << ": " << Msg << "\n";
+ outs().flush();
}
}
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index d99f71eb4aae..12867bbd071c 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -123,10 +123,10 @@ std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
return "";
}
-// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
std::string lld::toString(const InputFile *F) {
if (!F)
- return "(internal)";
+ return "<internal>";
if (F->ToStringCache.empty()) {
if (F->ArchiveName.empty())
@@ -137,15 +137,13 @@ std::string lld::toString(const InputFile *F) {
return F->ToStringCache;
}
-template <class ELFT> static ELFKind getELFKind() {
- if (ELFT::TargetEndianness == support::little)
- return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
- return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
-}
-
template <class ELFT>
ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
- EKind = getELFKind<ELFT>();
+ if (ELFT::TargetEndianness == support::little)
+ EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
+ else
+ EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
+
EMachine = getObj().getHeader()->e_machine;
OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
}
@@ -174,8 +172,10 @@ void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
}
template <class ELFT>
-elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
- : ELFFileBase<ELFT>(Base::ObjectKind, M) {}
+elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName)
+ : ELFFileBase<ELFT>(Base::ObjectKind, M) {
+ this->ArchiveName = ArchiveName;
+}
template <class ELFT>
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
@@ -361,6 +361,15 @@ InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
return Target;
}
+// Create a regular InputSection class that has the same contents
+// as a given section.
+InputSectionBase *toRegularSection(MergeInputSection *Sec) {
+ auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment,
+ Sec->Data, Sec->Name);
+ Ret->File = Sec->File;
+ return Ret;
+}
+
template <class ELFT>
InputSectionBase *
elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
@@ -398,9 +407,18 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
if (Target->FirstRelocation)
fatal(toString(this) +
": multiple relocation sections to one section are not supported");
- if (isa<MergeInputSection>(Target))
- fatal(toString(this) +
- ": relocations pointing to SHF_MERGE are not supported");
+
+ // Mergeable sections with relocations are tricky because relocations
+ // need to be taken into account when comparing section contents for
+ // merging. It doesn't worth supporting such mergeable sections because
+ // they are rare and it'd complicates the internal design (we usually
+ // have to determine if two sections are mergeable early in the link
+ // process much before applying relocations). We simply handle mergeable
+ // sections with relocations as non-mergeable.
+ if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
+ Target = toRegularSection(MS);
+ this->Sections[Sec.sh_info] = Target;
+ }
size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
@@ -461,6 +479,15 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
if (Config->Strip != StripPolicy::None && Name.startswith(".debug"))
return &InputSection::Discarded;
+ // If -gdb-index is given, LLD creates .gdb_index section, and that
+ // section serves the same purpose as .debug_gnu_pub{names,types} sections.
+ // If that's the case, we want to eliminate .debug_gnu_pub{names,types}
+ // because they are redundant and can waste large amount of disk space
+ // (for example, they are about 400 MiB in total for a clang debug build.)
+ if (Config->GdbIndex &&
+ (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes"))
+ return &InputSection::Discarded;
+
// The linkonce feature is a sort of proto-comdat. Some glibc i386 object
// files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
// sections. Drop those sections to avoid duplicate symbol errors.
@@ -665,7 +692,7 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
uint64_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
fatal(toString(this) + ": invalid DT_SONAME entry");
- SoName = StringRef(this->StringTable.data() + Val);
+ SoName = this->StringTable.data() + Val;
return;
}
}
@@ -748,7 +775,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
// with explicit versions.
if (V) {
StringRef VerName = this->StringTable.data() + V->getAux()->vda_name;
- Name = Saver.save(Twine(Name) + "@" + VerName);
+ Name = Saver.save(Name + "@" + VerName);
elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
}
}
@@ -862,76 +889,50 @@ void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
}
-// Small bit of template meta programming to handle the SharedFile constructor
-// being the only one with a DefaultSoName parameter.
-template <template <class> class T, class E>
-typename std::enable_if<std::is_same<T<E>, SharedFile<E>>::value,
- InputFile *>::type
-createELFAux(MemoryBufferRef MB, StringRef DefaultSoName) {
- return make<T<E>>(MB, DefaultSoName);
-}
-template <template <class> class T, class E>
-typename std::enable_if<!std::is_same<T<E>, SharedFile<E>>::value,
- InputFile *>::type
-createELFAux(MemoryBufferRef MB, StringRef DefaultSoName) {
- return make<T<E>>(MB);
-}
-
-template <template <class> class T>
-static InputFile *createELFFile(MemoryBufferRef MB, StringRef DefaultSoName) {
+static ELFKind getELFKind(MemoryBufferRef MB) {
unsigned char Size;
unsigned char Endian;
std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
+
if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
fatal(MB.getBufferIdentifier() + ": invalid data encoding");
+ if (Size != ELFCLASS32 && Size != ELFCLASS64)
+ fatal(MB.getBufferIdentifier() + ": invalid file class");
size_t BufSize = MB.getBuffer().size();
if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) ||
(Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr)))
fatal(MB.getBufferIdentifier() + ": file is too short");
- InputFile *Obj;
- if (Size == ELFCLASS32 && Endian == ELFDATA2LSB)
- Obj = createELFAux<T, ELF32LE>(MB, DefaultSoName);
- else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB)
- Obj = createELFAux<T, ELF32BE>(MB, DefaultSoName);
- else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB)
- Obj = createELFAux<T, ELF64LE>(MB, DefaultSoName);
- else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB)
- Obj = createELFAux<T, ELF64BE>(MB, DefaultSoName);
- else
- fatal(MB.getBufferIdentifier() + ": invalid file class");
-
- if (!Config->FirstElf)
- Config->FirstElf = Obj;
- return Obj;
+ if (Size == ELFCLASS32)
+ return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind;
+ return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind;
}
template <class ELFT> void BinaryFile::parse() {
- StringRef Buf = MB.getBuffer();
- ArrayRef<uint8_t> Data =
- makeArrayRef<uint8_t>((const uint8_t *)Buf.data(), Buf.size());
-
- std::string Filename = MB.getBufferIdentifier();
- std::transform(Filename.begin(), Filename.end(), Filename.begin(),
- [](char C) { return isalnum(C) ? C : '_'; });
- Filename = "_binary_" + Filename;
- StringRef StartName = Saver.save(Twine(Filename) + "_start");
- StringRef EndName = Saver.save(Twine(Filename) + "_end");
- StringRef SizeName = Saver.save(Twine(Filename) + "_size");
-
+ ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
auto *Section =
make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data");
Sections.push_back(Section);
- elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0,
- STB_GLOBAL, Section, nullptr);
- elf::Symtab<ELFT>::X->addRegular(EndName, STV_DEFAULT, STT_OBJECT,
- Data.size(), 0, STB_GLOBAL, Section,
- nullptr);
- elf::Symtab<ELFT>::X->addRegular(SizeName, STV_DEFAULT, STT_OBJECT,
- Data.size(), 0, STB_GLOBAL, nullptr,
+ // For each input file foo that is embedded to a result as a binary
+ // blob, we define _binary_foo_{start,end,size} symbols, so that
+ // user programs can access blobs by name. Non-alphanumeric
+ // characters in a filename are replaced with underscore.
+ std::string S = "_binary_" + MB.getBufferIdentifier().str();
+ for (size_t I = 0; I < S.size(); ++I)
+ if (!isalnum(S[I]))
+ S[I] = '_';
+
+ elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT,
+ STT_OBJECT, 0, 0, STB_GLOBAL, Section,
nullptr);
+ elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT,
+ STT_OBJECT, Data.size(), 0, STB_GLOBAL,
+ Section, nullptr);
+ elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT,
+ STT_OBJECT, Data.size(), 0, STB_GLOBAL,
+ nullptr, nullptr);
}
static bool isBitcode(MemoryBufferRef MB) {
@@ -941,15 +942,36 @@ static bool isBitcode(MemoryBufferRef MB) {
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
- InputFile *F = isBitcode(MB)
- ? make<BitcodeFile>(MB, ArchiveName, OffsetInArchive)
- : createELFFile<ObjectFile>(MB, "");
- F->ArchiveName = ArchiveName;
- return F;
+ if (isBitcode(MB))
+ return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive);
+
+ switch (getELFKind(MB)) {
+ case ELF32LEKind:
+ return make<ObjectFile<ELF32LE>>(MB, ArchiveName);
+ case ELF32BEKind:
+ return make<ObjectFile<ELF32BE>>(MB, ArchiveName);
+ case ELF64LEKind:
+ return make<ObjectFile<ELF64LE>>(MB, ArchiveName);
+ case ELF64BEKind:
+ return make<ObjectFile<ELF64BE>>(MB, ArchiveName);
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
- return createELFFile<SharedFile>(MB, DefaultSoName);
+ switch (getELFKind(MB)) {
+ case ELF32LEKind:
+ return make<SharedFile<ELF32LE>>(MB, DefaultSoName);
+ case ELF32BEKind:
+ return make<SharedFile<ELF32BE>>(MB, DefaultSoName);
+ case ELF64LEKind:
+ return make<SharedFile<ELF64LE>>(MB, DefaultSoName);
+ case ELF64BEKind:
+ return make<SharedFile<ELF64BE>>(MB, DefaultSoName);
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
MemoryBufferRef LazyObjectFile::getBuffer() {
@@ -1004,17 +1026,18 @@ std::vector<StringRef> LazyObjectFile::getSymbols() {
if (isBitcode(this->MB))
return getBitcodeSymbols();
- unsigned char Size;
- unsigned char Endian;
- std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer());
- if (Size == ELFCLASS32) {
- if (Endian == ELFDATA2LSB)
- return getElfSymbols<ELF32LE>();
+ switch (getELFKind(this->MB)) {
+ case ELF32LEKind:
+ return getElfSymbols<ELF32LE>();
+ case ELF32BEKind:
return getElfSymbols<ELF32BE>();
- }
- if (Endian == ELFDATA2LSB)
+ case ELF64LEKind:
return getElfSymbols<ELF64LE>();
- return getElfSymbols<ELF64BE>();
+ case ELF64BEKind:
+ return getElfSymbols<ELF64BE>();
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
template void ArchiveFile::parse<ELF32LE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 4552270316d9..d0a45a4a98cf 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -156,7 +156,7 @@ public:
ArrayRef<SymbolBody *> getSymbols();
ArrayRef<SymbolBody *> getLocalSymbols();
- explicit ObjectFile(MemoryBufferRef M);
+ ObjectFile(MemoryBufferRef M, StringRef ArchiveName);
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
InputSectionBase *getSection(const Elf_Sym &Sym) const;
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index aff57551a8b3..c082f128a9bc 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -39,9 +39,7 @@ std::vector<InputSectionBase *> elf::InputSections;
// Returns a string to construct an error message.
std::string lld::toString(const InputSectionBase *Sec) {
- // File can be absent if section is synthetic.
- std::string FileName = Sec->File ? Sec->File->getName() : "<internal>";
- return (FileName + ":(" + Sec->Name + ")").str();
+ return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
}
template <class ELFT>
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index dd435173101a..de0d45bea1c4 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -105,6 +105,11 @@ BitcodeCompiler::~BitcodeCompiler() = default;
static void undefine(Symbol *S) {
replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
STV_DEFAULT, S->body()->Type, nullptr);
+ // It shouldn't normally matter what the binding is, but if a bug in the LTO
+ // implementation causes it to fail to provide a definition for a symbol,
+ // setting the binding to STB_GLOBAL will cause the linker to report an
+ // undefined symbol error, even if the definition was weak.
+ S->Binding = STB_GLOBAL;
}
void BitcodeCompiler::add(BitcodeFile &F) {
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 63eb90456e17..22a5b639469b 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -406,8 +406,15 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
}
// Add input sections to an output section.
- for (InputSectionBase *S : V)
- Factory.addInputSec(S, Cmd->Name);
+ unsigned Pos = 0;
+ for (InputSectionBase *S : V) {
+ // The actual offset will be computed during
+ // assignAddresses. For now, use the index as a very crude
+ // approximation so that it is at least easy for other code to
+ // know the section order.
+ cast<InputSection>(S)->OutSecOff = Pos++;
+ Factory.addInputSec(S, Cmd->Name, Cmd->Sec);
+ }
}
}
CurOutSec = nullptr;
@@ -465,9 +472,26 @@ void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) {
// Add sections that didn't match any sections command.
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
- for (InputSectionBase *S : InputSections)
- if (S->Live && !S->OutSec)
- Factory.addInputSec(S, getOutputSectionName(S->Name));
+ for (InputSectionBase *S : InputSections) {
+ if (!S->Live || S->OutSec)
+ continue;
+ StringRef Name = getOutputSectionName(S->Name);
+ auto I = std::find_if(
+ Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ return Cmd->Name == Name;
+ return false;
+ });
+ if (I == Opt.Commands.end()) {
+ Factory.addInputSec(S, Name);
+ } else {
+ auto *Cmd = cast<OutputSectionCommand>(*I);
+ Factory.addInputSec(S, Name, Cmd->Sec);
+ auto *ISD = make<InputSectionDescription>("");
+ ISD->Sections.push_back(S);
+ Cmd->Commands.push_back(ISD);
+ }
+ }
}
static bool isTbss(OutputSection *Sec) {
@@ -475,8 +499,6 @@ static bool isTbss(OutputSection *Sec) {
}
void LinkerScript::output(InputSection *S) {
- if (!AlreadyOutputIS.insert(S).second)
- return;
bool IsTbss = isTbss(CurOutSec);
uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
@@ -508,19 +530,9 @@ void LinkerScript::output(InputSection *S) {
Dot = Pos;
}
-void LinkerScript::flush() {
- assert(CurOutSec);
- if (!AlreadyOutputOS.insert(CurOutSec).second)
- return;
- for (InputSection *I : CurOutSec->Sections)
- output(I);
-}
-
void LinkerScript::switchTo(OutputSection *Sec) {
if (CurOutSec == Sec)
return;
- if (AlreadyOutputOS.count(Sec))
- return;
CurOutSec = Sec;
@@ -571,19 +583,11 @@ void LinkerScript::process(BaseCommand &Base) {
if (!Sec->Live)
continue;
- assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec));
+ assert(CurOutSec == Sec->OutSec);
output(cast<InputSection>(Sec));
}
}
-static OutputSection *
-findSection(StringRef Name, const std::vector<OutputSection *> &Sections) {
- for (OutputSection *Sec : Sections)
- if (Sec->Name == Name)
- return Sec;
- return nullptr;
-}
-
// This function searches for a memory region to place the given output
// section in. If found, a pointer to the appropriate memory region is
// returned. Otherwise, a nullptr is returned.
@@ -638,19 +642,8 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
Dot = CurMemRegion->Offset;
switchTo(Sec);
- // flush() may add orphan sections, so the order of flush() and
- // symbol assignments is important. We want to call flush() first so
- // that symbols pointing the end of the current section points to
- // the location after orphan sections.
- auto Mid =
- std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
- [](BaseCommand *Cmd) { return !isa<SymbolAssignment>(Cmd); })
- .base();
- for (auto I = Cmd->Commands.begin(); I != Mid; ++I)
- process(**I);
- flush();
- for (auto I = Mid, E = Cmd->Commands.end(); I != E; ++I)
- process(**I);
+ for (BaseCommand *C : Cmd->Commands)
+ process(*C);
}
void LinkerScript::removeEmptyCommands() {
@@ -663,7 +656,8 @@ void LinkerScript::removeEmptyCommands() {
auto Pos = std::remove_if(
Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
- return !Cmd->Sec;
+ return std::find(OutputSections->begin(), OutputSections->end(),
+ Cmd->Sec) == OutputSections->end();
return false;
});
Opt.Commands.erase(Pos, Opt.Commands.end());
@@ -687,8 +681,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
- if (OutputSection *Sec = findSection(Cmd->Name, *OutputSections)) {
- Cmd->Sec = Sec;
+ if (OutputSection *Sec = Cmd->Sec) {
Flags = Sec->Flags;
Type = Sec->Type;
continue;
@@ -820,15 +813,24 @@ void LinkerScript::placeOrphanSections() {
++CmdIndex;
}
+ // If there is no command corresponding to this output section,
+ // create one and put a InputSectionDescription in it so that both
+ // representations agree on which input sections to use.
auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
return Cmd && Cmd->Name == Name;
});
if (Pos == E) {
auto *Cmd = make<OutputSectionCommand>(Name);
- Cmd->Sec = Sec;
Opt.Commands.insert(CmdIter, Cmd);
++CmdIndex;
+
+ Cmd->Sec = Sec;
+ auto *ISD = make<InputSectionDescription>("");
+ for (InputSection *IS : Sec->Sections)
+ ISD->Sections.push_back(IS);
+ Cmd->Commands.push_back(ISD);
+
continue;
}
@@ -846,6 +848,51 @@ void LinkerScript::processNonSectionCommands() {
}
}
+// Do a last effort at synchronizing the linker script "AST" and the section
+// list. This is needed to account for last minute changes, like adding a
+// .ARM.exidx terminator and sorting SHF_LINK_ORDER sections.
+//
+// FIXME: We should instead create the "AST" earlier and the above changes would
+// be done directly in the "AST".
+//
+// This can only handle new sections being added and sections being reordered.
+void LinkerScript::synchronize() {
+ for (BaseCommand *Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ ArrayRef<InputSection *> Sections = Cmd->Sec->Sections;
+ std::vector<InputSectionBase **> ScriptSections;
+ DenseSet<InputSectionBase *> ScriptSectionsSet;
+ for (BaseCommand *Base : Cmd->Commands) {
+ auto *ISD = dyn_cast<InputSectionDescription>(Base);
+ if (!ISD)
+ continue;
+ for (InputSectionBase *&IS : ISD->Sections) {
+ if (IS->Live) {
+ ScriptSections.push_back(&IS);
+ ScriptSectionsSet.insert(IS);
+ }
+ }
+ }
+ std::vector<InputSectionBase *> Missing;
+ for (InputSection *IS : Sections)
+ if (!ScriptSectionsSet.count(IS))
+ Missing.push_back(IS);
+ if (!Missing.empty()) {
+ auto ISD = make<InputSectionDescription>("");
+ ISD->Sections = Missing;
+ Cmd->Commands.push_back(ISD);
+ for (InputSectionBase *&IS : ISD->Sections)
+ if (IS->Live)
+ ScriptSections.push_back(&IS);
+ }
+ assert(ScriptSections.size() == Sections.size());
+ for (int I = 0, N = Sections.size(); I < N; ++I)
+ *ScriptSections[I] = Sections[I];
+ }
+}
+
void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = 0;
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 61942b2db357..dd96d335a660 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -228,7 +228,6 @@ protected:
MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
void switchTo(OutputSection *Sec);
- void flush();
void output(InputSection *Sec);
void process(BaseCommand &Base);
@@ -242,9 +241,6 @@ protected:
OutputSection *CurOutSec = nullptr;
MemoryRegion *CurMemRegion = nullptr;
- llvm::DenseSet<OutputSection *> AlreadyOutputOS;
- llvm::DenseSet<InputSectionBase *> AlreadyOutputIS;
-
public:
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
uint64_t getDot() { return Dot; }
@@ -271,6 +267,7 @@ public:
void assignOffsets(OutputSectionCommand *Cmd);
void placeOrphanSections();
void processNonSectionCommands();
+ void synchronize();
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
int getSectionIndex(StringRef Name);
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index 31c8091bb6a1..af5bc3c2c813 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -11,19 +11,19 @@
// hierarchically the output sections, input sections, input files and
// symbol:
//
-// Address Size Align Out In File Symbol
-// =================================================================
-// 00201000 00000015 4 .text
-// 00201000 0000000e 4 .text
-// 00201000 0000000e 4 test.o
-// 0020100e 00000000 0 local
-// 00201005 00000000 0 f(int)
+// Address Size Align Out In Symbol
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 test.o:(.text)
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
//
//===----------------------------------------------------------------------===//
#include "MapFile.h"
#include "InputFiles.h"
#include "Strings.h"
+#include "SymbolTable.h"
+#include "Threads.h"
#include "llvm/Support/raw_ostream.h"
@@ -33,83 +33,68 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
-static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
- uint64_t Size, uint64_t Align, StringRef Name) {
- OS << format("%0*llx %0*llx %5lld ", Width, Address, Width, Size, Align)
- << left_justify(Name, 7);
-}
-
-static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
- uint64_t Size, uint64_t Align, StringRef Name) {
- // Pass an empty name to align the text to the correct column.
- writeOutSecLine(OS, Width, Address, Size, Align, "");
- OS << ' ' << left_justify(Name, 7);
-}
+typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>>
+ SymbolMapTy;
-static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address,
- uint64_t Size, uint64_t Align, StringRef Name) {
- // Pass an empty name to align the text to the correct column.
- writeInSecLine(OS, Width, Address, Size, Align, "");
- OS << ' ' << left_justify(Name, 7);
+// Print out the first three columns of a line.
+template <class ELFT>
+static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
+ uint64_t Align) {
+ int W = ELFT::Is64Bits ? 16 : 8;
+ OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
}
-static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address,
- uint64_t Size, StringRef Name) {
- // Pass an empty name to align the text to the correct column.
- writeFileLine(OS, Width, Address, Size, 0, "");
- OS << ' ' << left_justify(Name, 7);
+static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
+
+// Returns a list of all symbols that we want to print out.
+template <class ELFT> std::vector<DefinedRegular *> getSymbols() {
+ std::vector<DefinedRegular *> V;
+ for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles())
+ for (SymbolBody *B : File->getSymbols())
+ if (B->File == File && !B->isSection())
+ if (auto *Sym = dyn_cast<DefinedRegular>(B))
+ if (Sym->Section)
+ V.push_back(Sym);
+ return V;
}
+// Returns a map from sections to their symbols.
template <class ELFT>
-static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS,
- StringRef &PrevName) {
- int Width = ELFT::Is64Bits ? 16 : 8;
- StringRef Name = IS->Name;
- if (Name != PrevName) {
- writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
- IS->Alignment, Name);
- OS << '\n';
- PrevName = Name;
- }
-
- elf::ObjectFile<ELFT> *File = IS->template getFile<ELFT>();
- if (!File)
- return;
- writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
- IS->Alignment, toString(File));
- OS << '\n';
-
- for (SymbolBody *Sym : File->getSymbols()) {
- auto *DR = dyn_cast<DefinedRegular>(Sym);
- if (!DR)
- continue;
- if (DR->Section != IS)
- continue;
- if (DR->isSection())
- continue;
- writeSymbolLine(OS, Width, Sym->getVA(), Sym->getSize<ELFT>(),
- toString(*Sym));
- OS << '\n';
+SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
+ SymbolMapTy Ret;
+ for (DefinedRegular *S : Syms)
+ Ret[S->Section].push_back(S);
+
+ // Sort symbols by address. We want to print out symbols in the
+ // order in the output file rather than the order they appeared
+ // in the input files.
+ for (auto &It : Ret) {
+ SmallVectorImpl<DefinedRegular *> &V = It.second;
+ std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
+ return A->getVA() < B->getVA();
+ });
}
+ return Ret;
}
+// Construct a map from symbols to their stringified representations.
+// Demangling symbols (which is what toString() does) is slow, so
+// we do that in batch using parallel-for.
template <class ELFT>
-static void writeMapFile2(raw_fd_ostream &OS,
- ArrayRef<OutputSection *> OutputSections) {
- int Width = ELFT::Is64Bits ? 16 : 8;
-
- OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width)
- << " Align Out In File Symbol\n";
-
- for (OutputSection *Sec : OutputSections) {
- writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Alignment, Sec->Name);
- OS << '\n';
-
- StringRef PrevName = "";
- for (InputSection *IS : Sec->Sections) {
- writeInputSection<ELFT>(OS, IS, PrevName);
- }
- }
+DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
+ std::vector<std::string> Str(Syms.size());
+ parallelFor(0, Syms.size(), [&](size_t I) {
+ raw_string_ostream OS(Str[I]);
+ writeHeader<ELFT>(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(),
+ 0);
+ OS << indent(2) << toString(*Syms[I]);
+ });
+
+ DenseMap<DefinedRegular *, std::string> Ret;
+ for (size_t I = 0, E = Syms.size(); I < E; ++I)
+ Ret[Syms[I]] = std::move(Str[I]);
+ return Ret;
}
template <class ELFT>
@@ -117,12 +102,38 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
if (Config->MapFile.empty())
return;
+ // Open a map file for writing.
std::error_code EC;
raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
- if (EC)
+ if (EC) {
error("cannot open " + Config->MapFile + ": " + EC.message());
- else
- writeMapFile2<ELFT>(OS, OutputSections);
+ return;
+ }
+
+ // Collect symbol info that we want to print out.
+ std::vector<DefinedRegular *> Syms = getSymbols<ELFT>();
+ SymbolMapTy SectionSyms = getSectionSyms<ELFT>(Syms);
+ DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms);
+
+ // Print out the header line.
+ int W = ELFT::Is64Bits ? 16 : 8;
+ OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
+ << " Align Out In Symbol\n";
+
+ // Print out file contents.
+ for (OutputSection *OSec : OutputSections) {
+ writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment);
+ OS << OSec->Name << '\n';
+
+ // Dump symbols for each input section.
+ for (InputSection *IS : OSec->Sections) {
+ writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
+ IS->Alignment);
+ OS << indent(1) << toString(IS) << '\n';
+ for (DefinedRegular *Sym : SectionSyms[IS])
+ OS << SymStr[Sym] << '\n';
+ }
+ }
}
template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>);
diff --git a/ELF/Options.td b/ELF/Options.td
index fda675449956..8863912c179c 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -344,6 +344,26 @@ def end_group_paren: Flag<["-"], ")">;
def start_group: F<"start-group">;
def start_group_paren: Flag<["-"], "(">;
+// LTO-related options.
+def lto_aa_pipeline: J<"lto-aa-pipeline=">,
+ HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_newpm_passes: J<"lto-newpm-passes=">,
+ HelpText<"Passes to run during LTO">;
+def lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
+def disable_verify: F<"disable-verify">;
+def mllvm: S<"mllvm">;
+def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
+ HelpText<"YAML output file for optimization remarks">;
+def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
+ HelpText<"Include hotness informations in the optimization remarks file">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+def thinlto_cache_policy: S<"thinlto-cache-policy">,
+ HelpText<"Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+
// Ignore LTO plugin-related options.
// clang -flto passes -plugin and -plugin-opt to the linker. This is required
// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
@@ -365,6 +385,7 @@ def no_add_needed: F<"no-add-needed">;
def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
Alias<no_add_needed>;
+def no_keep_memory: F<"no-keep-memory">;
def no_mmap_output_file: F<"no-mmap-output-file">;
def no_warn_common: F<"no-warn-common">;
def no_warn_mismatch: F<"no-warn-mismatch">;
@@ -382,23 +403,3 @@ def Qy : F<"Qy">;
// Aliases for ignored options
def alias_version_script_version_script: J<"version-script=">,
Alias<version_script>;
-
-// LTO-related options.
-def lto_aa_pipeline: J<"lto-aa-pipeline=">,
- HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
-def lto_newpm_passes: J<"lto-newpm-passes=">,
- HelpText<"Passes to run during LTO">;
-def lto_partitions: J<"lto-partitions=">,
- HelpText<"Number of LTO codegen partitions">;
-def disable_verify: F<"disable-verify">;
-def mllvm: S<"mllvm">;
-def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
- HelpText<"YAML output file for optimization remarks">;
-def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
- HelpText<"Include hotness informations in the optimization remarks file">;
-def save_temps: F<"save-temps">;
-def thinlto_cache_dir: J<"thinlto-cache-dir=">,
- HelpText<"Path to ThinLTO cached object file directory">;
-def thinlto_cache_policy: S<"thinlto-cache-policy">,
- HelpText<"Pruning policy for the ThinLTO cache">;
-def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 71fc00ac35e7..839f68f2da55 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -395,14 +395,20 @@ static void reportDiscarded(InputSectionBase *IS) {
void OutputSectionFactory::addInputSec(InputSectionBase *IS,
StringRef OutsecName) {
+ SectionKey Key = createKey(IS, OutsecName);
+ OutputSection *&Sec = Map[Key];
+ return addInputSec(IS, OutsecName, Sec);
+}
+
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+ StringRef OutsecName,
+ OutputSection *&Sec) {
if (!IS->Live) {
reportDiscarded(IS);
return;
}
- SectionKey Key = createKey(IS, OutsecName);
uint64_t Flags = getOutFlags(IS);
- OutputSection *&Sec = Map[Key];
if (Sec) {
if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
error("incompatible section flags for " + Sec->Name +
@@ -418,7 +424,7 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
}
Sec->Flags |= Flags;
} else {
- Sec = make<OutputSection>(Key.Name, IS->Type, Flags);
+ Sec = make<OutputSection>(OutsecName, IS->Type, Flags);
OutputSections.push_back(Sec);
}
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index bcda77d1a26d..6405fb38c6d6 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -141,6 +141,8 @@ public:
~OutputSectionFactory();
void addInputSec(InputSectionBase *IS, StringRef OutsecName);
+ void addInputSec(InputSectionBase *IS, StringRef OutsecName,
+ OutputSection *&Sec);
private:
llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
diff --git a/ELF/Strings.h b/ELF/Strings.h
index 934b6427105f..bcfa28144989 100644
--- a/ELF/Strings.h
+++ b/ELF/Strings.h
@@ -76,6 +76,10 @@ llvm::Optional<std::string> demangle(StringRef Name);
inline StringRef toStringRef(ArrayRef<uint8_t> Arr) {
return {(const char *)Arr.data(), Arr.size()};
}
+
+inline ArrayRef<uint8_t> toArrayRef(StringRef S) {
+ return {(const uint8_t *)S.data(), S.size()};
+}
}
}
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index e55b8bf52c10..541fc1bf6479 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -52,6 +52,9 @@ template <class ELFT> static bool isCompatible(InputFile *F) {
// Add symbols in File to the symbol table.
template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
+ if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File))
+ Config->FirstElf = File;
+
if (!isCompatible<ELFT>(File))
return;
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index e1f81940bb59..a271d31048f5 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -97,7 +97,7 @@ static ArrayRef<uint8_t> getVersion() {
// Creates a .comment section containing LLD version info.
// With this feature, you can identify LLD-generated binaries easily
-// by "objdump -s -j .comment <file>".
+// by "readelf --string-dump .comment <file>".
// The returned object is a mergeable string section.
template <class ELFT> MergeInputSection *elf::createCommentSection() {
typename ELFT::Shdr Hdr = {};
@@ -541,6 +541,13 @@ template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() {
Off += alignTo(Fde->size(), Config->Wordsize);
}
}
+
+ // The LSB standard does not allow a .eh_frame section with zero
+ // Call Frame Information records. Therefore add a CIE record length
+ // 0 as a terminator if this .eh_frame section is empty.
+ if (Off == 0)
+ Off = 4;
+
this->Size = Off;
}
@@ -1022,9 +1029,9 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() {
// fixed early.
for (StringRef S : Config->AuxiliaryList)
add({DT_AUXILIARY, In<ELFT>::DynStrTab->addString(S)});
- if (!Config->RPath.empty())
+ if (!Config->Rpath.empty())
add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- In<ELFT>::DynStrTab->addString(Config->RPath)});
+ In<ELFT>::DynStrTab->addString(Config->Rpath)});
for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles())
if (F->isNeeded())
add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->SoName)});
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 989a55af1675..e2ab48433a52 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -101,7 +101,7 @@ StringRef elf::getOutputSectionName(StringRef Name) {
for (StringRef V : {".rel.", ".rela."}) {
if (Name.startswith(V)) {
StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1));
- return Saver.save(Twine(V.drop_back()) + Inner);
+ return Saver.save(V.drop_back() + Inner);
}
}
}
@@ -123,7 +123,7 @@ StringRef elf::getOutputSectionName(StringRef Name) {
// ".zdebug_" is a prefix for ZLIB-compressed sections.
// Because we decompressed input sections, we want to remove 'z'.
if (Name.startswith(".zdebug_"))
- return Saver.save(Twine(".") + Name.substr(2));
+ return Saver.save("." + Name.substr(2));
return Name;
}
@@ -254,6 +254,7 @@ template <class ELFT> void Writer<ELFT>::run() {
fixSectionAlignments();
Script->fabricateDefaultCommands(Config->MaxPageSize);
}
+ Script->synchronize();
Script->assignAddresses(Phdrs);
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
@@ -1080,6 +1081,7 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(),
SS->OutSec->Sections.end(), SS));
+ SS->Live = false;
// If there are no other sections in the output section, remove it from the
// output.
if (SS->OutSec->Sections.empty())