aboutsummaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'ELF')
-rw-r--r--ELF/CMakeLists.txt1
-rw-r--r--ELF/Config.h9
-rw-r--r--ELF/Driver.cpp18
-rw-r--r--ELF/EhFrame.cpp2
-rw-r--r--ELF/GdbIndex.h25
-rw-r--r--ELF/ICF.cpp2
-rw-r--r--ELF/InputFiles.cpp28
-rw-r--r--ELF/InputSection.cpp44
-rw-r--r--ELF/InputSection.h2
-rw-r--r--ELF/LTO.cpp3
-rw-r--r--ELF/LinkerScript.cpp153
-rw-r--r--ELF/LinkerScript.h16
-rw-r--r--ELF/Mips.cpp2
-rw-r--r--ELF/OutputSections.cpp108
-rw-r--r--ELF/OutputSections.h6
-rw-r--r--ELF/Relocations.cpp160
-rw-r--r--ELF/Relocations.h19
-rw-r--r--ELF/ScriptParser.cpp51
-rw-r--r--ELF/SymbolTable.cpp38
-rw-r--r--ELF/SymbolTable.h5
-rw-r--r--ELF/Symbols.cpp11
-rw-r--r--ELF/SyntheticSections.cpp174
-rw-r--r--ELF/SyntheticSections.h19
-rw-r--r--ELF/Target.cpp20
-rw-r--r--ELF/Thunks.cpp8
-rw-r--r--ELF/Writer.cpp99
26 files changed, 601 insertions, 422 deletions
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index 41da497abe26..c852198bb240 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -36,6 +36,7 @@ add_lld_library(lldELF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Analysis
+ BinaryFormat
BitReader
BitWriter
Codegen
diff --git a/ELF/Config.h b/ELF/Config.h
index 54f6dc2acc7c..9c73b4c9c068 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -13,9 +13,9 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include <vector>
@@ -67,6 +67,12 @@ struct VersionDefinition {
size_t NameOff = 0; // Offset in the string table
};
+// Structure for mapping renamed symbols
+struct RenamedSymbol {
+ Symbol *Target;
+ uint8_t OrigBinding;
+};
+
// This struct contains the global configuration for the linker.
// Most fields are direct mapping from the command line options
// and such fields have the same name as the corresponding options.
@@ -98,6 +104,7 @@ struct Configuration {
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols;
bool AllowMultipleDefinition;
bool AsNeeded = false;
bool Bsymbolic;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 325404447b24..f3943b5cf655 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -185,7 +185,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
// is attempting LTO and using a default ar command that doesn't
// understand the LLVM bitcode file. It is a pretty common error, so
// we'll handle it as if it had a symbol table.
- if (!File->hasSymbolTable()) {
+ if (!File->isEmpty() && !File->hasSymbolTable()) {
for (const auto &P : getArchiveMembers(MBRef))
Files.push_back(make<LazyObjectFile>(P.first, Path, P.second));
return;
@@ -970,6 +970,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Symtab.scanShlibUndefined();
Symtab.scanVersionScript();
+ // Create wrapped symbols for -wrap option.
+ for (auto *Arg : Args.filtered(OPT_wrap))
+ Symtab.addSymbolWrap(Arg->getValue());
+
+ // Create alias symbols for -defsym option.
+ for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
+ Symtab.addSymbolAlias(Def.first, Def.second);
+
Symtab.addCombinedLTOObject();
if (ErrorCount)
return;
@@ -979,12 +987,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
for (StringRef Sym : Script->Opt.ReferencedSymbols)
Symtab.addUndefined(Sym);
- for (auto *Arg : Args.filtered(OPT_wrap))
- Symtab.wrap(Arg->getValue());
-
- // Handle --defsym=sym=alias option.
- for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
- Symtab.alias(Def.first, Def.second);
+ // Apply symbol renames for -wrap and -defsym
+ Symtab.applySymbolRenames();
// Now that we have a complete list of input files.
// Beyond this point, no new files are added.
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index 90be30a5f0f9..c4e3f65c730e 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -22,8 +22,8 @@
#include "Relocations.h"
#include "Strings.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
index 03fec64f9bd5..527667f7280e 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/GdbIndex.h
@@ -24,7 +24,30 @@ struct AddressEntry {
InputSection *Section;
uint64_t LowAddress;
uint64_t HighAddress;
- size_t CuIndex;
+ uint32_t CuIndex;
+};
+
+// Struct represents single entry of compilation units list area of gdb index.
+// It consist of CU offset in .debug_info section and it's size.
+struct CompilationUnitEntry {
+ uint64_t CuOffset;
+ uint64_t CuLength;
+};
+
+// Represents data about symbol and type names which are used
+// to build symbol table and constant pool area of gdb index.
+struct NameTypeEntry {
+ StringRef Name;
+ uint8_t Type;
+};
+
+// We fill one GdbIndexDataChunk for each object where scan of
+// debug information performed. That information futher used
+// for filling gdb index section areas.
+struct GdbIndexChunk {
+ std::vector<AddressEntry> AddressArea;
+ std::vector<CompilationUnitEntry> CompilationUnits;
+ std::vector<NameTypeEntry> NamesAndTypes;
};
// Element of GdbHashTab hash table.
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index 419ae6816328..536032bdc3a8 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -78,8 +78,8 @@
#include "SymbolTable.h"
#include "Threads.h"
#include "llvm/ADT/Hashing.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
#include <algorithm>
#include <atomic>
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 98189825ccbf..524246ed1d17 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -306,21 +306,23 @@ void elf::ObjectFile<ELFT>::initializeSections(
switch (Sec.sh_type) {
case SHT_GROUP: {
- // We discard comdat sections usually. When -r we should not do that. We
- // still do deduplication in this case to simplify implementation, because
- // otherwise merging group sections together would requre additional
- // regeneration of its contents.
- bool New = ComdatGroups
- .insert(CachedHashStringRef(
- getShtGroupSignature(ObjSections, Sec)))
- .second;
- if (New && Config->Relocatable)
- this->Sections[I] = createInputSection(Sec, SectionStringTable);
- else
- this->Sections[I] = &InputSection::Discarded;
- if (New)
+ // De-duplicate section groups by their signatures.
+ StringRef Signature = getShtGroupSignature(ObjSections, Sec);
+ bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
+ this->Sections[I] = &InputSection::Discarded;
+
+ // If it is a new section group, we want to keep group members.
+ // Group leader sections, which contain indices of group members, are
+ // discarded because they are useless beyond this point. The only
+ // exception is the -r option because in order to produce re-linkable
+ // object files, we want to pass through basically everything.
+ if (IsNew) {
+ if (Config->Relocatable)
+ this->Sections[I] = createInputSection(Sec, SectionStringTable);
continue;
+ }
+ // Otherwise, discard group members.
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
fatal(toString(this) +
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 4af05c1a187b..e82f8c3016fa 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -20,6 +20,7 @@
#include "Target.h"
#include "Thunks.h"
#include "llvm/Object/Decompressor.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Path.h"
@@ -72,6 +73,16 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
this->Alignment = V;
}
+// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
+// SHF_GROUP is a marker that a section belongs to some comdat group.
+// That flag doesn't make sense in an executable.
+static uint64_t getFlags(uint64_t Flags) {
+ Flags &= ~(uint64_t)SHF_INFO_LINK;
+ if (!Config->Relocatable)
+ Flags &= ~(uint64_t)SHF_GROUP;
+ return Flags;
+}
+
// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
// March 2017) fail to infer section types for sections starting with
// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
@@ -94,7 +105,7 @@ template <class ELFT>
InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File,
const typename ELFT::Shdr *Hdr,
StringRef Name, Kind SectionKind)
- : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK,
+ : InputSectionBase(File, getFlags(Hdr->sh_flags),
getType(Hdr->sh_type, Name), Hdr->sh_entsize,
Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign,
getSectionContents(File, Hdr), Name, SectionKind) {
@@ -308,23 +319,21 @@ OutputSection *InputSection::getParent() const {
return cast_or_null<OutputSection>(Parent);
}
-void InputSection::copyShtGroup(uint8_t *Buf) {
- assert(this->Type == SHT_GROUP);
+// Copy SHT_GROUP section contents. Used only for the -r option.
+template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
+ // ELFT::Word is the 32-bit integral type in the target endianness.
+ typedef typename ELFT::Word u32;
+ ArrayRef<u32> From = getDataAs<u32>();
+ auto *To = reinterpret_cast<u32 *>(Buf);
- ArrayRef<uint32_t> From = getDataAs<uint32_t>();
- uint32_t *To = reinterpret_cast<uint32_t *>(Buf);
-
- // First entry is a flag word, we leave it unchanged.
+ // The first entry is not a section number but a flag.
*To++ = From[0];
- // Here we adjust indices of sections that belong to group as it
- // might change during linking.
+ // Adjust section numbers because section numbers in an input object
+ // files are different in the output.
ArrayRef<InputSectionBase *> Sections = this->File->getSections();
- for (uint32_t Val : From.slice(1)) {
- uint32_t Index = read32(&Val, Config->Endianness);
- write32(To++, Sections[Index]->getOutputSection()->SectionIndex,
- Config->Endianness);
- }
+ for (uint32_t Idx : From.slice(1))
+ *To++ = Sections[Idx]->getOutputSection()->SectionIndex;
}
InputSectionBase *InputSection::getRelocatedSection() {
@@ -682,7 +691,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
// Patch a nop (0x60000000) to a ld.
if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
- // fallthrough
+ LLVM_FALLTHROUGH;
default:
Target->relocateOne(BufLoc, Type, TargetVA);
break;
@@ -712,10 +721,9 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
return;
}
- // If -r is given, linker should keep SHT_GROUP sections. We should fixup
- // them, see copyShtGroup().
+ // If -r is given, we may have a SHT_GROUP section.
if (this->Type == SHT_GROUP) {
- copyShtGroup(Buf + OutSecOff);
+ copyShtGroup<ELFT>(Buf + OutSecOff);
return;
}
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 97ca2133f905..d262b589219a 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -325,7 +325,7 @@ private:
template <class ELFT, class RelTy>
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
- void copyShtGroup(uint8_t *Buf);
+ template <class ELFT> void copyShtGroup(uint8_t *Buf);
};
// The list of all input sections.
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index 6915d9713891..3a536271db4c 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -17,13 +17,13 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/SymbolicFile.h"
#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -136,6 +136,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
if (R.Prevailing)
undefine(Sym);
+ R.LinkerRedefined = Config->RenamedSymbols.count(Sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 1ced3e8e8d71..9dd7ba52be19 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -25,9 +25,9 @@
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compression.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
@@ -54,7 +54,7 @@ uint64_t ExprValue::getValue() const {
if (Sec) {
if (OutputSection *OS = Sec->getOutputSection())
return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment);
- error("unable to evaluate expression: input section " + Sec->Name +
+ error(Loc + ": unable to evaluate expression: input section " + Sec->Name +
" has no output section assigned");
}
return alignTo(Val, Alignment);
@@ -431,6 +431,8 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
if (OutputSection *Sec = Cmd->Sec) {
assert(Sec->SectionIndex == INT_MAX);
Sec->SectionIndex = I;
+ if (Cmd->Noload)
+ Sec->Type = SHT_NOBITS;
SecToCommand[Sec] = Cmd;
}
}
@@ -442,7 +444,7 @@ void LinkerScript::fabricateDefaultCommands() {
std::vector<BaseCommand *> Commands;
// Define start address
- uint64_t StartAddr = Config->ImageBase + elf::getHeaderSize();
+ uint64_t StartAddr = -1;
// The Sections with -T<section> have been sorted in order of ascending
// address. We must lower StartAddr if the lowest -T<section address> as
@@ -450,8 +452,12 @@ void LinkerScript::fabricateDefaultCommands() {
for (auto& KV : Config->SectionStartMap)
StartAddr = std::min(StartAddr, KV.second);
- Commands.push_back(
- make<SymbolAssignment>(".", [=] { return StartAddr; }, ""));
+ Commands.push_back(make<SymbolAssignment>(
+ ".",
+ [=] {
+ return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize());
+ },
+ ""));
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
// with an InputSectionDescription describing the InputSections
@@ -870,51 +876,6 @@ 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<InputSection **> ScriptSections;
- DenseSet<InputSection *> ScriptSectionsSet;
- for (BaseCommand *Base : Cmd->Commands) {
- auto *ISD = dyn_cast<InputSectionDescription>(Base);
- if (!ISD)
- continue;
- for (InputSection *&IS : ISD->Sections) {
- if (IS->Live) {
- ScriptSections.push_back(&IS);
- ScriptSectionsSet.insert(IS);
- }
- }
- }
- std::vector<InputSection *> 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 (InputSection *&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];
- }
-}
-
static bool
allocateHeaders(std::vector<PhdrEntry> &Phdrs,
ArrayRef<OutputSectionCommand *> OutputSectionCommands,
@@ -1071,6 +1032,81 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
llvm_unreachable("unsupported Size argument");
}
+static bool compareByFilePosition(InputSection *A, InputSection *B) {
+ // Synthetic doesn't have link order dependecy, stable_sort will keep it last
+ if (A->kind() == InputSectionBase::Synthetic ||
+ B->kind() == InputSectionBase::Synthetic)
+ return false;
+ InputSection *LA = A->getLinkOrderDep();
+ InputSection *LB = B->getLinkOrderDep();
+ OutputSection *AOut = LA->getParent();
+ OutputSection *BOut = LB->getParent();
+ if (AOut != BOut)
+ return AOut->SectionIndex < BOut->SectionIndex;
+ return LA->OutSecOff < LB->OutSecOff;
+}
+
+template <class ELFT>
+static void finalizeShtGroup(OutputSection *OS,
+ ArrayRef<InputSection *> Sections) {
+ // sh_link field for SHT_GROUP sections should contain the section index of
+ // the symbol table.
+ OS->Link = InX::SymTab->getParent()->SectionIndex;
+
+ // sh_info then contain index of an entry in symbol table section which
+ // provides signature of the section group.
+ elf::ObjectFile<ELFT> *Obj = Sections[0]->getFile<ELFT>();
+ assert(Config->Relocatable && Sections.size() == 1);
+ ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
+ OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]);
+}
+
+template <class ELFT> void OutputSectionCommand::finalize() {
+ // Link order may be distributed across several InputSectionDescriptions
+ // but sort must consider them all at once.
+ std::vector<InputSection **> ScriptSections;
+ std::vector<InputSection *> Sections;
+ for (BaseCommand *Base : Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ for (InputSection *&IS : ISD->Sections) {
+ ScriptSections.push_back(&IS);
+ Sections.push_back(IS);
+ }
+
+ if ((Sec->Flags & SHF_LINK_ORDER)) {
+ std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
+ for (int I = 0, N = Sections.size(); I < N; ++I)
+ *ScriptSections[I] = Sections[I];
+
+ // We must preserve the link order dependency of sections with the
+ // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
+ // need to translate the InputSection sh_link to the OutputSection sh_link,
+ // all InputSections in the OutputSection have the same dependency.
+ if (auto *D = Sections.front()->getLinkOrderDep())
+ Sec->Link = D->getParent()->SectionIndex;
+ }
+
+ uint32_t Type = Sec->Type;
+ if (Type == SHT_GROUP) {
+ finalizeShtGroup<ELFT>(Sec, Sections);
+ return;
+ }
+
+ if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
+ return;
+
+ InputSection *First = Sections[0];
+ if (isa<SyntheticSection>(First))
+ return;
+
+ Sec->Link = InX::SymTab->getParent()->SectionIndex;
+ // sh_info for SHT_REL[A] sections should contain the section header index of
+ // the section to which the relocation applies.
+ InputSectionBase *S = First->getRelocatedSection();
+ Sec->Info = S->getOutputSection()->SectionIndex;
+ Sec->Flags |= SHF_INFO_LINK;
+}
+
// Compress section contents if this section contains debug info.
template <class ELFT> void OutputSectionCommand::maybeCompress() {
typedef typename ELFT::Chdr Elf_Chdr;
@@ -1099,6 +1135,9 @@ template <class ELFT> void OutputSectionCommand::maybeCompress() {
}
template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
+ if (Sec->Type == SHT_NOBITS)
+ return;
+
Sec->Loc = Buf;
// We may have already rendered compressed content when using
@@ -1110,9 +1149,6 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
return;
}
- if (Sec->Type == SHT_NOBITS)
- return;
-
// Write leading padding.
std::vector<InputSection *> Sections;
for (BaseCommand *Cmd : Commands)
@@ -1156,12 +1192,12 @@ bool LinkerScript::hasLMA(OutputSection *Sec) {
ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
if (S == ".")
- return {CurOutSec, Dot - CurOutSec->Addr};
+ return {CurOutSec, Dot - CurOutSec->Addr, Loc};
if (SymbolBody *B = findSymbol(S)) {
if (auto *D = dyn_cast<DefinedRegular>(B))
- return {D->Section, D->Value};
+ return {D->Section, D->Value, Loc};
if (auto *C = dyn_cast<DefinedCommon>(B))
- return {InX::Common, C->Offset};
+ return {InX::Common, C->Offset, Loc};
}
error(Loc + ": symbol not found: " + S);
return 0;
@@ -1201,3 +1237,8 @@ template void OutputSectionCommand::maybeCompress<ELF32LE>();
template void OutputSectionCommand::maybeCompress<ELF32BE>();
template void OutputSectionCommand::maybeCompress<ELF64LE>();
template void OutputSectionCommand::maybeCompress<ELF64BE>();
+
+template void OutputSectionCommand::finalize<ELF32LE>();
+template void OutputSectionCommand::finalize<ELF32BE>();
+template void OutputSectionCommand::finalize<ELF64LE>();
+template void OutputSectionCommand::finalize<ELF64BE>();
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index a708ea7f61d5..1d4c736763fb 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -42,15 +42,14 @@ struct ExprValue {
uint64_t Val;
bool ForceAbsolute;
uint64_t Alignment = 1;
+ std::string Loc;
ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val,
- uint64_t Alignment)
- : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Alignment(Alignment) {
- }
- ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val)
- : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {}
- ExprValue(SectionBase *Sec, uint64_t Val) : ExprValue(Sec, false, Val) {}
- ExprValue(uint64_t Val) : ExprValue(nullptr, Val) {}
+ const Twine &Loc)
+ : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Loc(Loc.str()) {}
+ ExprValue(SectionBase *Sec, uint64_t Val, const Twine &Loc)
+ : ExprValue(Sec, false, Val, Loc) {}
+ ExprValue(uint64_t Val) : ExprValue(nullptr, Val, "") {}
bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; }
uint64_t getValue() const;
uint64_t getSecAddr() const;
@@ -135,7 +134,9 @@ struct OutputSectionCommand : BaseCommand {
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
+ bool Noload = false;
+ template <class ELFT> void finalize();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void maybeCompress();
uint32_t getFiller();
@@ -281,7 +282,6 @@ public:
void assignOffsets(OutputSectionCommand *Cmd);
void placeOrphanSections();
void processNonSectionCommands();
- void synchronize();
void assignAddresses(std::vector<PhdrEntry> &Phdrs,
ArrayRef<OutputSectionCommand *> OutputSectionCommands);
diff --git a/ELF/Mips.cpp b/ELF/Mips.cpp
index ac65672b70fc..af92fb9d24fd 100644
--- a/ELF/Mips.cpp
+++ b/ELF/Mips.cpp
@@ -16,8 +16,8 @@
#include "SymbolTable.h"
#include "Writer.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/MipsABIFlags.h"
using namespace llvm;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 8357d6b03bb1..008871fd3889 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -16,7 +16,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
-#include "llvm/Support/Dwarf.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SHA1.h"
@@ -70,67 +70,6 @@ OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
/*Link*/ 0),
SectionIndex(INT_MAX) {}
-static bool compareByFilePosition(InputSection *A, InputSection *B) {
- // Synthetic doesn't have link order dependecy, stable_sort will keep it last
- if (A->kind() == InputSectionBase::Synthetic ||
- B->kind() == InputSectionBase::Synthetic)
- return false;
- InputSection *LA = A->getLinkOrderDep();
- InputSection *LB = B->getLinkOrderDep();
- OutputSection *AOut = LA->getParent();
- OutputSection *BOut = LB->getParent();
- if (AOut != BOut)
- return AOut->SectionIndex < BOut->SectionIndex;
- return LA->OutSecOff < LB->OutSecOff;
-}
-
-template <class ELFT> static void finalizeShtGroup(OutputSection *Sec) {
- // sh_link field for SHT_GROUP sections should contain the section index of
- // the symbol table.
- Sec->Link = InX::SymTab->getParent()->SectionIndex;
-
- // sh_info then contain index of an entry in symbol table section which
- // provides signature of the section group.
- elf::ObjectFile<ELFT> *Obj = Sec->Sections[0]->getFile<ELFT>();
- assert(Config->Relocatable && Sec->Sections.size() == 1);
- ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
- Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]);
-}
-
-template <class ELFT> void OutputSection::finalize() {
- if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
- std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
- assignOffsets();
-
- // We must preserve the link order dependency of sections with the
- // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
- // need to translate the InputSection sh_link to the OutputSection sh_link,
- // all InputSections in the OutputSection have the same dependency.
- if (auto *D = this->Sections.front()->getLinkOrderDep())
- this->Link = D->getParent()->SectionIndex;
- }
-
- uint32_t Type = this->Type;
- if (Type == SHT_GROUP) {
- finalizeShtGroup<ELFT>(this);
- return;
- }
-
- if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
- return;
-
- InputSection *First = Sections[0];
- if (isa<SyntheticSection>(First))
- return;
-
- this->Link = InX::SymTab->getParent()->SectionIndex;
- // sh_info for SHT_REL[A] sections should contain the section header index of
- // the section to which the relocation applies.
- InputSectionBase *S = First->getRelocatedSection();
- Info = S->getOutputSection()->SectionIndex;
- Flags |= SHF_INFO_LINK;
-}
-
static uint64_t updateOffset(uint64_t Off, InputSection *S) {
Off = alignTo(Off, S->Alignment);
S->OutSecOff = Off;
@@ -162,9 +101,12 @@ void OutputSection::addSection(InputSection *S) {
// This function is called after we sort input sections
// and scan relocations to setup sections' offsets.
void OutputSection::assignOffsets() {
+ OutputSectionCommand *Cmd = Script->getCmd(this);
uint64_t Off = 0;
- for (InputSection *S : Sections)
- Off = updateOffset(Off, S);
+ for (BaseCommand *Base : Cmd->Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ for (InputSection *S : ISD->Sections)
+ Off = updateOffset(Off, S);
this->Size = Off;
}
@@ -333,6 +275,31 @@ void elf::reportDiscarded(InputSectionBase *IS) {
void OutputSectionFactory::addInputSec(InputSectionBase *IS,
StringRef OutsecName) {
+ // Sections with the SHT_GROUP attribute reach here only when the - r option
+ // is given. Such sections define "section groups", and InputFiles.cpp has
+ // dedup'ed section groups by their signatures. For the -r, we want to pass
+ // through all SHT_GROUP sections without merging them because merging them
+ // creates broken section contents.
+ if (IS->Type == SHT_GROUP) {
+ OutputSection *Out = nullptr;
+ addInputSec(IS, OutsecName, Out);
+ return;
+ }
+
+ // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have
+ // relocation sections .rela.foo and .rela.bar for example. Most tools do
+ // not allow multiple REL[A] sections for output section. Hence we
+ // should combine these relocation sections into single output.
+ // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any
+ // other REL[A] sections created by linker itself.
+ if (!isa<SyntheticSection>(IS) &&
+ (IS->Type == SHT_REL || IS->Type == SHT_RELA)) {
+ auto *Sec = cast<InputSection>(IS);
+ OutputSection *Out = Sec->getRelocatedSection()->getOutputSection();
+ addInputSec(IS, OutsecName, Out->RelocationSection);
+ return;
+ }
+
SectionKey Key = createKey(IS, OutsecName);
OutputSection *&Sec = Map[Key];
return addInputSec(IS, OutsecName, Sec);
@@ -346,10 +313,6 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
return;
}
- uint64_t Flags = IS->Flags;
- if (!Config->Relocatable)
- Flags &= ~(uint64_t)SHF_GROUP;
-
if (Sec) {
if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
error("incompatible section flags for " + Sec->Name +
@@ -366,9 +329,9 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
"\n>>> output section " + Sec->Name + ": " +
getELFSectionTypeName(Config->EMachine, Sec->Type));
}
- Sec->Flags |= Flags;
+ Sec->Flags |= IS->Flags;
} else {
- Sec = make<OutputSection>(OutsecName, IS->Type, Flags);
+ Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags);
OutputSections.push_back(Sec);
}
@@ -405,8 +368,3 @@ template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
-
-template void OutputSection::finalize<ELF32LE>();
-template void OutputSection::finalize<ELF32BE>();
-template void OutputSection::finalize<ELF64LE>();
-template void OutputSection::finalize<ELF64BE>();
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 0f2fe68ca708..7b093fb9dee7 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -67,6 +67,11 @@ public:
// formula: Off = Off_first + VA - VA_first.
OutputSection *FirstInPtLoad = nullptr;
+ // Pointer to a relocation section for this section. Usually nullptr because
+ // we consume relocations, but if --emit-relocs is specified (which is rare),
+ // it may have a non-null value.
+ OutputSection *RelocationSection = nullptr;
+
// The following fields correspond to Elf_Shdr members.
uint64_t Size = 0;
uint64_t Offset = 0;
@@ -78,7 +83,6 @@ public:
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
- template <class ELFT> void finalize();
void assignOffsets();
std::vector<InputSection *> Sections;
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 54cc6dd89d46..98c1349a2f0d 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -43,6 +43,7 @@
#include "Relocations.h"
#include "Config.h"
+#include "LinkerScript.h"
#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
@@ -967,48 +968,51 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
// in the Sections vector, and recalculate the InputSection output section
// offsets.
// This may invalidate any output section offsets stored outside of InputSection
-void ThunkCreator::mergeThunks(OutputSection *OS,
- std::vector<ThunkSection *> &Thunks) {
- // Order Thunks in ascending OutSecOff
- auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) {
- return A->OutSecOff < B->OutSecOff;
- };
- std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
-
- // Merge sorted vectors of Thunks and InputSections by OutSecOff
- std::vector<InputSection *> Tmp;
- Tmp.reserve(OS->Sections.size() + Thunks.size());
- auto MergeCmp = [](const InputSection *A, const InputSection *B) {
- // std::merge requires a strict weak ordering.
- if (A->OutSecOff < B->OutSecOff)
- return true;
- if (A->OutSecOff == B->OutSecOff)
- // Check if Thunk is immediately before any specific Target InputSection
- // for example Mips LA25 Thunks.
- if (auto *TA = dyn_cast<ThunkSection>(A))
- if (TA && TA->getTargetInputSection() == B)
- return true;
- return false;
- };
- std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(),
- Thunks.end(), std::back_inserter(Tmp), MergeCmp);
- OS->Sections = std::move(Tmp);
- OS->assignOffsets();
+void ThunkCreator::mergeThunks() {
+ for (auto &KV : ThunkSections) {
+ std::vector<InputSection *> *ISR = KV.first;
+ std::vector<ThunkSection *> &Thunks = KV.second;
+
+ // Order Thunks in ascending OutSecOff
+ auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) {
+ return A->OutSecOff < B->OutSecOff;
+ };
+ std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
+
+ // Merge sorted vectors of Thunks and InputSections by OutSecOff
+ std::vector<InputSection *> Tmp;
+ Tmp.reserve(ISR->size() + Thunks.size());
+ auto MergeCmp = [](const InputSection *A, const InputSection *B) {
+ // std::merge requires a strict weak ordering.
+ if (A->OutSecOff < B->OutSecOff)
+ return true;
+ if (A->OutSecOff == B->OutSecOff)
+ // Check if Thunk is immediately before any specific Target InputSection
+ // for example Mips LA25 Thunks.
+ if (auto *TA = dyn_cast<ThunkSection>(A))
+ if (TA && TA->getTargetInputSection() == B)
+ return true;
+ return false;
+ };
+ std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(),
+ std::back_inserter(Tmp), MergeCmp);
+ *ISR = std::move(Tmp);
+ }
}
-ThunkSection *ThunkCreator::getOSThunkSec(ThunkSection *&TS,
- OutputSection *OS) {
- if (TS == nullptr) {
+ThunkSection *ThunkCreator::getOSThunkSec(OutputSection *OS,
+ std::vector<InputSection *> *ISR) {
+ if (CurTS == nullptr) {
uint32_t Off = 0;
for (auto *IS : OS->Sections) {
Off = IS->OutSecOff + IS->getSize();
if ((IS->Flags & SHF_EXECINSTR) == 0)
break;
}
- TS = make<ThunkSection>(OS, Off);
- ThunkSections[OS].push_back(TS);
+ CurTS = make<ThunkSection>(OS, Off);
+ ThunkSections[ISR].push_back(CurTS);
}
- return TS;
+ return CurTS;
}
ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
@@ -1017,7 +1021,21 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
return TS;
auto *TOS = IS->getParent();
TS = make<ThunkSection>(TOS, IS->OutSecOff);
- ThunkSections[TOS].push_back(TS);
+
+ // Find InputSectionRange within TOS that IS is in
+ OutputSectionCommand *C = Script->getCmd(TOS);
+ std::vector<InputSection *> *Range = nullptr;
+ for (BaseCommand *BC : C->Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription> (BC)) {
+ InputSection *first = ISD->Sections.front();
+ InputSection *last = ISD->Sections.back();
+ if (IS->OutSecOff >= first->OutSecOff &&
+ IS->OutSecOff <= last->OutSecOff) {
+ Range = &ISD->Sections;
+ break;
+ }
+ }
+ ThunkSections[Range].push_back(TS);
ThunkedSections[IS] = TS;
return TS;
}
@@ -1030,6 +1048,27 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
return std::make_pair(res.first->second, res.second);
}
+// Call Fn on every executable InputSection accessed via the linker script
+// InputSectionDescription::Sections.
+void ThunkCreator::forEachExecInputSection(
+ ArrayRef<OutputSectionCommand *> OutputSections,
+ std::function<void(OutputSection *, std::vector<InputSection *> *,
+ InputSection *)>
+ Fn) {
+ for (OutputSectionCommand *Cmd : OutputSections) {
+ OutputSection *OS = Cmd->Sec;
+ if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+ continue;
+ if (OutputSectionCommand *C = Script->getCmd(OS))
+ for (BaseCommand *BC : C->Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+ CurTS = nullptr;
+ for (InputSection* IS : ISD->Sections)
+ Fn(OS, &ISD->Sections, IS);
+ }
+ }
+}
+
// Process all relocations from the InputSections that have been assigned
// to OutputSections and redirect through Thunks if needed.
//
@@ -1040,42 +1079,41 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
//
// FIXME: All Thunks are assumed to be in range of the relocation. Range
// extension Thunks are not yet supported.
-bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
+bool ThunkCreator::createThunks(
+ ArrayRef<OutputSectionCommand *> OutputSections) {
// Create all the Thunks and insert them into synthetic ThunkSections. The
// ThunkSections are later inserted back into the OutputSection.
// We separate the creation of ThunkSections from the insertion of the
// ThunkSections back into the OutputSection as ThunkSections are not always
// inserted into the same OutputSection as the caller.
- for (OutputSection *OS : OutputSections) {
- ThunkSection *OSTS = nullptr;
- for (InputSection *IS : OS->Sections) {
- for (Relocation &Rel : IS->Relocations) {
- SymbolBody &Body = *Rel.Sym;
- if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
- continue;
- Thunk *T;
- bool IsNew;
- std::tie(T, IsNew) = getThunk(Body, Rel.Type);
- if (IsNew) {
- // Find or create a ThunkSection for the new Thunk
- ThunkSection *TS;
- if (auto *TIS = T->getTargetInputSection())
- TS = getISThunkSec(TIS, OS);
- else
- TS = getOSThunkSec(OSTS, OS);
- TS->addThunk(T);
+ forEachExecInputSection(
+ OutputSections, [=](OutputSection *OS, std::vector<InputSection*> *ISR,
+ InputSection *IS) {
+ for (Relocation &Rel : IS->Relocations) {
+ SymbolBody &Body = *Rel.Sym;
+ if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
+ continue;
+ Thunk *T;
+ bool IsNew;
+ std::tie(T, IsNew) = getThunk(Body, Rel.Type);
+ if (IsNew) {
+ // Find or create a ThunkSection for the new Thunk
+ ThunkSection *TS;
+ if (auto *TIS = T->getTargetInputSection())
+ TS = getISThunkSec(TIS, OS);
+ else
+ TS = getOSThunkSec(OS, ISR);
+ TS->addThunk(T);
+ }
+ // Redirect relocation to Thunk, we never go via the PLT to a Thunk
+ Rel.Sym = T->ThunkSym;
+ Rel.Expr = fromPlt(Rel.Expr);
}
- // Redirect relocation to Thunk, we never go via the PLT to a Thunk
- Rel.Sym = T->ThunkSym;
- Rel.Expr = fromPlt(Rel.Expr);
- }
- }
- }
+ });
// Merge all created synthetic ThunkSections back into OutputSection
- for (auto &KV : ThunkSections)
- mergeThunks(KV.first, KV.second);
+ mergeThunks();
return !ThunkSections.empty();
}
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 206f0d9423c9..dcbf545cde53 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -21,6 +21,7 @@ class SymbolBody;
class InputSection;
class InputSectionBase;
class OutputSection;
+struct OutputSectionCommand;
// List of target-independent relocation types. Relocations read
// from files are converted to these types so that the main code
@@ -123,12 +124,18 @@ class Thunk;
class ThunkCreator {
public:
// Return true if Thunks have been added to OutputSections
- bool createThunks(ArrayRef<OutputSection *> OutputSections);
+ bool createThunks(ArrayRef<OutputSectionCommand *> OutputSections);
private:
- void mergeThunks(OutputSection *OS, std::vector<ThunkSection *> &Thunks);
- ThunkSection *getOSThunkSec(ThunkSection *&TS, OutputSection *OS);
+ void mergeThunks();
+ ThunkSection *getOSThunkSec(OutputSection *OS,
+ std::vector<InputSection *> *ISR);
ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS);
+ void forEachExecInputSection(
+ ArrayRef<OutputSectionCommand *> OutputSections,
+ std::function<void(OutputSection *, std::vector<InputSection *> *,
+ InputSection *)>
+ Fn);
std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
// Track Symbols that already have a Thunk
@@ -138,7 +145,11 @@ private:
llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
// Track the ThunksSections that need to be inserted into an OutputSection
- std::map<OutputSection *, std::vector<ThunkSection *>> ThunkSections;
+ std::map<std::vector<InputSection *> *, std::vector<ThunkSection *>>
+ ThunkSections;
+
+ // The ThunkSection for this vector of InputSections
+ ThunkSection *CurTS;
};
// Return a int64_t to make sure we get the sign extension out of the way as
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index 02212fa8ba14..4a44944fe7ed 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -25,8 +25,8 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -76,6 +76,7 @@ private:
BytesDataCommand *readBytesDataCommand(StringRef Tok);
uint32_t readFill();
uint32_t parseFill(StringRef Tok);
+ void readSectionAddressType(OutputSectionCommand *Cmd);
OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
std::vector<StringRef> readOutputSectionPhdrs();
InputSectionDescription *readInputSectionDescription(StringRef Tok);
@@ -127,16 +128,16 @@ static void moveAbsRight(ExprValue &A, ExprValue &B) {
if (A.isAbsolute())
std::swap(A, B);
if (!B.isAbsolute())
- error("At least one side of the expression must be absolute");
+ error(A.Loc + ": at least one side of the expression must be absolute");
}
static ExprValue add(ExprValue A, ExprValue B) {
moveAbsRight(A, B);
- return {A.Sec, A.ForceAbsolute, A.Val + B.getValue()};
+ return {A.Sec, A.ForceAbsolute, A.Val + B.getValue(), A.Loc};
}
static ExprValue sub(ExprValue A, ExprValue B) {
- return {A.Sec, A.Val - B.getValue()};
+ return {A.Sec, A.Val - B.getValue(), A.Loc};
}
static ExprValue mul(ExprValue A, ExprValue B) {
@@ -153,13 +154,13 @@ static ExprValue div(ExprValue A, ExprValue B) {
static ExprValue bitAnd(ExprValue A, ExprValue B) {
moveAbsRight(A, B);
return {A.Sec, A.ForceAbsolute,
- (A.getValue() & B.getValue()) - A.getSecAddr()};
+ (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc};
}
static ExprValue bitOr(ExprValue A, ExprValue B) {
moveAbsRight(A, B);
return {A.Sec, A.ForceAbsolute,
- (A.getValue() | B.getValue()) - A.getSecAddr()};
+ (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc};
}
void ScriptParser::readDynamicList() {
@@ -563,16 +564,42 @@ uint32_t ScriptParser::readFill() {
return V;
}
+// Reads an expression and/or the special directive "(NOLOAD)" for an
+// output section definition.
+//
+// An output section name can be followed by an address expression
+// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be
+// interpreted as either the beginning of some expression or "(NOLOAD)".
+//
+// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
+// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
+void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) {
+ if (consume("(")) {
+ if (consume("NOLOAD")) {
+ expect(")");
+ Cmd->Noload = true;
+ return;
+ }
+ Cmd->AddrExpr = readExpr();
+ expect(")");
+ } else {
+ Cmd->AddrExpr = readExpr();
+ }
+
+ if (consume("(")) {
+ expect("NOLOAD");
+ expect(")");
+ Cmd->Noload = true;
+ }
+}
+
OutputSectionCommand *
ScriptParser::readOutputSectionDescription(StringRef OutSec) {
OutputSectionCommand *Cmd =
Script->createOutputSectionCommand(OutSec, getCurrentLocation());
- // Read an address expression.
- // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
if (peek() != ":")
- Cmd->AddrExpr = readExpr();
-
+ readSectionAddressType(Cmd);
expect(":");
if (consume("AT"))
@@ -859,7 +886,9 @@ Expr ScriptParser::readPrimary() {
if (Tok == "ADDR") {
StringRef Name = readParenLiteral();
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
- return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; };
+ return [=]() -> ExprValue {
+ return {checkSection(Cmd, Location), 0, Location};
+ };
}
if (Tok == "ALIGN") {
expect("(");
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index ed8a790c9599..a223aec98624 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -156,7 +156,7 @@ template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
// 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) {
+template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
SymbolBody *B = find(Name);
if (!B)
return;
@@ -164,16 +164,16 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
Symbol *Real = addUndefined(Saver.save("__real_" + Name));
Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
- // We rename symbols by replacing the old symbol's SymbolBody with the new
- // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
- // old symbol to instead refer to the new symbol.
- memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
- memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
+ // Tell LTO not to eliminate this symbol
+ Wrap->IsUsedInRegularObj = true;
+
+ Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding};
+ Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding};
}
// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
-template <class ELFT>
-void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) {
+template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias,
+ StringRef Name) {
SymbolBody *B = find(Name);
if (!B) {
error("-defsym: undefined symbol: " + Name);
@@ -181,7 +181,27 @@ void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) {
}
Symbol *Sym = B->symbol();
Symbol *AliasSym = addUndefined(Alias);
- memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body));
+
+ // Tell LTO not to eliminate this symbol
+ Sym->IsUsedInRegularObj = true;
+ Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding};
+}
+
+// Apply symbol renames created by -wrap and -defsym. The renames are created
+// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform
+// LTO (if LTO is running) not to include these symbols in IPO. Now that the
+// symbols are finalized, we can perform the replacement.
+template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
+ for (auto &KV : Config->RenamedSymbols) {
+ Symbol *Sym = KV.first;
+ Symbol *Rename = KV.second.Target;
+ Sym->Binding = KV.second.OrigBinding;
+
+ // We rename symbols by replacing the old symbol's SymbolBody with the new
+ // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
+ // old symbol to instead refer to the new symbol.
+ memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body));
+ }
}
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 1a745f9deea5..f38d09760c7e 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -39,6 +39,9 @@ template <class ELFT> class SymbolTable {
public:
void addFile(InputFile *File);
void addCombinedLTOObject();
+ void addSymbolAlias(StringRef Alias, StringRef Name);
+ void addSymbolWrap(StringRef Name);
+ void applySymbolRenames();
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; }
@@ -85,8 +88,6 @@ public:
SymbolBody *findInCurrentDSO(StringRef Name);
void trace(StringRef Name);
- void wrap(StringRef Name);
- void alias(StringRef Alias, StringRef Name);
private:
std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 67e57d9c8f00..8f9b20477b29 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -264,15 +264,14 @@ Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
: SymbolBody(K, Name, IsLocal, StOther, Type) {}
template <class ELFT> bool DefinedRegular::isMipsPIC() const {
+ typedef typename ELFT::Ehdr Elf_Ehdr;
if (!Section || !isFunc())
return false;
+
+ auto *Sec = cast<InputSectionBase>(Section);
+ const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (cast<InputSectionBase>(Section)
- ->template getFile<ELFT>()
- ->getObj()
- .getHeader()
- ->e_flags &
- EF_MIPS_PIC);
+ (Hdr->e_flags & EF_MIPS_PIC);
}
Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 223fc9a0fd07..5cd6c5f2b914 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -27,9 +27,9 @@
#include "Threads.h"
#include "Writer.h"
#include "lld/Config/Version.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/RandomNumberGenerator.h"
@@ -1691,49 +1691,44 @@ static uint32_t hash(StringRef Str) {
return R;
}
-static std::vector<std::pair<uint64_t, uint64_t>>
-readCuList(DWARFContext &Dwarf, InputSection *Sec) {
- std::vector<std::pair<uint64_t, uint64_t>> Ret;
+static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf,
+ InputSection *Sec) {
+ std::vector<CompilationUnitEntry> Ret;
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
return Ret;
}
-static InputSection *findSection(ArrayRef<InputSectionBase *> Arr,
- uint64_t Offset) {
- for (InputSectionBase *S : Arr)
- if (auto *IS = dyn_cast_or_null<InputSection>(S))
- if (IS != &InputSection::Discarded && IS->Live &&
- Offset >= IS->getOffsetInFile() &&
- Offset < IS->getOffsetInFile() + IS->getSize())
- return IS;
- return nullptr;
-}
-
-static std::vector<AddressEntry>
-readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) {
+static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf,
+ InputSection *Sec) {
std::vector<AddressEntry> Ret;
+ uint32_t CurrentCu = 0;
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) {
DWARFAddressRangesVector Ranges;
CU->collectAddressRanges(Ranges);
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
- for (DWARFAddressRange &R : Ranges)
- if (InputSection *S = findSection(Sections, R.LowPC))
- Ret.push_back({S, R.LowPC - S->getOffsetInFile(),
- R.HighPC - S->getOffsetInFile(), CurrentCU});
- ++CurrentCU;
+ for (DWARFAddressRange &R : Ranges) {
+ InputSectionBase *S = Sections[R.SectionIndex];
+ if (!S || S == &InputSection::Discarded || !S->Live)
+ continue;
+ // Range list with zero size has no effect.
+ if (R.LowPC == R.HighPC)
+ continue;
+ Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu});
+ }
+ ++CurrentCu;
}
return Ret;
}
-static std::vector<std::pair<StringRef, uint8_t>>
-readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) {
+static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf,
+ bool IsLE) {
StringRef Data[] = {Dwarf.getGnuPubNamesSection(),
Dwarf.getGnuPubTypesSection()};
- std::vector<std::pair<StringRef, uint8_t>> Ret;
+ std::vector<NameTypeEntry> Ret;
for (StringRef D : Data) {
DWARFDebugPubTable PubTable(D, IsLE, true);
for (const DWARFDebugPubTable::Set &Set : PubTable.getData())
@@ -1743,52 +1738,77 @@ readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) {
return Ret;
}
-class ObjInfoTy : public llvm::LoadedObjectInfo {
- uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
- auto &S = static_cast<const object::ELFSectionRef &>(Sec);
- if (S.getFlags() & ELF::SHF_ALLOC)
- return S.getOffset();
- return 0;
- }
+static std::vector<InputSection *> getDebugInfoSections() {
+ std::vector<InputSection *> Ret;
+ for (InputSectionBase *S : InputSections)
+ if (InputSection *IS = dyn_cast<InputSection>(S))
+ if (IS->getParent() && IS->Name == ".debug_info")
+ Ret.push_back(IS);
+ return Ret;
+}
- std::unique_ptr<llvm::LoadedObjectInfo> clone() const override { return {}; }
-};
+void GdbIndexSection::buildIndex() {
+ std::vector<InputSection *> V = getDebugInfoSections();
+ if (V.empty())
+ return;
+
+ for (InputSection *Sec : V)
+ Chunks.push_back(readDwarf(Sec));
+
+ uint32_t CuId = 0;
+ for (GdbIndexChunk &D : Chunks) {
+ for (AddressEntry &E : D.AddressArea)
+ E.CuIndex += CuId;
+
+ // Populate constant pool area.
+ for (NameTypeEntry &NameType : D.NamesAndTypes) {
+ uint32_t Hash = hash(NameType.Name);
+ size_t Offset = StringPool.add(NameType.Name);
+
+ bool IsNew;
+ GdbSymbol *Sym;
+ std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
+ if (IsNew) {
+ Sym->CuVectorIndex = CuVectors.size();
+ CuVectors.resize(CuVectors.size() + 1);
+ }
-void GdbIndexSection::readDwarf(InputSection *Sec) {
+ CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24));
+ }
+
+ CuId += D.CompilationUnits.size();
+ }
+}
+
+GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) {
Expected<std::unique_ptr<object::ObjectFile>> Obj =
object::ObjectFile::createObjectFile(Sec->File->MB);
if (!Obj) {
error(toString(Sec->File) + ": error creating DWARF context");
- return;
+ return {};
}
- ObjInfoTy ObjInfo;
- DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo);
-
- size_t CuId = CompilationUnits.size();
- for (std::pair<uint64_t, uint64_t> &P : readCuList(Dwarf, Sec))
- CompilationUnits.push_back(P);
-
- for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId))
- AddressArea.push_back(Ent);
-
- std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes =
- readPubNamesAndTypes(Dwarf, Config->IsLE);
+ DWARFContextInMemory Dwarf(*Obj.get());
- for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) {
- uint32_t Hash = hash(Pair.first);
- size_t Offset = StringPool.add(Pair.first);
+ GdbIndexChunk Ret;
+ Ret.CompilationUnits = readCuList(Dwarf, Sec);
+ Ret.AddressArea = readAddressArea(Dwarf, Sec);
+ Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
+ return Ret;
+}
- bool IsNew;
- GdbSymbol *Sym;
- std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
- if (IsNew) {
- Sym->CuVectorIndex = CuVectors.size();
- CuVectors.resize(CuVectors.size() + 1);
- }
+static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
+ size_t Ret = 0;
+ for (GdbIndexChunk &D : C)
+ Ret += D.CompilationUnits.size();
+ return Ret;
+}
- CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId);
- }
+static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) {
+ size_t Ret = 0;
+ for (GdbIndexChunk &D : C)
+ Ret += D.AddressArea.size();
+ return Ret;
}
void GdbIndexSection::finalizeContents() {
@@ -1796,17 +1816,14 @@ void GdbIndexSection::finalizeContents() {
return;
Finalized = true;
- for (InputSectionBase *S : InputSections)
- if (InputSection *IS = dyn_cast<InputSection>(S))
- if (IS->getParent() && IS->Name == ".debug_info")
- readDwarf(IS);
+ buildIndex();
SymbolTable.finalizeContents();
// GdbIndex header consist from version fields
// and 5 more fields with different kinds of offsets.
- CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize;
- SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize;
+ CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize;
+ SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize;
ConstantPoolOffset =
SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
@@ -1835,19 +1852,24 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
Buf += 24;
// Write the CU list.
- for (std::pair<uint64_t, uint64_t> CU : CompilationUnits) {
- write64le(Buf, CU.first);
- write64le(Buf + 8, CU.second);
- Buf += 16;
+ for (GdbIndexChunk &D : Chunks) {
+ for (CompilationUnitEntry &Cu : D.CompilationUnits) {
+ write64le(Buf, Cu.CuOffset);
+ write64le(Buf + 8, Cu.CuLength);
+ Buf += 16;
+ }
}
// Write the address area.
- for (AddressEntry &E : AddressArea) {
- uint64_t BaseAddr = E.Section->getParent()->Addr + E.Section->getOffset(0);
- write64le(Buf, BaseAddr + E.LowAddress);
- write64le(Buf + 8, BaseAddr + E.HighAddress);
- write32le(Buf + 16, E.CuIndex);
- Buf += 20;
+ for (GdbIndexChunk &D : Chunks) {
+ for (AddressEntry &E : D.AddressArea) {
+ uint64_t BaseAddr =
+ E.Section->getParent()->Addr + E.Section->getOffset(0);
+ write64le(Buf, BaseAddr + E.LowAddress);
+ write64le(Buf + 8, BaseAddr + E.HighAddress);
+ write32le(Buf + 16, E.CuIndex);
+ Buf += 20;
+ }
}
// Write the symbol table.
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index b47d2fab24ec..c807043c9dc2 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -509,20 +509,23 @@ public:
size_t getSize() const override;
bool empty() const override;
- // Pairs of [CU Offset, CU length].
- std::vector<std::pair<uint64_t, uint64_t>> CompilationUnits;
-
- llvm::StringTableBuilder StringPool;
-
+ // Symbol table is a hash table for types and names.
+ // It is the area of gdb index.
GdbHashTab SymbolTable;
- // The CU vector portion of the constant pool.
+ // CU vector is a part of constant pool area of section.
std::vector<std::set<uint32_t>> CuVectors;
- std::vector<AddressEntry> AddressArea;
+ // String pool is also a part of constant pool, it follows CU vectors.
+ llvm::StringTableBuilder StringPool;
+
+ // Each chunk contains information gathered from a debug sections of single
+ // object and used to build different areas of gdb index.
+ std::vector<GdbIndexChunk> Chunks;
private:
- void readDwarf(InputSection *Sec);
+ GdbIndexChunk readDwarf(InputSection *Sec);
+ void buildIndex();
uint32_t CuTypesOffset;
uint32_t SymTabOffset;
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index b6c6e7089365..ee5a7690fc64 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -35,8 +35,8 @@
#include "Thunks.h"
#include "Writer.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
@@ -537,7 +537,17 @@ void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
write16le(Loc, Val);
break;
case R_386_PC16:
- checkInt<16>(Loc, Val, Type);
+ // R_386_PC16 is normally used with 16 bit code. In that situation
+ // the PC is 16 bits, just like the addend. This means that it can
+ // point from any 16 bit address to any other if the possibility
+ // of wrapping is included.
+ // The only restriction we have to check then is that the destination
+ // address fits in 16 bits. That is impossible to do here. The problem is
+ // that we are passed the final value, which already had the
+ // current location subtracted from it.
+ // We just check that Val fits in 17 bits. This misses some cases, but
+ // should have no false positives.
+ checkInt<17>(Loc, Val, Type);
write16le(Loc, Val);
break;
default:
@@ -2085,7 +2095,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
return R_MIPS_GOT_GP_PC;
if (&S == ElfSym::MipsLocalGp)
return R_MIPS_GOT_GP;
- // fallthrough
+ LLVM_FALLTHROUGH;
case R_MIPS_GOT_OFST:
return R_ABS;
case R_MIPS_PC32:
@@ -2099,7 +2109,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
case R_MIPS_GOT16:
if (S.isLocal())
return R_MIPS_GOT_LOCAL_PAGE;
- // fallthrough
+ LLVM_FALLTHROUGH;
case R_MIPS_CALL16:
case R_MIPS_GOT_DISP:
case R_MIPS_TLS_GOTTPREL:
@@ -2353,7 +2363,7 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:
checkInt<16>(Loc, Val, Type);
- // fallthrough
+ LLVM_FALLTHROUGH;
case R_MIPS_CALL16:
case R_MIPS_CALL_LO16:
case R_MIPS_GOT_LO16:
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index da2b13677513..752a881d7867 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -30,8 +30,8 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
@@ -143,7 +143,7 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
ThunkSym = addSyntheticLocal(
Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), &IS);
+ Offset | 0x1, size(), &IS);
addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
}
@@ -176,7 +176,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
0x60, 0x47, // bx r12
};
uint64_t S = getARMThunkDestVA(Destination);
- uint64_t P = ThunkSym->getVA();
+ uint64_t P = ThunkSym->getVA() & ~0x1;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
@@ -185,7 +185,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
ThunkSym = addSyntheticLocal(
Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC,
- Offset, size(), &IS);
+ Offset | 0x1, size(), &IS);
addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
}
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index f68e07fc69d7..ad95a8acced4 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -93,21 +93,14 @@ private:
} // anonymous namespace
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("." + Name.substr(2));
+
if (Config->Relocatable)
return Name;
- // If -emit-relocs is given (which is rare), we need to copy
- // relocation sections to the output. If input section .foo is
- // output as .bar, we want to rename .rel.foo .rel.bar as well.
- if (Config->EmitRelocs) {
- for (StringRef V : {".rel.", ".rela."}) {
- if (Name.startswith(V)) {
- StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1));
- return Saver.save(V.drop_back() + Inner);
- }
- }
- }
-
for (StringRef V :
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
@@ -122,10 +115,6 @@ StringRef elf::getOutputSectionName(StringRef Name) {
if (Name == "COMMON")
return ".bss";
- // ".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("." + Name.substr(2));
return Name;
}
@@ -257,18 +246,7 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
- if (!Script->Opt.HasSections)
- Script->fabricateDefaultCommands();
- else
- Script->synchronize();
-
- for (BaseCommand *Base : Script->Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
- OutputSectionCommands.push_back(Cmd);
-
- clearOutputSections();
-
- if (!Script->Opt.HasSections &&!Config->Relocatable)
+ if (!Script->Opt.HasSections && !Config->Relocatable)
fixSectionAlignments();
// If -compressed-debug-sections is specified, we need to compress
@@ -278,22 +256,24 @@ template <class ELFT> void Writer<ELFT>::run() {
OutputSectionCommands.begin(), OutputSectionCommands.end(),
[](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
- if (Config->Relocatable) {
- assignFileOffsets();
- } else {
- Script->assignAddresses(Phdrs, OutputSectionCommands);
+ Script->assignAddresses(Phdrs, OutputSectionCommands);
- // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
- // 0 sized region. This has to be done late since only after assignAddresses
- // we know the size of the sections.
- removeEmptyPTLoad();
+ // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
+ // 0 sized region. This has to be done late since only after assignAddresses
+ // we know the size of the sections.
+ removeEmptyPTLoad();
- if (!Config->OFormatBinary)
- assignFileOffsets();
- else
- assignFileOffsetsBinary();
+ if (!Config->OFormatBinary)
+ assignFileOffsets();
+ else
+ assignFileOffsetsBinary();
+
+ setPhdrs();
- setPhdrs();
+ if (Config->Relocatable) {
+ for (OutputSectionCommand *Cmd : OutputSectionCommands)
+ Cmd->Sec->Addr = 0;
+ } else {
fixPredefinedSymbols();
}
@@ -915,7 +895,14 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// this symbol unconditionally even when using a linker script, which
// differs from the behavior implemented by GNU linker which only define
// this symbol if ELF headers are in the memory mapped segment.
- addOptionalRegular<ELFT>("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
+ // __executable_start is not documented, but the expectation of at
+ // least the android libc is that it points to the elf header too.
+ // __dso_handle symbol is passed to cxa_finalize as a marker to identify
+ // each DSO. The address of the symbol doesn't matter as long as they are
+ // different in different DSOs, so we chose the start address of the DSO.
+ for (const char *Name :
+ {"__ehdr_start", "__executable_start", "__dso_handle"})
+ addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN);
// If linker script do layout we do not need to create any standart symbols.
if (Script->Opt.HasSections)
@@ -1011,9 +998,6 @@ template <class ELFT> void Writer<ELFT>::createSections() {
sortInitFini(findSection(".fini_array"));
sortCtorsDtors(findSection(".ctors"));
sortCtorsDtors(findSection(".dtors"));
-
- for (OutputSection *Sec : OutputSections)
- Sec->assignOffsets();
}
// We want to find how similar two ranks are.
@@ -1116,10 +1100,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
std::function<void(SyntheticSection *)> Fn) {
for (SyntheticSection *SS : Sections)
- if (SS && SS->getParent() && !SS->empty()) {
+ if (SS && SS->getParent() && !SS->empty())
Fn(SS);
- SS->getParent()->assignOffsets();
- }
}
// We need to add input synthetic sections early in createSyntheticSections()
@@ -1225,6 +1207,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Sec->ShName = InX::ShStrTab->addString(Sec->Name);
}
+ if (!Script->Opt.HasSections)
+ Script->fabricateDefaultCommands();
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ OutputSectionCommands.push_back(Cmd);
+
// Binary and relocatable output does not have PHDRS.
// The headers have to be created before finalize as that can influence the
// image base and the dynamic section on mips includes the image base.
@@ -1234,6 +1222,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
}
+ clearOutputSections();
+
+ // Compute the size of .rela.dyn and .rela.plt early since we need
+ // them to populate .dynamic.
+ for (SyntheticSection *SS : {In<ELFT>::RelaDyn, In<ELFT>::RelaPlt})
+ if (SS->getParent() && !SS->empty())
+ SS->getParent()->assignOffsets();
+
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo,
@@ -1257,15 +1253,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// are out of range. This will need to turn into a loop that converges
// when no more Thunks are added
ThunkCreator TC;
- if (TC.createThunks(OutputSections))
+ if (TC.createThunks(OutputSectionCommands))
applySynthetic({InX::MipsGot},
[](SyntheticSection *SS) { SS->updateAllocSize(); });
}
+
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
- for (OutputSection *Sec : OutputSections)
- Sec->finalize<ELFT>();
+ for (OutputSectionCommand *Cmd : OutputSectionCommands)
+ Cmd->finalize<ELFT>();
// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},