aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/InputFiles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/InputFiles.cpp')
-rw-r--r--lld/ELF/InputFiles.cpp430
1 files changed, 193 insertions, 237 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index b5510b3b2736..0ea2a2c74b63 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
+#include "Config.h"
+#include "DWARF.h"
#include "Driver.h"
#include "InputSection.h"
#include "LinkerScript.h"
@@ -16,16 +18,14 @@
#include "Target.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/DWARF.h"
+#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/CodeGen/Analysis.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
#include "llvm/LTO/LTO.h"
-#include "llvm/MC/StringTableBuilder.h"
-#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RISCVAttributeParser.h"
#include "llvm/Support/TarWriter.h"
@@ -43,14 +43,6 @@ using namespace lld::elf;
bool InputFile::isInGroup;
uint32_t InputFile::nextGroupId;
-SmallVector<std::unique_ptr<MemoryBuffer>> elf::memoryBuffers;
-SmallVector<ArchiveFile *, 0> elf::archiveFiles;
-SmallVector<BinaryFile *, 0> elf::binaryFiles;
-SmallVector<BitcodeFile *, 0> elf::bitcodeFiles;
-SmallVector<BitcodeFile *, 0> elf::lazyBitcodeFiles;
-SmallVector<ELFFileBase *, 0> elf::objectFiles;
-SmallVector<SharedFile *, 0> elf::sharedFiles;
-
std::unique_ptr<TarWriter> elf::tar;
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
@@ -124,7 +116,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef path) {
}
MemoryBufferRef mbref = (*mbOrErr)->getMemBufferRef();
- memoryBuffers.push_back(std::move(*mbOrErr)); // take MB ownership
+ ctx->memoryBuffers.push_back(std::move(*mbOrErr)); // take MB ownership
if (tar)
tar->append(relativeToRoot(path), mbref.getBuffer());
@@ -152,18 +144,17 @@ static bool isCompatible(InputFile *file) {
return false;
}
- InputFile *existing;
- if (!objectFiles.empty())
- existing = objectFiles[0];
- else if (!sharedFiles.empty())
- existing = sharedFiles[0];
- else if (!bitcodeFiles.empty())
- existing = bitcodeFiles[0];
- else
- llvm_unreachable("Must have -m, OUTPUT_FORMAT or existing input file to "
- "determine target emulation");
-
- error(toString(file) + " is incompatible with " + toString(existing));
+ InputFile *existing = nullptr;
+ if (!ctx->objectFiles.empty())
+ existing = ctx->objectFiles[0];
+ else if (!ctx->sharedFiles.empty())
+ existing = ctx->sharedFiles[0];
+ else if (!ctx->bitcodeFiles.empty())
+ existing = ctx->bitcodeFiles[0];
+ std::string with;
+ if (existing)
+ with = " with " + toString(existing);
+ error(toString(file) + " is incompatible" + with);
return false;
}
@@ -173,14 +164,7 @@ template <class ELFT> static void doParseFile(InputFile *file) {
// Binary file
if (auto *f = dyn_cast<BinaryFile>(file)) {
- binaryFiles.push_back(f);
- f->parse();
- return;
- }
-
- // .a file
- if (auto *f = dyn_cast<ArchiveFile>(file)) {
- archiveFiles.push_back(f);
+ ctx->binaryFiles.push_back(f);
f->parse();
return;
}
@@ -188,7 +172,7 @@ template <class ELFT> static void doParseFile(InputFile *file) {
// Lazy object file
if (file->lazy) {
if (auto *f = dyn_cast<BitcodeFile>(file)) {
- lazyBitcodeFiles.push_back(f);
+ ctx->lazyBitcodeFiles.push_back(f);
f->parseLazy();
} else {
cast<ObjFile<ELFT>>(file)->parseLazy();
@@ -207,13 +191,13 @@ template <class ELFT> static void doParseFile(InputFile *file) {
// LLVM bitcode file
if (auto *f = dyn_cast<BitcodeFile>(file)) {
- bitcodeFiles.push_back(f);
+ ctx->bitcodeFiles.push_back(f);
f->parse<ELFT>();
return;
}
// Regular object file
- objectFiles.push_back(cast<ELFFileBase>(file));
+ ctx->objectFiles.push_back(cast<ELFFileBase>(file));
cast<ObjFile<ELFT>>(file)->parse();
}
@@ -233,11 +217,11 @@ template <class ELFT>
static std::string getSrcMsgAux(ObjFile<ELFT> &file, const Symbol &sym,
InputSectionBase &sec, uint64_t offset) {
// In DWARF, functions and variables are stored to different places.
- // First, lookup a function for a given offset.
+ // First, look up a function for a given offset.
if (Optional<DILineInfo> info = file.getDILineInfo(&sec, offset))
return createFileLineMsg(info->FileName, info->Line);
- // If it failed, lookup again as a variable.
+ // If it failed, look up again as a variable.
if (Optional<std::pair<std::string, unsigned>> fileLine =
file.getVariableLoc(sym.getName()))
return createFileLineMsg(fileLine->first, fileLine->second);
@@ -610,6 +594,9 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
case SHT_RELA:
case SHT_NULL:
break;
+ case SHT_LLVM_SYMPART:
+ ctx->hasSympart.store(true, std::memory_order_relaxed);
+ LLVM_FALLTHROUGH;
default:
this->sections[i] =
createInputSection(i, sec, check(obj.getSectionName(sec, shstrtab)));
@@ -703,7 +690,7 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes,
const InputFile *f) {
Optional<unsigned> attr =
attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
- if (!attr.hasValue())
+ if (!attr)
// If an ABI tag isn't present then it is implicitly given the value of 0
// which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files,
// including some in glibc that don't use FP args (and should have value 3)
@@ -711,7 +698,7 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes,
// as a clash.
return;
- unsigned vfpArgs = attr.getValue();
+ unsigned vfpArgs = *attr;
ARMVFPArgKind arg;
switch (vfpArgs) {
case ARMBuildAttrs::BaseAAPCS:
@@ -750,7 +737,7 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes,
static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) {
Optional<unsigned> attr =
attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
- if (!attr.hasValue())
+ if (!attr)
return;
auto arch = attr.getValue();
switch (arch) {
@@ -799,10 +786,10 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
using Elf_Note = typename ELFT::Note;
uint32_t featuresSet = 0;
- ArrayRef<uint8_t> data = sec.data();
+ ArrayRef<uint8_t> data = sec.rawData;
auto reportFatal = [&](const uint8_t *place, const char *msg) {
fatal(toString(sec.file) + ":(" + sec.name + "+0x" +
- Twine::utohexstr(place - sec.data().data()) + "): " + msg);
+ Twine::utohexstr(place - sec.rawData.data()) + "): " + msg);
};
while (!data.empty()) {
// Read one NOTE record.
@@ -1002,15 +989,6 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
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.
- // FIXME: This is glibc PR20543, we should remove this hack once that has been
- // fixed for a while.
- if (name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" ||
- name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx")
- return &InputSection::discarded;
-
// The linker merges EH (exception handling) frames and creates a
// .eh_frame_hdr section for runtime. So we handle them with a special
// class. For relocatable outputs, they are just passed through.
@@ -1026,16 +1004,72 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
// its corresponding ELF symbol table.
template <class ELFT>
void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
- ArrayRef<InputSectionBase *> sections(this->sections);
SymbolTable &symtab = *elf::symtab;
ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
symbols.resize(eSyms.size());
- SymbolUnion *locals =
- firstGlobal == 0
- ? nullptr
- : getSpecificAllocSingleton<SymbolUnion>().Allocate(firstGlobal);
+ // Some entries have been filled by LazyObjFile.
+ for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
+ if (!symbols[i])
+ symbols[i] = symtab.insert(CHECK(eSyms[i].getName(stringTable), this));
+
+ // Perform symbol resolution on non-local symbols.
+ SmallVector<unsigned, 32> undefineds;
+ for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) {
+ const Elf_Sym &eSym = eSyms[i];
+ uint32_t secIdx = eSym.st_shndx;
+ if (secIdx == SHN_UNDEF) {
+ undefineds.push_back(i);
+ continue;
+ }
+
+ uint8_t binding = eSym.getBinding();
+ uint8_t stOther = eSym.st_other;
+ uint8_t type = eSym.getType();
+ uint64_t value = eSym.st_value;
+ uint64_t size = eSym.st_size;
+
+ Symbol *sym = symbols[i];
+ sym->isUsedInRegularObj = true;
+ if (LLVM_UNLIKELY(eSym.st_shndx == SHN_COMMON)) {
+ if (value == 0 || value >= UINT32_MAX)
+ fatal(toString(this) + ": common symbol '" + sym->getName() +
+ "' has invalid alignment: " + Twine(value));
+ hasCommonSyms = true;
+ sym->resolve(
+ CommonSymbol{this, StringRef(), binding, stOther, type, value, size});
+ continue;
+ }
+
+ // Handle global defined symbols. Defined::section will be set in postParse.
+ sym->resolve(Defined{this, StringRef(), binding, stOther, type, value, size,
+ nullptr});
+ }
+
+ // Undefined symbols (excluding those defined relative to non-prevailing
+ // sections) can trigger recursive extract. Process defined symbols first so
+ // that the relative order between a defined symbol and an undefined symbol
+ // does not change the symbol resolution behavior. In addition, a set of
+ // interconnected symbols will all be resolved to the same file, instead of
+ // being resolved to different files.
+ for (unsigned i : undefineds) {
+ const Elf_Sym &eSym = eSyms[i];
+ Symbol *sym = symbols[i];
+ sym->resolve(Undefined{this, StringRef(), eSym.getBinding(), eSym.st_other,
+ eSym.getType()});
+ sym->isUsedInRegularObj = true;
+ sym->referenced = true;
+ }
+}
+
+template <class ELFT> void ObjFile<ELFT>::initializeLocalSymbols() {
+ if (!firstGlobal)
+ return;
+ localSymStorage = std::make_unique<SymbolUnion[]>(firstGlobal);
+ SymbolUnion *locals = localSymStorage.get();
+
+ ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
for (size_t i = 0, end = firstGlobal; i != end; ++i) {
const Elf_Sym &eSym = eSyms[i];
uint32_t secIdx = eSym.st_shndx;
@@ -1064,25 +1098,40 @@ void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
else
new (symbols[i]) Defined(this, name, STB_LOCAL, eSym.st_other, type,
eSym.st_value, eSym.st_size, sec);
+ symbols[i]->isUsedInRegularObj = true;
}
+}
- // Some entries have been filled by LazyObjFile.
- for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i)
- if (!symbols[i])
- symbols[i] = symtab.insert(CHECK(eSyms[i].getName(stringTable), this));
-
- // Perform symbol resolution on non-local symbols.
- SmallVector<unsigned, 32> undefineds;
+// Called after all ObjFile::parse is called for all ObjFiles. This checks
+// duplicate symbols and may do symbol property merge in the future.
+template <class ELFT> void ObjFile<ELFT>::postParse() {
+ static std::mutex mu;
+ ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) {
const Elf_Sym &eSym = eSyms[i];
+ Symbol &sym = *symbols[i];
+ uint32_t secIdx = eSym.st_shndx;
uint8_t binding = eSym.getBinding();
- if (LLVM_UNLIKELY(binding == STB_LOCAL)) {
- errorOrWarn(toString(this) + ": STB_LOCAL symbol (" + Twine(i) +
- ") found at index >= .symtab's sh_info (" +
- Twine(firstGlobal) + ")");
+ if (LLVM_UNLIKELY(binding != STB_GLOBAL && binding != STB_WEAK &&
+ binding != STB_GNU_UNIQUE))
+ errorOrWarn(toString(this) + ": symbol (" + Twine(i) +
+ ") has invalid binding: " + Twine((int)binding));
+
+ // st_value of STT_TLS represents the assigned offset, not the actual
+ // address which is used by STT_FUNC and STT_OBJECT. STT_TLS symbols can
+ // only be referenced by special TLS relocations. It is usually an error if
+ // a STT_TLS symbol is replaced by a non-STT_TLS symbol, vice versa.
+ if (LLVM_UNLIKELY(sym.isTls()) && eSym.getType() != STT_TLS &&
+ eSym.getType() != STT_NOTYPE)
+ errorOrWarn("TLS attribute mismatch: " + toString(sym) + "\n>>> in " +
+ toString(sym.file) + "\n>>> in " + toString(this));
+
+ // Handle non-COMMON defined symbol below. !sym.file allows a symbol
+ // assignment to redefine a symbol without an error.
+ if (!sym.file || !sym.isDefined() || secIdx == SHN_UNDEF ||
+ secIdx == SHN_COMMON)
continue;
- }
- uint32_t secIdx = eSym.st_shndx;
+
if (LLVM_UNLIKELY(secIdx == SHN_XINDEX))
secIdx = check(getExtendedSymbolTableIndex<ELFT>(eSym, i, shndxTable));
else if (secIdx >= SHN_LORESERVE)
@@ -1090,116 +1139,31 @@ void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
if (LLVM_UNLIKELY(secIdx >= sections.size()))
fatal(toString(this) + ": invalid section index: " + Twine(secIdx));
InputSectionBase *sec = sections[secIdx];
- uint8_t stOther = eSym.st_other;
- uint8_t type = eSym.getType();
- uint64_t value = eSym.st_value;
- uint64_t size = eSym.st_size;
-
- if (eSym.st_shndx == SHN_UNDEF) {
- undefineds.push_back(i);
- continue;
- }
-
- Symbol *sym = symbols[i];
- const StringRef name = sym->getName();
- if (LLVM_UNLIKELY(eSym.st_shndx == SHN_COMMON)) {
- if (value == 0 || value >= UINT32_MAX)
- fatal(toString(this) + ": common symbol '" + name +
- "' has invalid alignment: " + Twine(value));
- hasCommonSyms = true;
- sym->resolve(
- CommonSymbol{this, name, binding, stOther, type, value, size});
- continue;
- }
-
- // If a defined symbol is in a discarded section, handle it as if it
- // were an undefined symbol. Such symbol doesn't comply with the
- // standard, but in practice, a .eh_frame often directly refer
- // COMDAT member sections, and if a comdat group is discarded, some
- // defined symbol in a .eh_frame becomes dangling symbols.
if (sec == &InputSection::discarded) {
- Undefined und{this, name, binding, stOther, type, secIdx};
- // !ArchiveFile::parsed or !LazyObjFile::lazy means that the file
- // containing this object has not finished processing, i.e. this symbol is
- // a result of a lazy symbol extract. We should demote the lazy symbol to
- // an Undefined so that any relocations outside of the group to it will
- // trigger a discarded section error.
- if ((sym->symbolKind == Symbol::LazyArchiveKind &&
- !cast<ArchiveFile>(sym->file)->parsed) ||
- (sym->symbolKind == Symbol::LazyObjectKind && !sym->file->lazy)) {
- sym->replace(und);
- // Prevent LTO from internalizing the symbol in case there is a
- // reference to this symbol from this file.
- sym->isUsedInRegularObj = true;
- } else
- sym->resolve(und);
+ if (sym.traced) {
+ printTraceSymbol(Undefined{this, sym.getName(), sym.binding,
+ sym.stOther, sym.type, secIdx},
+ sym.getName());
+ }
+ if (sym.file == this) {
+ std::lock_guard<std::mutex> lock(mu);
+ ctx->nonPrevailingSyms.emplace_back(&sym, secIdx);
+ }
continue;
}
- // Handle global defined symbols.
- if (binding == STB_GLOBAL || binding == STB_WEAK ||
- binding == STB_GNU_UNIQUE) {
- sym->resolve(
- Defined{this, name, binding, stOther, type, value, size, sec});
+ if (sym.file == this) {
+ cast<Defined>(sym).section = sec;
continue;
}
- fatal(toString(this) + ": unexpected binding: " + Twine((int)binding));
- }
-
- // Undefined symbols (excluding those defined relative to non-prevailing
- // sections) can trigger recursive extract. Process defined symbols first so
- // that the relative order between a defined symbol and an undefined symbol
- // does not change the symbol resolution behavior. In addition, a set of
- // interconnected symbols will all be resolved to the same file, instead of
- // being resolved to different files.
- for (unsigned i : undefineds) {
- const Elf_Sym &eSym = eSyms[i];
- Symbol *sym = symbols[i];
- sym->resolve(Undefined{this, sym->getName(), eSym.getBinding(),
- eSym.st_other, eSym.getType()});
- sym->referenced = true;
+ if (binding == STB_WEAK)
+ continue;
+ std::lock_guard<std::mutex> lock(mu);
+ ctx->duplicates.push_back({&sym, this, sec, eSym.st_value});
}
}
-ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&file)
- : InputFile(ArchiveKind, file->getMemoryBufferRef()),
- file(std::move(file)) {}
-
-void ArchiveFile::parse() {
- SymbolTable &symtab = *elf::symtab;
- for (const Archive::Symbol &sym : file->symbols())
- symtab.addSymbol(LazyArchive{*this, sym});
-
- // Inform a future invocation of ObjFile<ELFT>::initializeSymbols() that this
- // archive has been processed.
- parsed = true;
-}
-
-// Returns a buffer pointing to a member file containing a given symbol.
-void ArchiveFile::extract(const Archive::Symbol &sym) {
- Archive::Child c =
- CHECK(sym.getMember(), toString(this) +
- ": could not get the member for symbol " +
- toELFString(sym));
-
- if (!seen.insert(c.getChildOffset()).second)
- return;
-
- MemoryBufferRef mb =
- CHECK(c.getMemoryBufferRef(),
- toString(this) +
- ": could not get the buffer for the member defining symbol " +
- toELFString(sym));
-
- if (tar && c.getParent()->isThin())
- tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer());
-
- InputFile *file = createObjectFile(mb, getName(), c.getChildOffset());
- file->groupId = groupId;
- parseFile(file);
-}
-
// The handling of tentative definitions (COMMON symbols) in archives is murky.
// A tentative definition will be promoted to a global definition if there are
// no non-tentative definitions to dominate it. When we hold a tentative
@@ -1266,36 +1230,6 @@ static bool isNonCommonDef(MemoryBufferRef mb, StringRef symName,
}
}
-bool ArchiveFile::shouldExtractForCommon(const Archive::Symbol &sym) {
- Archive::Child c =
- CHECK(sym.getMember(), toString(this) +
- ": could not get the member for symbol " +
- toELFString(sym));
- MemoryBufferRef mb =
- CHECK(c.getMemoryBufferRef(),
- toString(this) +
- ": could not get the buffer for the member defining symbol " +
- toELFString(sym));
-
- if (isBitcode(mb))
- return isBitcodeNonCommonDef(mb, sym.getName(), getName());
-
- return isNonCommonDef(mb, sym.getName(), getName());
-}
-
-size_t ArchiveFile::getMemberCount() const {
- size_t count = 0;
- Error err = Error::success();
- for (const Archive::Child &c : file->children(err)) {
- (void)c;
- ++count;
- }
- // This function is used by --print-archive-stats=, where an error does not
- // really matter.
- consumeError(std::move(err));
- return count;
-}
-
unsigned SharedFile::vernauxNum;
// Parse the version definitions in the object file if present, and return a
@@ -1456,7 +1390,7 @@ template <class ELFT> void SharedFile::parse() {
if (!wasInserted)
return;
- sharedFiles.push_back(this);
+ ctx->sharedFiles.push_back(this);
verdefs = parseVerdefs<ELFT>(obj.base(), verdefSec);
std::vector<uint32_t> verneeds = parseVerneed<ELFT>(obj, verneedSec);
@@ -1531,9 +1465,11 @@ template <class ELFT> void SharedFile::parse() {
uint32_t alignment = getAlignment<ELFT>(sections, sym);
if (!(versyms[i] & VERSYM_HIDDEN)) {
- symtab.addSymbol(SharedSymbol{*this, name, sym.getBinding(), sym.st_other,
- sym.getType(), sym.st_value, sym.st_size,
- alignment, idx});
+ auto *s = symtab.addSymbol(
+ SharedSymbol{*this, name, sym.getBinding(), sym.st_other,
+ sym.getType(), sym.st_value, sym.st_size, alignment});
+ if (s->file == this)
+ s->verdefIndex = idx;
}
// Also add the symbol with the versioned name to handle undefined symbols
@@ -1553,9 +1489,11 @@ template <class ELFT> void SharedFile::parse() {
reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name;
versionedNameBuffer.clear();
name = (name + "@" + verName).toStringRef(versionedNameBuffer);
- symtab.addSymbol(SharedSymbol{*this, saver().save(name), sym.getBinding(),
- sym.st_other, sym.getType(), sym.st_value,
- sym.st_size, alignment, idx});
+ auto *s = symtab.addSymbol(
+ SharedSymbol{*this, saver().save(name), sym.getBinding(), sym.st_other,
+ sym.getType(), sym.st_value, sym.st_size, alignment});
+ if (s->file == this)
+ s->verdefIndex = idx;
}
}
@@ -1669,40 +1607,31 @@ createBitcodeSymbol(Symbol *&sym, const std::vector<bool> &keptComdats,
uint8_t binding = objSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t type = objSym.isTLS() ? STT_TLS : STT_NOTYPE;
uint8_t visibility = mapVisibility(objSym.getVisibility());
- bool canOmitFromDynSym = objSym.canBeOmittedFromSymbolTable();
- StringRef name;
- if (sym) {
- name = sym->getName();
- } else {
- name = saver().save(objSym.getName());
- sym = symtab->insert(name);
- }
+ if (!sym)
+ sym = symtab->insert(saver().save(objSym.getName()));
int c = objSym.getComdatIndex();
if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) {
- Undefined newSym(&f, name, binding, visibility, type);
- if (canOmitFromDynSym)
- newSym.exportDynamic = false;
+ Undefined newSym(&f, StringRef(), binding, visibility, type);
sym->resolve(newSym);
sym->referenced = true;
return;
}
if (objSym.isCommon()) {
- sym->resolve(CommonSymbol{&f, name, binding, visibility, STT_OBJECT,
+ sym->resolve(CommonSymbol{&f, StringRef(), binding, visibility, STT_OBJECT,
objSym.getCommonAlignment(),
objSym.getCommonSize()});
} else {
- Defined newSym(&f, name, binding, visibility, type, 0, 0, nullptr);
- if (canOmitFromDynSym)
+ Defined newSym(&f, StringRef(), binding, visibility, type, 0, 0, nullptr);
+ if (objSym.canBeOmittedFromSymbolTable())
newSym.exportDynamic = false;
sym->resolve(newSym);
}
}
template <class ELFT> void BitcodeFile::parse() {
- std::vector<bool> keptComdats;
for (std::pair<StringRef, Comdat::SelectionKind> s : obj->getComdatTable()) {
keptComdats.push_back(
s.second == Comdat::NoDeduplicate ||
@@ -1711,10 +1640,18 @@ template <class ELFT> void BitcodeFile::parse() {
}
symbols.resize(obj->symbols().size());
- for (auto it : llvm::enumerate(obj->symbols())) {
- Symbol *&sym = symbols[it.index()];
- createBitcodeSymbol<ELFT>(sym, keptComdats, it.value(), *this);
- }
+ // Process defined symbols first. See the comment in
+ // ObjFile<ELFT>::initializeSymbols.
+ for (auto it : llvm::enumerate(obj->symbols()))
+ if (!it.value().isUndefined()) {
+ Symbol *&sym = symbols[it.index()];
+ createBitcodeSymbol<ELFT>(sym, keptComdats, it.value(), *this);
+ }
+ for (auto it : llvm::enumerate(obj->symbols()))
+ if (it.value().isUndefined()) {
+ Symbol *&sym = symbols[it.index()];
+ createBitcodeSymbol<ELFT>(sym, keptComdats, it.value(), *this);
+ }
for (auto l : obj->getDependentLibraries())
addDependentLibrary(l, this);
@@ -1724,9 +1661,25 @@ void BitcodeFile::parseLazy() {
SymbolTable &symtab = *elf::symtab;
symbols.resize(obj->symbols().size());
for (auto it : llvm::enumerate(obj->symbols()))
- if (!it.value().isUndefined())
- symbols[it.index()] = symtab.addSymbol(
- LazyObject{*this, saver().save(it.value().getName())});
+ if (!it.value().isUndefined()) {
+ auto *sym = symtab.insert(saver().save(it.value().getName()));
+ sym->resolve(LazyObject{*this});
+ symbols[it.index()] = sym;
+ }
+}
+
+void BitcodeFile::postParse() {
+ for (auto it : llvm::enumerate(obj->symbols())) {
+ const Symbol &sym = *symbols[it.index()];
+ const auto &objSym = it.value();
+ if (sym.file == this || !sym.isDefined() || objSym.isUndefined() ||
+ objSym.isCommon() || objSym.isWeak())
+ continue;
+ int c = objSym.getComdatIndex();
+ if (c != -1 && !keptComdats[c])
+ continue;
+ reportDuplicate(sym, this, nullptr, 0);
+ }
}
void BinaryFile::parse() {
@@ -1746,12 +1699,15 @@ void BinaryFile::parse() {
llvm::StringSaver &saver = lld::saver();
- symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL,
- STV_DEFAULT, STT_OBJECT, 0, 0, section});
- symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL,
- STV_DEFAULT, STT_OBJECT, data.size(), 0, section});
- symtab->addSymbol(Defined{nullptr, saver.save(s + "_size"), STB_GLOBAL,
- STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr});
+ symtab->addAndCheckDuplicate(Defined{nullptr, saver.save(s + "_start"),
+ STB_GLOBAL, STV_DEFAULT, STT_OBJECT, 0,
+ 0, section});
+ symtab->addAndCheckDuplicate(Defined{nullptr, saver.save(s + "_end"),
+ STB_GLOBAL, STV_DEFAULT, STT_OBJECT,
+ data.size(), 0, section});
+ symtab->addAndCheckDuplicate(Defined{nullptr, saver.save(s + "_size"),
+ STB_GLOBAL, STV_DEFAULT, STT_OBJECT,
+ data.size(), 0, nullptr});
}
InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName,
@@ -1800,7 +1756,7 @@ template <class ELFT> void ObjFile<ELFT>::parseLazy() {
// exit from the loop early.
for (Symbol *sym : makeArrayRef(symbols).slice(firstGlobal))
if (sym) {
- sym->resolve(LazyObject{*this, sym->getName()});
+ sym->resolve(LazyObject{*this});
if (!lazy)
return;
}