aboutsummaryrefslogtreecommitdiff
path: root/ELF/InputFiles.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:12:21 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:12:21 +0000
commiteb1ff93d02b5f17b6b409e83c6d9be585f4a04b3 (patch)
tree7490b4a8943293f251ad733465936e6ec302b3e9 /ELF/InputFiles.cpp
parentbafea25f368c63f0b39789906adfed6e39219e64 (diff)
downloadsrc-eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3.tar.gz
src-eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3.zip
Vendor import of lld trunk r321017:vendor/lld/lld-trunk-r321017
Notes
Notes: svn path=/vendor/lld/dist/; revision=326947 svn path=/vendor/lld/lld-trunk-r321017/; revision=326948; tag=vendor/lld/lld-trunk-r321017
Diffstat (limited to 'ELF/InputFiles.cpp')
-rw-r--r--ELF/InputFiles.cpp541
1 files changed, 292 insertions, 249 deletions
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index c609615fcc2e..1f68340c9428 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -8,13 +8,13 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
-#include "Error.h"
#include "InputSection.h"
#include "LinkerScript.h"
-#include "Memory.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -23,6 +23,8 @@
#include "llvm/LTO/LTO.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,26 +37,23 @@ using namespace llvm::sys::fs;
using namespace lld;
using namespace lld::elf;
+std::vector<BinaryFile *> elf::BinaryFiles;
+std::vector<BitcodeFile *> elf::BitcodeFiles;
+std::vector<InputFile *> elf::ObjectFiles;
+std::vector<InputFile *> elf::SharedFiles;
+
TarWriter *elf::Tar;
InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
-namespace {
-// In ELF object file all section addresses are zero. If we have multiple
-// .text sections (when using -ffunction-section or comdat group) then
-// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
-// we assign each section some unique address. This callback method assigns
-// each section an address equal to its offset in ELF object file.
-class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> {
-public:
- uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
- return static_cast<const ELFSectionRef &>(Sec).getOffset();
- }
-};
-}
-
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
+ // The --chroot option changes our virtual root directory.
+ // This is useful when you are dealing with files created by --reproduce.
+ if (!Config->Chroot.empty() && Path.startswith("/"))
+ Path = Saver.save(Config->Chroot + Path);
+
log(Path);
+
auto MBOrErr = MemoryBuffer::getFile(Path);
if (auto EC = MBOrErr.getError()) {
error("cannot open " + Path + ": " + EC.message());
@@ -70,28 +69,88 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
return MBRef;
}
-template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
- std::unique_ptr<object::ObjectFile> Obj =
- check(object::ObjectFile::createObjectFile(this->MB), toString(this));
-
- ObjectInfo ObjInfo;
- DWARFContextInMemory Dwarf(*Obj, &ObjInfo);
+template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
+ DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this));
+ const DWARFObject &Obj = Dwarf.getDWARFObj();
DwarfLine.reset(new DWARFDebugLine);
- DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE,
+ DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE,
Config->Wordsize);
// The second parameter is offset in .debug_line section
// for compilation unit (CU) of interest. We have only one
// CU (object file), so offset is always 0.
- DwarfLine->getOrParseLineTable(LineData, 0);
+ // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5
+ // needs it in order to find indirect strings.
+ const DWARFDebugLine::LineTable *LT =
+ DwarfLine->getOrParseLineTable(LineData, 0, nullptr);
+
+ // Return if there is no debug information about CU available.
+ if (!Dwarf.getNumCompileUnits())
+ return;
+
+ // Loop over variable records and insert them to VariableLoc.
+ DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0);
+ for (const auto &Entry : CU->dies()) {
+ DWARFDie Die(CU, &Entry);
+ // Skip all tags that are not variables.
+ if (Die.getTag() != dwarf::DW_TAG_variable)
+ continue;
+
+ // Skip if a local variable because we don't need them for generating error
+ // messages. In general, only non-local symbols can fail to be linked.
+ if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0))
+ continue;
+
+ // Get the source filename index for the variable.
+ unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0);
+ if (!LT->hasFileAtIndex(File))
+ continue;
+
+ // Get the line number on which the variable is declared.
+ unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0);
+
+ // Get the name of the variable and add the collected information to
+ // VariableLoc. Usually Name is non-empty, but it can be empty if the input
+ // object file lacks some debug info.
+ StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), "");
+ if (!Name.empty())
+ VariableLoc.insert({Name, {File, Line}});
+ }
+}
+
+// Returns the pair of file name and line number describing location of data
+// object (variable, array, etc) definition.
+template <class ELFT>
+Optional<std::pair<std::string, unsigned>>
+ObjFile<ELFT>::getVariableLoc(StringRef Name) {
+ llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
+
+ // There is always only one CU so it's offset is 0.
+ const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0);
+ if (!LT)
+ return None;
+
+ // Return if we have no debug information about data object.
+ auto It = VariableLoc.find(Name);
+ if (It == VariableLoc.end())
+ return None;
+
+ // Take file name string from line table.
+ std::string FileName;
+ if (!LT->getFileNameByIndex(
+ It->second.first /* File */, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName))
+ return None;
+
+ return std::make_pair(FileName, It->second.second /*Line*/);
}
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
-Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
- uint64_t Offset) {
- llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); });
+Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S,
+ uint64_t Offset) {
+ llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); });
// The offset to CU is 0.
const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
@@ -112,8 +171,7 @@ Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
-std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
- uint64_t Offset) {
+std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) {
if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
return Info->FileName + ":" + std::to_string(Info->Line);
return "";
@@ -145,50 +203,41 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
}
template <class ELFT>
-typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() {
- return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end());
+typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() {
+ return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end());
}
template <class ELFT>
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
- return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX),
- toString(this));
+ return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this);
}
template <class ELFT>
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr *Symtab) {
FirstNonLocal = Symtab->sh_info;
- Symbols = check(getObj().symbols(Symtab), toString(this));
- if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size())
+ ELFSyms = CHECK(getObj().symbols(Symtab), this);
+ if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size())
fatal(toString(this) + ": invalid sh_info in symbol table");
- StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections),
- toString(this));
+ StringTable =
+ CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this);
}
template <class ELFT>
-elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName)
- : ELFFileBase<ELFT>(Base::ObjectKind, M) {
+ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName)
+ : ELFFileBase<ELFT>(Base::ObjKind, M) {
this->ArchiveName = ArchiveName;
}
-template <class ELFT>
-ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
- if (this->SymbolBodies.empty())
- return this->SymbolBodies;
- return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1);
-}
-
-template <class ELFT>
-ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
- if (this->SymbolBodies.empty())
- return this->SymbolBodies;
- return makeArrayRef(this->SymbolBodies).slice(1);
+template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() {
+ if (this->Symbols.empty())
+ return {};
+ return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1);
}
template <class ELFT>
-void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
// Read section and symbol tables.
initializeSections(ComdatGroups);
initializeSymbols();
@@ -198,19 +247,17 @@ void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
// They are identified and deduplicated by group name. This function
// returns a group name.
template <class ELFT>
-StringRef
-elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
- const Elf_Shdr &Sec) {
+StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr &Sec) {
// Group signatures are stored as symbol names in object files.
// sh_info contains a symbol index, so we fetch a symbol and read its name.
- if (this->Symbols.empty())
+ if (this->ELFSyms.empty())
this->initSymtab(
- Sections,
- check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this)));
+ Sections, CHECK(object::getSection<ELFT>(Sections, Sec.sh_link), this));
- const Elf_Sym *Sym = check(
- object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this));
- StringRef Signature = check(Sym->getName(this->StringTable), toString(this));
+ const Elf_Sym *Sym =
+ CHECK(object::getSymbol<ELFT>(this->ELFSyms, Sec.sh_info), this);
+ StringRef Signature = CHECK(Sym->getName(this->StringTable), this);
// As a special case, if a symbol is a section symbol and has no name,
// we use a section name as a signature.
@@ -225,32 +272,22 @@ elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
}
template <class ELFT>
-ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
-elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
+ArrayRef<typename ObjFile<ELFT>::Elf_Word>
+ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Word> Entries = check(
- Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this));
+ ArrayRef<Elf_Word> Entries =
+ CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this);
if (Entries.empty() || Entries[0] != GRP_COMDAT)
fatal(toString(this) + ": unsupported SHT_GROUP format");
return Entries.slice(1);
}
-template <class ELFT>
-bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
+template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
// We don't merge sections if -O0 (default is -O1). This makes sometimes
// the linker significantly faster, although the output will be bigger.
if (Config->Optimize == 0)
return false;
- // Do not merge sections if generating a relocatable object. It makes
- // the code simpler because we do not need to update relocation addends
- // to reflect changes introduced by merging. Instead of that we write
- // such "merge" sections into separate OutputSections and keep SHF_MERGE
- // / SHF_STRINGS flags and sh_entsize value to be able to perform merging
- // later during a final linking.
- if (Config->Relocatable)
- return false;
-
// A mergeable section with size 0 is useless because they don't have
// any data to merge. A mergeable string section with size 0 can be
// argued as invalid because it doesn't end with a null character.
@@ -276,29 +313,19 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
if (Flags & SHF_WRITE)
fatal(toString(this) + ": writable SHF_MERGE section is not supported");
- // Don't try to merge if the alignment is larger than the sh_entsize and this
- // is not SHF_STRINGS.
- //
- // Since this is not a SHF_STRINGS, we would need to pad after every entity.
- // It would be equivalent for the producer of the .o to just set a larger
- // sh_entsize.
- if (Flags & SHF_STRINGS)
- return true;
-
- return Sec.sh_addralign <= EntSize;
+ return true;
}
template <class ELFT>
-void elf::ObjectFile<ELFT>::initializeSections(
+void ObjFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Shdr> ObjSections =
- check(this->getObj().sections(), toString(this));
+ ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this);
uint64_t Size = ObjSections.size();
this->Sections.resize(Size);
this->SectionStringTable =
- check(Obj.getSectionStringTable(ObjSections), toString(this));
+ CHECK(Obj.getSectionStringTable(ObjSections), this);
for (size_t I = 0, E = ObjSections.size(); I < E; I++) {
if (this->Sections[I] == &InputSection::Discarded)
@@ -344,8 +371,7 @@ void elf::ObjectFile<ELFT>::initializeSections(
this->initSymtab(ObjSections, &Sec);
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX =
- check(Obj.getSHNDXTable(Sec, ObjSections), toString(this));
+ this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this);
break;
case SHT_STRTAB:
case SHT_NULL:
@@ -361,13 +387,55 @@ void elf::ObjectFile<ELFT>::initializeSections(
fatal(toString(this) + ": invalid sh_link index: " +
Twine(Sec.sh_link));
this->Sections[Sec.sh_link]->DependentSections.push_back(
- this->Sections[I]);
+ cast<InputSection>(this->Sections[I]));
}
}
}
+// The ARM support in lld makes some use of instructions that are not available
+// on all ARM architectures. Namely:
+// - Use of BLX instruction for interworking between ARM and Thumb state.
+// - Use of the extended Thumb branch encoding in relocation.
+// - Use of the MOVT/MOVW instructions in Thumb Thunks.
+// The ARM Attributes section contains information about the architecture chosen
+// at compile time. We follow the convention that if at least one input object
+// is compiled with an architecture that supports these features then lld is
+// permitted to use them.
+static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) {
+ if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch))
+ return;
+ auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ switch (Arch) {
+ case ARMBuildAttrs::Pre_v4:
+ case ARMBuildAttrs::v4:
+ case ARMBuildAttrs::v4T:
+ // Architectures prior to v5 do not support BLX instruction
+ break;
+ case ARMBuildAttrs::v5T:
+ case ARMBuildAttrs::v5TE:
+ case ARMBuildAttrs::v5TEJ:
+ case ARMBuildAttrs::v6:
+ case ARMBuildAttrs::v6KZ:
+ case ARMBuildAttrs::v6K:
+ Config->ARMHasBlx = true;
+ // Architectures used in pre-Cortex processors do not support
+ // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception
+ // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do.
+ break;
+ default:
+ // All other Architectures have BLX and extended branch encoding
+ Config->ARMHasBlx = true;
+ Config->ARMJ1J2BranchEncoding = true;
+ if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M)
+ // All Architectures used in Cortex processors with the exception
+ // of v6-M and v6S-M have the MOVT and MOVW instructions.
+ Config->ARMHasMovtMovw = true;
+ break;
+ }
+}
+
template <class ELFT>
-InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
uint32_t Idx = Sec.sh_info;
if (Idx >= this->Sections.size())
fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
@@ -394,21 +462,26 @@ InputSectionBase *toRegularSection(MergeInputSection *Sec) {
}
template <class ELFT>
-InputSectionBase *
-elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
+InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
StringRef Name = getSectionName(Sec);
switch (Sec.sh_type) {
- case SHT_ARM_ATTRIBUTES:
- // FIXME: ARM meta-data section. Retain the first attribute section
- // we see. The eglibc ARM dynamic loaders require the presence of an
- // attribute section for dlopen to work.
- // In a full implementation we would merge all attribute sections.
+ case SHT_ARM_ATTRIBUTES: {
+ if (Config->EMachine != EM_ARM)
+ break;
+ ARMAttributeParser Attributes;
+ ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec));
+ Attributes.Parse(Contents, /*isLittle*/Config->EKind == ELF32LEKind);
+ updateSupportedARMFeatures(Attributes);
+ // FIXME: Retain the first attribute section we see. The eglibc ARM
+ // dynamic loaders require the presence of an attribute section for dlopen
+ // to work. In a full implementation we would merge all attribute sections.
if (InX::ARMAttributes == nullptr) {
InX::ARMAttributes = make<InputSection>(this, &Sec, Name);
return InX::ARMAttributes;
}
return &InputSection::Discarded;
+ }
case SHT_RELA:
case SHT_REL: {
// Find the relocation target section and associate this
@@ -443,13 +516,12 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
- ArrayRef<Elf_Rela> Rels =
- check(this->getObj().relas(&Sec), toString(this));
+ ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this);
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = true;
} else {
- ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this));
+ ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this);
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = false;
@@ -497,18 +569,6 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
return &InputSection::Discarded;
}
- 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.
@@ -529,46 +589,24 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
}
template <class ELFT>
-StringRef elf::ObjectFile<ELFT>::getSectionName(const Elf_Shdr &Sec) {
- return check(this->getObj().getSectionName(&Sec, SectionStringTable),
- toString(this));
-}
-
-template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
- SymbolBodies.reserve(this->Symbols.size());
- for (const Elf_Sym &Sym : this->Symbols)
- SymbolBodies.push_back(createSymbolBody(&Sym));
+StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &Sec) {
+ return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this);
}
-template <class ELFT>
-InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
- uint32_t Index = this->getSectionIndex(Sym);
- if (Index >= this->Sections.size())
- fatal(toString(this) + ": invalid section index: " + Twine(Index));
- InputSectionBase *S = this->Sections[Index];
-
- // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could
- // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be
- // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections.
- // In this case it is fine for section to be null here as we do not
- // allocate sections of these types.
- if (!S) {
- if (Index == 0 || Sym.getType() == STT_SECTION ||
- Sym.getType() == STT_NOTYPE)
- return nullptr;
- fatal(toString(this) + ": invalid section index: " + Twine(Index));
- }
-
- if (S == &InputSection::Discarded)
- return S;
- return S->Repl;
+template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
+ this->Symbols.reserve(this->ELFSyms.size());
+ for (const Elf_Sym &Sym : this->ELFSyms)
+ this->Symbols.push_back(createSymbol(&Sym));
}
-template <class ELFT>
-SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
+template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
int Binding = Sym->getBinding();
- InputSectionBase *Sec = getSection(*Sym);
+ uint32_t SecIdx = this->getSectionIndex(*Sym);
+ if (SecIdx >= this->Sections.size())
+ fatal(toString(this) + ": invalid section index: " + Twine(SecIdx));
+
+ InputSectionBase *Sec = this->Sections[SecIdx];
uint8_t StOther = Sym->st_other;
uint8_t Type = Sym->getType();
uint64_t Value = Sym->st_value;
@@ -576,34 +614,29 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
if (Binding == STB_LOCAL) {
if (Sym->getType() == STT_FILE)
- SourceFile = check(Sym->getName(this->StringTable), toString(this));
+ SourceFile = CHECK(Sym->getName(this->StringTable), this);
if (this->StringTable.size() <= Sym->st_name)
fatal(toString(this) + ": invalid symbol name offset");
StringRefZ Name = this->StringTable.data() + Sym->st_name;
if (Sym->st_shndx == SHN_UNDEF)
- return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this);
+ return make<Undefined>(this, Name, Binding, StOther, Type);
- return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value,
- Size, Sec, this);
+ return make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec);
}
- StringRef Name = check(Sym->getName(this->StringTable), toString(this));
+ StringRef Name = CHECK(Sym->getName(this->StringTable), this);
switch (Sym->st_shndx) {
case SHN_UNDEF:
- return elf::Symtab<ELFT>::X
- ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
- /*CanOmitFromDynSym=*/false, this)
- ->body();
+ return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
+ /*CanOmitFromDynSym=*/false, this);
case SHN_COMMON:
if (Value == 0 || Value >= UINT32_MAX)
fatal(toString(this) + ": common symbol '" + Name +
"' has invalid alignment: " + Twine(Value));
- return elf::Symtab<ELFT>::X
- ->addCommon(Name, Size, Value, Binding, StOther, Type, this)
- ->body();
+ return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this);
}
switch (Binding) {
@@ -613,13 +646,10 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
case STB_WEAK:
case STB_GNU_UNIQUE:
if (Sec == &InputSection::Discarded)
- return elf::Symtab<ELFT>::X
- ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
- /*CanOmitFromDynSym=*/false, this)
- ->body();
- return elf::Symtab<ELFT>::X
- ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this)
- ->body();
+ return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
+ /*CanOmitFromDynSym=*/false, this);
+ return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding,
+ Sec, this);
}
}
@@ -630,14 +660,14 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
template <class ELFT> void ArchiveFile::parse() {
Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
- Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym));
+ Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym));
}
// Returns a buffer pointing to a member file containing a given symbol.
std::pair<MemoryBufferRef, uint64_t>
ArchiveFile::getMember(const Archive::Symbol *Sym) {
Archive::Child C =
- check(Sym->getMember(), toString(this) +
+ CHECK(Sym->getMember(), toString(this) +
": could not get the member for symbol " +
Sym->getName());
@@ -645,14 +675,13 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) {
return {MemoryBufferRef(), 0};
MemoryBufferRef Ret =
- check(C.getMemoryBufferRef(),
+ CHECK(C.getMemoryBufferRef(),
toString(this) +
": could not get the buffer for the member defining symbol " +
Sym->getName());
if (C.getParent()->isThin() && Tar)
- Tar->append(relativeToRoot(check(C.getFullName(), toString(this))),
- Ret.getBuffer());
+ Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer());
if (C.getParent()->isThin())
return {Ret, 0};
return {Ret, C.getChildOffset()};
@@ -661,22 +690,14 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) {
template <class ELFT>
SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
: ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName),
- AsNeeded(Config->AsNeeded) {}
-
-template <class ELFT>
-const typename ELFT::Shdr *
-SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
- return check(
- this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX),
- toString(this));
-}
+ IsNeeded(!Config->AsNeeded) {}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
const Elf_Shdr *DynamicSec = nullptr;
const ELFFile<ELFT> Obj = this->getObj();
- ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
+ ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this);
// Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
for (const Elf_Shdr &Sec : Sections) {
@@ -690,8 +711,7 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
DynamicSec = &Sec;
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX =
- check(Obj.getSHNDXTable(Sec, Sections), toString(this));
+ this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this);
break;
case SHT_GNU_versym:
this->VersymSec = &Sec;
@@ -702,15 +722,14 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
}
}
- if (this->VersymSec && this->Symbols.empty())
+ if (this->VersymSec && this->ELFSyms.empty())
error("SHT_GNU_versym should be associated with symbol table");
// Search for a DT_SONAME tag to initialize this->SoName.
if (!DynamicSec)
return;
ArrayRef<Elf_Dyn> Arr =
- check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
- toString(this));
+ CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), this);
for (const Elf_Dyn &Dyn : Arr) {
if (Dyn.d_tag == DT_SONAME) {
uint64_t Val = Dyn.getVal();
@@ -767,11 +786,14 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
template <class ELFT> void SharedFile<ELFT>::parseRest() {
// Create mapping from version identifiers to Elf_Verdef entries.
const Elf_Versym *Versym = nullptr;
- std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
+ Verdefs = parseVerdefs(Versym);
- Elf_Sym_Range Syms = this->getGlobalSymbols();
+ ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this);
+
+ // Add symbols to the symbol table.
+ Elf_Sym_Range Syms = this->getGlobalELFSyms();
for (const Elf_Sym &Sym : Syms) {
- unsigned VersymIndex = 0;
+ unsigned VersymIndex = VER_NDX_GLOBAL;
if (Versym) {
VersymIndex = Versym->vs_index;
++Versym;
@@ -779,28 +801,54 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
bool Hidden = VersymIndex & VERSYM_HIDDEN;
VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
- StringRef Name = check(Sym.getName(this->StringTable), toString(this));
+ StringRef Name = CHECK(Sym.getName(this->StringTable), this);
if (Sym.isUndefined()) {
Undefs.push_back(Name);
continue;
}
- // Ignore local symbols.
- if (Versym && VersymIndex == VER_NDX_LOCAL)
+ if (Sym.getBinding() == STB_LOCAL) {
+ warn("found local symbol '" + Name +
+ "' in global part of symbol table in file " + toString(this));
continue;
+ }
+
+ const Elf_Verdef *Ver = nullptr;
+ if (VersymIndex != VER_NDX_GLOBAL) {
+ if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) {
+ error("corrupt input file: version definition index " +
+ Twine(VersymIndex) + " for symbol " + Name +
+ " is out of bounds\n>>> defined in " + toString(this));
+ continue;
+ }
+ Ver = Verdefs[VersymIndex];
+ } else {
+ VersymIndex = 0;
+ }
- const Elf_Verdef *V =
- VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex];
+ // We do not usually care about alignments of data in shared object
+ // files because the loader takes care of it. However, if we promote a
+ // DSO symbol to point to .bss due to copy relocation, we need to keep
+ // the original alignment requirements. We infer it here.
+ uint64_t Alignment = 1;
+ if (Sym.st_value)
+ Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
+ if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) {
+ uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign;
+ Alignment = std::min(Alignment, SecAlign);
+ }
+ if (Alignment > UINT32_MAX)
+ error(toString(this) + ": alignment too large: " + Name);
if (!Hidden)
- elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+ Symtab->addShared(Name, this, Sym, Alignment, VersymIndex);
// Also add the symbol with the versioned name to handle undefined symbols
// with explicit versions.
- if (V) {
- StringRef VerName = this->StringTable.data() + V->getAux()->vda_name;
+ if (Ver) {
+ StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name;
Name = Saver.save(Name + "@" + VerName);
- elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+ Symtab->addShared(Name, this, Sym, Alignment, VersymIndex);
}
}
}
@@ -855,7 +903,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
MemoryBufferRef MBRef(MB.getBuffer(),
Saver.save(ArchiveName + MB.getBufferIdentifier() +
utostr(OffsetInArchive)));
- Obj = check(lto::InputFile::create(MBRef), toString(this));
+ Obj = CHECK(lto::InputFile::create(MBRef), this);
Triple T(Obj->getTargetTriple());
EKind = getBitcodeELFKind(T);
@@ -887,22 +935,20 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
- return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
- Visibility, Type, CanOmitFromDynSym,
- F);
+ return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ CanOmitFromDynSym, F);
if (ObjSym.isUndefined())
- return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
- Visibility, Type, CanOmitFromDynSym,
- F);
+ return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type,
+ CanOmitFromDynSym, F);
if (ObjSym.isCommon())
- return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
- ObjSym.getCommonAlignment(), Binding,
- Visibility, STT_OBJECT, F);
+ return Symtab->addCommon(NameRef, ObjSym.getCommonSize(),
+ ObjSym.getCommonAlignment(), Binding, Visibility,
+ STT_OBJECT, F);
- return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type,
- CanOmitFromDynSym, F);
+ return Symtab->addBitcode(NameRef, Binding, Visibility, Type,
+ CanOmitFromDynSym, F);
}
template <class ELFT>
@@ -947,18 +993,15 @@ template <class ELFT> void BinaryFile::parse() {
// 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]))
+ 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);
+ Symtab->addRegular<ELFT>(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT,
+ 0, 0, STB_GLOBAL, Section, nullptr);
+ Symtab->addRegular<ELFT>(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
+ Data.size(), 0, STB_GLOBAL, Section, nullptr);
+ Symtab->addRegular<ELFT>(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
+ Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
}
static bool isBitcode(MemoryBufferRef MB) {
@@ -973,13 +1016,13 @@ InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
switch (getELFKind(MB)) {
case ELF32LEKind:
- return make<ObjectFile<ELF32LE>>(MB, ArchiveName);
+ return make<ObjFile<ELF32LE>>(MB, ArchiveName);
case ELF32BEKind:
- return make<ObjectFile<ELF32BE>>(MB, ArchiveName);
+ return make<ObjFile<ELF32BE>>(MB, ArchiveName);
case ELF64LEKind:
- return make<ObjectFile<ELF64LE>>(MB, ArchiveName);
+ return make<ObjFile<ELF64LE>>(MB, ArchiveName);
case ELF64BEKind:
- return make<ObjectFile<ELF64BE>>(MB, ArchiveName);
+ return make<ObjFile<ELF64BE>>(MB, ArchiveName);
default:
llvm_unreachable("getELFKind");
}
@@ -1000,53 +1043,53 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
}
}
-MemoryBufferRef LazyObjectFile::getBuffer() {
+MemoryBufferRef LazyObjFile::getBuffer() {
if (Seen)
return MemoryBufferRef();
Seen = true;
return MB;
}
-InputFile *LazyObjectFile::fetch() {
+InputFile *LazyObjFile::fetch() {
MemoryBufferRef MBRef = getBuffer();
if (MBRef.getBuffer().empty())
return nullptr;
return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
}
-template <class ELFT> void LazyObjectFile::parse() {
- for (StringRef Sym : getSymbols())
- Symtab<ELFT>::X->addLazyObject(Sym, *this);
+template <class ELFT> void LazyObjFile::parse() {
+ for (StringRef Sym : getSymbolNames())
+ Symtab->addLazyObject<ELFT>(Sym, *this);
}
-template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
+template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() {
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::SymRange Elf_Sym_Range;
- const ELFFile<ELFT> Obj(this->MB.getBuffer());
- ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
+ ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer()));
+ ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this);
for (const Elf_Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
- Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this));
+ Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this);
uint32_t FirstNonLocal = Sec.sh_info;
StringRef StringTable =
- check(Obj.getStringTableForSymtab(Sec, Sections), toString(this));
+ CHECK(Obj.getStringTableForSymtab(Sec, Sections), this);
std::vector<StringRef> V;
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
if (Sym.st_shndx != SHN_UNDEF)
- V.push_back(check(Sym.getName(StringTable), toString(this)));
+ V.push_back(CHECK(Sym.getName(StringTable), this));
return V;
}
return {};
}
-std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
+std::vector<StringRef> LazyObjFile::getBitcodeSymbols() {
std::unique_ptr<lto::InputFile> Obj =
- check(lto::InputFile::create(this->MB), toString(this));
+ CHECK(lto::InputFile::create(this->MB), this);
std::vector<StringRef> V;
for (const lto::InputFile::Symbol &Sym : Obj->symbols())
if (!Sym.isUndefined())
@@ -1055,7 +1098,7 @@ std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
}
// Returns a vector of globally-visible defined symbol names.
-std::vector<StringRef> LazyObjectFile::getSymbols() {
+std::vector<StringRef> LazyObjFile::getSymbolNames() {
if (isBitcode(this->MB))
return getBitcodeSymbols();
@@ -1083,20 +1126,20 @@ template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &);
template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &);
template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &);
-template void LazyObjectFile::parse<ELF32LE>();
-template void LazyObjectFile::parse<ELF32BE>();
-template void LazyObjectFile::parse<ELF64LE>();
-template void LazyObjectFile::parse<ELF64BE>();
+template void LazyObjFile::parse<ELF32LE>();
+template void LazyObjFile::parse<ELF32BE>();
+template void LazyObjFile::parse<ELF64LE>();
+template void LazyObjFile::parse<ELF64BE>();
template class elf::ELFFileBase<ELF32LE>;
template class elf::ELFFileBase<ELF32BE>;
template class elf::ELFFileBase<ELF64LE>;
template class elf::ELFFileBase<ELF64BE>;
-template class elf::ObjectFile<ELF32LE>;
-template class elf::ObjectFile<ELF32BE>;
-template class elf::ObjectFile<ELF64LE>;
-template class elf::ObjectFile<ELF64BE>;
+template class elf::ObjFile<ELF32LE>;
+template class elf::ObjFile<ELF32BE>;
+template class elf::ObjFile<ELF64LE>;
+template class elf::ObjFile<ELF64BE>;
template class elf::SharedFile<ELF32LE>;
template class elf::SharedFile<ELF32BE>;