forked from OSchip/llvm-project
ELF: De-template SharedFile. NFCI.
Differential Revision: https://reviews.llvm.org/D60305 llvm-svn: 357925
This commit is contained in:
parent
1b62c758d0
commit
cc1618e668
|
@ -1289,10 +1289,10 @@ template <class ELFT> static void handleLibcall(StringRef Name) {
|
|||
// to DT_NEEDED. If that happens, we need to eliminate shared symbols
|
||||
// created from the DSO. Otherwise, they become dangling references
|
||||
// that point to a non-existent DSO.
|
||||
template <class ELFT> static void demoteSharedSymbols() {
|
||||
static void demoteSharedSymbols() {
|
||||
for (Symbol *Sym : Symtab->getSymbols()) {
|
||||
if (auto *S = dyn_cast<SharedSymbol>(Sym)) {
|
||||
if (!S->getFile<ELFT>().IsNeeded) {
|
||||
if (!S->getFile().IsNeeded) {
|
||||
bool Used = S->Used;
|
||||
replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
|
||||
S->Type);
|
||||
|
@ -1644,7 +1644,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
|
|||
// and identical code folding.
|
||||
splitSections<ELFT>();
|
||||
markLive<ELFT>();
|
||||
demoteSharedSymbols<ELFT>();
|
||||
demoteSharedSymbols();
|
||||
mergeSections();
|
||||
if (Config->ICF != ICFLevel::None) {
|
||||
findKeepUniqueSections<ELFT>(Args);
|
||||
|
|
|
@ -43,7 +43,7 @@ std::vector<BinaryFile *> elf::BinaryFiles;
|
|||
std::vector<BitcodeFile *> elf::BitcodeFiles;
|
||||
std::vector<LazyObjFile *> elf::LazyObjFiles;
|
||||
std::vector<InputFile *> elf::ObjectFiles;
|
||||
std::vector<InputFile *> elf::SharedFiles;
|
||||
std::vector<SharedFile *> elf::SharedFiles;
|
||||
|
||||
std::unique_ptr<TarWriter> elf::Tar;
|
||||
|
||||
|
@ -869,20 +869,83 @@ InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) {
|
|||
return File;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
|
||||
SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
|
||||
: ELFFileBase(SharedKind, M), SoName(DefaultSoName),
|
||||
IsNeeded(!Config->AsNeeded) {
|
||||
parseHeader<ELFT>();
|
||||
IsNeeded(!Config->AsNeeded) {}
|
||||
|
||||
// Parse the version definitions in the object file if present, and return a
|
||||
// vector whose nth element contains a pointer to the Elf_Verdef for version
|
||||
// identifier n. Version identifiers that are not definitions map to nullptr.
|
||||
template <typename ELFT>
|
||||
static std::vector<const void *> parseVerdefs(const uint8_t *Base,
|
||||
const typename ELFT::Shdr *Sec) {
|
||||
if (!Sec)
|
||||
return {};
|
||||
|
||||
// We cannot determine the largest verdef identifier without inspecting
|
||||
// every Elf_Verdef, but both bfd and gold assign verdef identifiers
|
||||
// sequentially starting from 1, so we predict that the largest identifier
|
||||
// will be VerdefCount.
|
||||
unsigned VerdefCount = Sec->sh_info;
|
||||
std::vector<const void *> Verdefs(VerdefCount + 1);
|
||||
|
||||
// Build the Verdefs array by following the chain of Elf_Verdef objects
|
||||
// from the start of the .gnu.version_d section.
|
||||
const uint8_t *Verdef = Base + Sec->sh_offset;
|
||||
for (unsigned I = 0; I != VerdefCount; ++I) {
|
||||
auto *CurVerdef = reinterpret_cast<const typename ELFT::Verdef *>(Verdef);
|
||||
Verdef += CurVerdef->vd_next;
|
||||
unsigned VerdefIndex = CurVerdef->vd_ndx;
|
||||
Verdefs.resize(VerdefIndex + 1);
|
||||
Verdefs[VerdefIndex] = CurVerdef;
|
||||
}
|
||||
return Verdefs;
|
||||
}
|
||||
|
||||
// Partially parse the shared object file so that we can call
|
||||
// getSoName on this object.
|
||||
template <class ELFT> void SharedFile<ELFT>::parseDynamic() {
|
||||
// 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 in this function.
|
||||
template <typename ELFT>
|
||||
static uint64_t getAlignment(ArrayRef<typename ELFT::Shdr> Sections,
|
||||
const typename ELFT::Sym &Sym) {
|
||||
uint64_t Ret = UINT64_MAX;
|
||||
if (Sym.st_value)
|
||||
Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
|
||||
if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size())
|
||||
Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign);
|
||||
return (Ret > UINT32_MAX) ? 0 : Ret;
|
||||
}
|
||||
|
||||
// Fully parse the shared object file.
|
||||
//
|
||||
// This function parses symbol versions. If a DSO has version information,
|
||||
// the file has a ".gnu.version_d" section which contains symbol version
|
||||
// definitions. Each symbol is associated to one version through a table in
|
||||
// ".gnu.version" section. That table is a parallel array for the symbol
|
||||
// table, and each table entry contains an index in ".gnu.version_d".
|
||||
//
|
||||
// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for
|
||||
// VER_NDX_GLOBAL. There's no table entry for these special versions in
|
||||
// ".gnu.version_d".
|
||||
//
|
||||
// The file format for symbol versioning is perhaps a bit more complicated
|
||||
// than necessary, but you can easily understand the code if you wrap your
|
||||
// head around the data structure described above.
|
||||
template <class ELFT> void SharedFile::parse() {
|
||||
using Elf_Dyn = typename ELFT::Dyn;
|
||||
using Elf_Shdr = typename ELFT::Shdr;
|
||||
using Elf_Sym = typename ELFT::Sym;
|
||||
using Elf_Verdef = typename ELFT::Verdef;
|
||||
using Elf_Versym = typename ELFT::Versym;
|
||||
|
||||
ArrayRef<Elf_Dyn> DynamicTags;
|
||||
const ELFFile<ELFT> Obj = this->getObj<ELFT>();
|
||||
ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this);
|
||||
|
||||
const Elf_Shdr *VersymSec = nullptr;
|
||||
const Elf_Shdr *VerdefSec = nullptr;
|
||||
|
||||
// Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
|
||||
for (const Elf_Shdr &Sec : Sections) {
|
||||
switch (Sec.sh_type) {
|
||||
|
@ -896,16 +959,18 @@ template <class ELFT> void SharedFile<ELFT>::parseDynamic() {
|
|||
CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(&Sec), this);
|
||||
break;
|
||||
case SHT_GNU_versym:
|
||||
this->VersymSec = &Sec;
|
||||
VersymSec = &Sec;
|
||||
break;
|
||||
case SHT_GNU_verdef:
|
||||
this->VerdefSec = &Sec;
|
||||
VerdefSec = &Sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->VersymSec && this->getELFSyms<ELFT>().empty())
|
||||
if (VersymSec && this->getELFSyms<ELFT>().empty()) {
|
||||
error("SHT_GNU_versym should be associated with symbol table");
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for a DT_SONAME tag to initialize this->SoName.
|
||||
for (const Elf_Dyn &Dyn : DynamicTags) {
|
||||
|
@ -921,91 +986,38 @@ template <class ELFT> void SharedFile<ELFT>::parseDynamic() {
|
|||
SoName = this->StringTable.data() + Val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parses ".gnu.version" section which is a parallel array for the symbol table.
|
||||
// If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL.
|
||||
template <class ELFT> std::vector<uint32_t> SharedFile<ELFT>::parseVersyms() {
|
||||
// DSOs are uniquified not by filename but by soname.
|
||||
DenseMap<StringRef, SharedFile *>::iterator It;
|
||||
bool WasInserted;
|
||||
std::tie(It, WasInserted) = Symtab->SoNames.try_emplace(SoName, this);
|
||||
|
||||
// If a DSO appears more than once on the command line with and without
|
||||
// --as-needed, --no-as-needed takes precedence over --as-needed because a
|
||||
// user can add an extra DSO with --no-as-needed to force it to be added to
|
||||
// the dependency list.
|
||||
It->second->IsNeeded |= IsNeeded;
|
||||
if (!WasInserted)
|
||||
return;
|
||||
|
||||
SharedFiles.push_back(this);
|
||||
|
||||
Verdefs = parseVerdefs<ELFT>(Obj.base(), VerdefSec);
|
||||
|
||||
// Parse ".gnu.version" section which is a parallel array for the symbol
|
||||
// table. If a given file doesn't have a ".gnu.version" section, we use
|
||||
// VER_NDX_GLOBAL.
|
||||
size_t Size = this->getELFSyms<ELFT>().size() - this->FirstGlobal;
|
||||
if (!VersymSec)
|
||||
return std::vector<uint32_t>(Size, VER_NDX_GLOBAL);
|
||||
|
||||
const char *Base = this->MB.getBuffer().data();
|
||||
const Elf_Versym *Versym =
|
||||
reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
|
||||
this->FirstGlobal;
|
||||
|
||||
std::vector<uint32_t> Ret(Size);
|
||||
for (size_t I = 0; I < Size; ++I)
|
||||
Ret[I] = Versym[I].vs_index;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// Parse the version definitions in the object file if present. Returns a vector
|
||||
// whose nth element contains a pointer to the Elf_Verdef for version identifier
|
||||
// n. Version identifiers that are not definitions map to nullptr.
|
||||
template <class ELFT>
|
||||
std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() {
|
||||
if (!VerdefSec)
|
||||
return {};
|
||||
|
||||
// We cannot determine the largest verdef identifier without inspecting
|
||||
// every Elf_Verdef, but both bfd and gold assign verdef identifiers
|
||||
// sequentially starting from 1, so we predict that the largest identifier
|
||||
// will be VerdefCount.
|
||||
unsigned VerdefCount = VerdefSec->sh_info;
|
||||
std::vector<const Elf_Verdef *> Verdefs(VerdefCount + 1);
|
||||
|
||||
// Build the Verdefs array by following the chain of Elf_Verdef objects
|
||||
// from the start of the .gnu.version_d section.
|
||||
const char *Base = this->MB.getBuffer().data();
|
||||
const char *Verdef = Base + VerdefSec->sh_offset;
|
||||
for (unsigned I = 0; I != VerdefCount; ++I) {
|
||||
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
|
||||
Verdef += CurVerdef->vd_next;
|
||||
unsigned VerdefIndex = CurVerdef->vd_ndx;
|
||||
Verdefs.resize(VerdefIndex + 1);
|
||||
Verdefs[VerdefIndex] = CurVerdef;
|
||||
std::vector<uint32_t> Versyms(Size, VER_NDX_GLOBAL);
|
||||
if (VersymSec) {
|
||||
ArrayRef<Elf_Versym> Versym =
|
||||
CHECK(Obj.template getSectionContentsAsArray<Elf_Versym>(VersymSec),
|
||||
this)
|
||||
.slice(FirstGlobal);
|
||||
for (size_t I = 0; I < Size; ++I)
|
||||
Versyms[I] = Versym[I].vs_index;
|
||||
}
|
||||
|
||||
return Verdefs;
|
||||
}
|
||||
|
||||
// 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 in this function.
|
||||
template <class ELFT>
|
||||
uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections,
|
||||
const Elf_Sym &Sym) {
|
||||
uint64_t Ret = UINT64_MAX;
|
||||
if (Sym.st_value)
|
||||
Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value);
|
||||
if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size())
|
||||
Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign);
|
||||
return (Ret > UINT32_MAX) ? 0 : Ret;
|
||||
}
|
||||
|
||||
// Fully parse the shared object file. This must be called after parseDynamic().
|
||||
//
|
||||
// This function parses symbol versions. If a DSO has version information,
|
||||
// the file has a ".gnu.version_d" section which contains symbol version
|
||||
// definitions. Each symbol is associated to one version through a table in
|
||||
// ".gnu.version" section. That table is a parallel array for the symbol
|
||||
// table, and each table entry contains an index in ".gnu.version_d".
|
||||
//
|
||||
// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for
|
||||
// VER_NDX_GLOBAL. There's no table entry for these special versions in
|
||||
// ".gnu.version_d".
|
||||
//
|
||||
// The file format for symbol versioning is perhaps a bit more complicated
|
||||
// than necessary, but you can easily understand the code if you wrap your
|
||||
// head around the data structure described above.
|
||||
template <class ELFT> void SharedFile<ELFT>::parseRest() {
|
||||
Verdefs = parseVerdefs(); // parse .gnu.version_d
|
||||
std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version
|
||||
ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj<ELFT>().sections(), this);
|
||||
|
||||
// System libraries can have a lot of symbols with versions. Using a
|
||||
// fixed buffer for computing the versions name (foo@ver) can save a
|
||||
// lot of allocations.
|
||||
|
@ -1043,9 +1055,9 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
|
|||
Name == "_gp_disp")
|
||||
continue;
|
||||
|
||||
uint64_t Alignment = getAlignment(Sections, Sym);
|
||||
uint64_t Alignment = getAlignment<ELFT>(Sections, Sym);
|
||||
if (!(Versyms[I] & VERSYM_HIDDEN))
|
||||
Symtab->addShared(Name, *this, Sym, Alignment, Idx);
|
||||
Symtab->addShared<ELFT>(Name, *this, Sym, Alignment, Idx);
|
||||
|
||||
// Also add the symbol with the versioned name to handle undefined symbols
|
||||
// with explicit versions.
|
||||
|
@ -1060,10 +1072,11 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
|
|||
}
|
||||
|
||||
StringRef VerName =
|
||||
this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name;
|
||||
this->StringTable.data() +
|
||||
reinterpret_cast<const Elf_Verdef *>(Verdefs[Idx])->getAux()->vda_name;
|
||||
VersionedNameBuffer.clear();
|
||||
Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer);
|
||||
Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx);
|
||||
Symtab->addShared<ELFT>(Saver.save(Name), *this, Sym, Alignment, Idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1259,18 +1272,24 @@ InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
|
|||
}
|
||||
|
||||
InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
|
||||
auto *F = make<SharedFile>(MB, DefaultSoName);
|
||||
switch (getELFKind(MB, "")) {
|
||||
case ELF32LEKind:
|
||||
return make<SharedFile<ELF32LE>>(MB, DefaultSoName);
|
||||
F->parseHeader<ELF32LE>();
|
||||
break;
|
||||
case ELF32BEKind:
|
||||
return make<SharedFile<ELF32BE>>(MB, DefaultSoName);
|
||||
F->parseHeader<ELF32BE>();
|
||||
break;
|
||||
case ELF64LEKind:
|
||||
return make<SharedFile<ELF64LE>>(MB, DefaultSoName);
|
||||
F->parseHeader<ELF64LE>();
|
||||
break;
|
||||
case ELF64BEKind:
|
||||
return make<SharedFile<ELF64BE>>(MB, DefaultSoName);
|
||||
F->parseHeader<ELF64BE>();
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("getELFKind");
|
||||
}
|
||||
return F;
|
||||
}
|
||||
|
||||
MemoryBufferRef LazyObjFile::getBuffer() {
|
||||
|
@ -1355,7 +1374,7 @@ 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>;
|
||||
template class elf::SharedFile<ELF64LE>;
|
||||
template class elf::SharedFile<ELF64BE>;
|
||||
template void SharedFile::parse<ELF32LE>();
|
||||
template void SharedFile::parse<ELF32BE>();
|
||||
template void SharedFile::parse<ELF64LE>();
|
||||
template void SharedFile::parse<ELF64BE>();
|
||||
|
|
|
@ -328,19 +328,10 @@ public:
|
|||
};
|
||||
|
||||
// .so file.
|
||||
template <class ELFT> class SharedFile : public ELFFileBase {
|
||||
using Elf_Dyn = typename ELFT::Dyn;
|
||||
using Elf_Shdr = typename ELFT::Shdr;
|
||||
using Elf_Sym = typename ELFT::Sym;
|
||||
using Elf_Sym_Range = typename ELFT::SymRange;
|
||||
using Elf_Verdef = typename ELFT::Verdef;
|
||||
using Elf_Versym = typename ELFT::Versym;
|
||||
|
||||
const Elf_Shdr *VersymSec = nullptr;
|
||||
const Elf_Shdr *VerdefSec = nullptr;
|
||||
|
||||
class SharedFile : public ELFFileBase {
|
||||
public:
|
||||
std::vector<const Elf_Verdef *> Verdefs;
|
||||
// This is actually a vector of Elf_Verdef pointers.
|
||||
std::vector<const void *> Verdefs;
|
||||
std::vector<StringRef> DtNeeded;
|
||||
std::string SoName;
|
||||
|
||||
|
@ -348,11 +339,7 @@ public:
|
|||
|
||||
SharedFile(MemoryBufferRef M, StringRef DefaultSoName);
|
||||
|
||||
void parseDynamic();
|
||||
void parseRest();
|
||||
uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym);
|
||||
std::vector<const Elf_Verdef *> parseVerdefs();
|
||||
std::vector<uint32_t> parseVersyms();
|
||||
template <typename ELFT> void parse();
|
||||
|
||||
struct NeededVer {
|
||||
// The string table offset of the version name in the output file.
|
||||
|
@ -364,7 +351,7 @@ public:
|
|||
|
||||
// Mapping from Elf_Verdef data structures to information about Elf_Vernaux
|
||||
// data structures in the output file.
|
||||
std::map<const Elf_Verdef *, NeededVer> VerdefMap;
|
||||
std::map<const void *, NeededVer> VerdefMap;
|
||||
|
||||
// Used for --no-allow-shlib-undefined.
|
||||
bool AllNeededIsKnown;
|
||||
|
@ -394,7 +381,7 @@ extern std::vector<BinaryFile *> BinaryFiles;
|
|||
extern std::vector<BitcodeFile *> BitcodeFiles;
|
||||
extern std::vector<LazyObjFile *> LazyObjFiles;
|
||||
extern std::vector<InputFile *> ObjectFiles;
|
||||
extern std::vector<InputFile *> SharedFiles;
|
||||
extern std::vector<SharedFile *> SharedFiles;
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
|
|
@ -103,7 +103,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &Sec, RelTy &Rel,
|
|||
|
||||
if (auto *SS = dyn_cast<SharedSymbol>(&Sym))
|
||||
if (!SS->isWeak())
|
||||
SS->getFile<ELFT>().IsNeeded = true;
|
||||
SS->getFile().IsNeeded = true;
|
||||
|
||||
for (InputSectionBase *Sec : CNamedSections.lookup(Sym.getName()))
|
||||
enqueue(Sec, 0);
|
||||
|
@ -276,7 +276,7 @@ template <class ELFT> void elf::markLive() {
|
|||
for (Symbol *Sym : Symtab->getSymbols())
|
||||
if (auto *S = dyn_cast<SharedSymbol>(Sym))
|
||||
if (S->IsUsedInRegularObj && !S->isWeak())
|
||||
S->getFile<ELFT>().IsNeeded = true;
|
||||
S->getFile().IsNeeded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -482,7 +482,7 @@ template <class ELFT> static bool isReadOnly(SharedSymbol &SS) {
|
|||
using Elf_Phdr = typename ELFT::Phdr;
|
||||
|
||||
// Determine if the symbol is read-only by scanning the DSO's program headers.
|
||||
const SharedFile<ELFT> &File = SS.getFile<ELFT>();
|
||||
const SharedFile &File = SS.getFile();
|
||||
for (const Elf_Phdr &Phdr :
|
||||
check(File.template getObj<ELFT>().program_headers()))
|
||||
if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
|
||||
|
@ -501,7 +501,7 @@ template <class ELFT>
|
|||
static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
|
||||
using Elf_Sym = typename ELFT::Sym;
|
||||
|
||||
SharedFile<ELFT> &File = SS.getFile<ELFT>();
|
||||
SharedFile &File = SS.getFile();
|
||||
|
||||
SmallSet<SharedSymbol *, 4> Ret;
|
||||
for (const Elf_Sym &S : File.template getGlobalELFSyms<ELFT>()) {
|
||||
|
|
|
@ -90,25 +90,8 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
|
|||
message(toString(File));
|
||||
|
||||
// .so file
|
||||
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
|
||||
// DSOs are uniquified not by filename but by soname.
|
||||
F->parseDynamic();
|
||||
if (errorCount())
|
||||
return;
|
||||
|
||||
// If a DSO appears more than once on the command line with and without
|
||||
// --as-needed, --no-as-needed takes precedence over --as-needed because a
|
||||
// user can add an extra DSO with --no-as-needed to force it to be added to
|
||||
// the dependency list.
|
||||
DenseMap<StringRef, InputFile *>::iterator It;
|
||||
bool WasInserted;
|
||||
std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F);
|
||||
cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded;
|
||||
if (!WasInserted)
|
||||
return;
|
||||
|
||||
SharedFiles.push_back(F);
|
||||
F->parseRest();
|
||||
if (auto *F = dyn_cast<SharedFile>(File)) {
|
||||
F->parse<ELFT>();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -485,7 +468,7 @@ Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
|
|||
}
|
||||
|
||||
template <typename ELFT>
|
||||
void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
|
||||
void SymbolTable::addShared(StringRef Name, SharedFile &File,
|
||||
const typename ELFT::Sym &Sym, uint32_t Alignment,
|
||||
uint32_t VerdefIndex) {
|
||||
// DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
|
||||
|
@ -802,15 +785,15 @@ template void SymbolTable::fetchLazy<ELF32BE>(Symbol *);
|
|||
template void SymbolTable::fetchLazy<ELF64LE>(Symbol *);
|
||||
template void SymbolTable::fetchLazy<ELF64BE>(Symbol *);
|
||||
|
||||
template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
|
||||
template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile &,
|
||||
const typename ELF32LE::Sym &,
|
||||
uint32_t Alignment, uint32_t);
|
||||
template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> &,
|
||||
template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile &,
|
||||
const typename ELF32BE::Sym &,
|
||||
uint32_t Alignment, uint32_t);
|
||||
template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &,
|
||||
template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile &,
|
||||
const typename ELF64LE::Sym &,
|
||||
uint32_t Alignment, uint32_t);
|
||||
template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
|
||||
template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile &,
|
||||
const typename ELF64BE::Sym &,
|
||||
uint32_t Alignment, uint32_t);
|
||||
|
|
|
@ -49,9 +49,8 @@ public:
|
|||
SectionBase *Section, InputFile *File);
|
||||
|
||||
template <class ELFT>
|
||||
void addShared(StringRef Name, SharedFile<ELFT> &F,
|
||||
const typename ELFT::Sym &Sym, uint32_t Alignment,
|
||||
uint32_t VerdefIndex);
|
||||
void addShared(StringRef Name, SharedFile &F, const typename ELFT::Sym &Sym,
|
||||
uint32_t Alignment, uint32_t VerdefIndex);
|
||||
|
||||
template <class ELFT>
|
||||
void addLazyArchive(StringRef Name, ArchiveFile &F,
|
||||
|
@ -80,7 +79,7 @@ public:
|
|||
void handleDynamicList();
|
||||
|
||||
// Set of .so files to not link the same shared object file more than once.
|
||||
llvm::DenseMap<StringRef, InputFile *> SoNames;
|
||||
llvm::DenseMap<StringRef, SharedFile *> SoNames;
|
||||
|
||||
private:
|
||||
std::pair<Symbol *, bool> insertName(StringRef Name);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef LLD_ELF_SYMBOLS_H
|
||||
#define LLD_ELF_SYMBOLS_H
|
||||
|
||||
#include "InputFiles.h"
|
||||
#include "InputSection.h"
|
||||
#include "lld/Common/LLVM.h"
|
||||
#include "lld/Common/Strings.h"
|
||||
|
@ -30,8 +31,6 @@ std::string toString(const elf::InputFile *);
|
|||
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT> class SharedFile;
|
||||
|
||||
// This is a StringRef-like container that doesn't run strlen().
|
||||
//
|
||||
// ELF string tables contain a lot of null-terminated strings. Most of them
|
||||
|
@ -266,9 +265,7 @@ public:
|
|||
this->Type = llvm::ELF::STT_FUNC;
|
||||
}
|
||||
|
||||
template <class ELFT> SharedFile<ELFT> &getFile() const {
|
||||
return *cast<SharedFile<ELFT>>(File);
|
||||
}
|
||||
SharedFile &getFile() const { return *cast<SharedFile>(File); }
|
||||
|
||||
uint32_t Alignment;
|
||||
|
||||
|
|
|
@ -1263,11 +1263,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
|||
addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
|
||||
In.DynStrTab->addString(Config->Rpath));
|
||||
|
||||
for (InputFile *File : SharedFiles) {
|
||||
SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
|
||||
if (F->IsNeeded)
|
||||
addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName));
|
||||
}
|
||||
for (SharedFile *File : SharedFiles)
|
||||
if (File->IsNeeded)
|
||||
addInt(DT_NEEDED, In.DynStrTab->addString(File->SoName));
|
||||
if (!Config->SoName.empty())
|
||||
addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName));
|
||||
|
||||
|
@ -2792,7 +2790,7 @@ VersionNeedBaseSection::VersionNeedBaseSection()
|
|||
}
|
||||
|
||||
template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
|
||||
auto &File = cast<SharedFile<ELFT>>(*SS->File);
|
||||
auto &File = cast<SharedFile>(*SS->File);
|
||||
if (SS->VerdefIndex == VER_NDX_GLOBAL) {
|
||||
SS->VersionId = VER_NDX_GLOBAL;
|
||||
return;
|
||||
|
@ -2803,8 +2801,9 @@ template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
|
|||
// for the soname.
|
||||
if (File.VerdefMap.empty())
|
||||
Needed.push_back({&File, In.DynStrTab->addString(File.SoName)});
|
||||
const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
|
||||
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
|
||||
auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(
|
||||
File.Verdefs[SS->VerdefIndex]);
|
||||
typename SharedFile::NeededVer &NV = File.VerdefMap[Ver];
|
||||
|
||||
// If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
|
||||
// prepare to create one by allocating a version identifier and creating a
|
||||
|
@ -2822,7 +2821,7 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
|
||||
auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
|
||||
|
||||
for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
|
||||
for (std::pair<SharedFile *, size_t> &P : Needed) {
|
||||
// Create an Elf_Verneed for this DSO.
|
||||
Verneed->vn_version = 1;
|
||||
Verneed->vn_cnt = P.first->VerdefMap.size();
|
||||
|
@ -2839,7 +2838,8 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
// pointers, but is deterministic because the pointers refer to Elf_Verdef
|
||||
// data structures within a single input file.
|
||||
for (auto &NV : P.first->VerdefMap) {
|
||||
Vernaux->vna_hash = NV.first->vd_hash;
|
||||
Vernaux->vna_hash =
|
||||
reinterpret_cast<const typename ELFT::Verdef *>(NV.first)->vd_hash;
|
||||
Vernaux->vna_flags = 0;
|
||||
Vernaux->vna_other = NV.second.Index;
|
||||
Vernaux->vna_name = NV.second.StrTab;
|
||||
|
@ -2860,7 +2860,7 @@ template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
|
|||
|
||||
template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
|
||||
unsigned Size = Needed.size() * sizeof(Elf_Verneed);
|
||||
for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
|
||||
for (const std::pair<SharedFile *, size_t> &P : Needed)
|
||||
Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
|
||||
return Size;
|
||||
}
|
||||
|
|
|
@ -809,7 +809,7 @@ class VersionNeedSection final : public VersionNeedBaseSection {
|
|||
|
||||
// A vector of shared files that need Elf_Verneed data structures and the
|
||||
// string table offsets of their sonames.
|
||||
std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
|
||||
std::vector<std::pair<SharedFile *, size_t>> Needed;
|
||||
|
||||
public:
|
||||
void addSymbol(Symbol *Sym) override;
|
||||
|
|
|
@ -1628,15 +1628,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
// ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to
|
||||
// catch more cases. That is too much for us. Our approach resembles the one
|
||||
// used in ld.gold, achieves a good balance to be useful but not too smart.
|
||||
for (InputFile *File : SharedFiles) {
|
||||
SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
|
||||
F->AllNeededIsKnown = llvm::all_of(F->DtNeeded, [&](StringRef Needed) {
|
||||
return Symtab->SoNames.count(Needed);
|
||||
});
|
||||
}
|
||||
for (SharedFile *File : SharedFiles)
|
||||
File->AllNeededIsKnown =
|
||||
llvm::all_of(File->DtNeeded, [&](StringRef Needed) {
|
||||
return Symtab->SoNames.count(Needed);
|
||||
});
|
||||
for (Symbol *Sym : Symtab->getSymbols())
|
||||
if (Sym->isUndefined() && !Sym->isWeak())
|
||||
if (auto *F = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
|
||||
if (auto *F = dyn_cast_or_null<SharedFile>(Sym->File))
|
||||
if (F->AllNeededIsKnown)
|
||||
error(toString(F) + ": undefined reference to " + toString(*Sym));
|
||||
}
|
||||
|
@ -1651,7 +1650,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
|
||||
if (Sym->includeInDynsym()) {
|
||||
In.DynSymTab->addSymbol(Sym);
|
||||
if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
|
||||
if (auto *File = dyn_cast_or_null<SharedFile>(Sym->File))
|
||||
if (File->IsNeeded && !Sym->isUndefined())
|
||||
In.VerNeed->addSymbol(Sym);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue