ELF2: Make SymbolTable a template class.

SymbolTable was not a template class. Instead we had switch-case-based
type dispatch to call desired functions. We had to do that because
SymbolTable was created before we know what ELF type objects had been
passed.

Every time I tried to add a new function to the symbol table, I had to
define a dispatcher which consist of a single switch statement.

It also brought an restriction what the driver can do. For example,
we cannot add undefined symbols before any files are added to the symbol
table. That's because no symbols can be added until the symbol table
knows the ELF type, but when it knows about that, it's too late.

In this patch, the driver makes a decision on what ELF type objects
are being handled. Then the driver creates a SymbolTable object for
an appropriate ELF type.

http://reviews.llvm.org/D13544

llvm-svn: 249902
This commit is contained in:
Rui Ueyama 2015-10-09 21:07:25 +00:00
parent 1ff409802d
commit 3ce825ed26
11 changed files with 179 additions and 208 deletions

View File

@ -46,7 +46,6 @@ struct Configuration {
bool NoUndefined;
bool Shared;
bool Static = false;
bool WholeArchive = false;
bool ZNow = false;
ELFKind ElfKind = ELFNoneKind;
uint16_t EMachine = llvm::ELF::EM_NONE;

View File

@ -20,6 +20,7 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;
@ -32,7 +33,7 @@ void lld::elf2::link(ArrayRef<const char *> Args) {
LinkerDriver D;
Config = &C;
Driver = &D;
Driver->link(Args.slice(1));
Driver->main(Args.slice(1));
}
static void setELFType(StringRef Emul) {
@ -102,28 +103,6 @@ static std::string searchLibrary(StringRef Path) {
error(Twine("Unable to find library -l") + Path);
}
template <template <class> class T>
std::unique_ptr<ELFFileBase>
LinkerDriver::createELFInputFile(MemoryBufferRef MB) {
std::unique_ptr<ELFFileBase> File = createELFFile<T>(MB);
const ELFKind ElfKind = File->getELFKind();
const uint16_t EMachine = File->getEMachine();
// Grab target from the first input file if wasn't set by -m option.
if (Config->ElfKind == ELFNoneKind) {
Config->ElfKind = ElfKind;
Config->EMachine = EMachine;
return File;
}
if (ElfKind == Config->ElfKind && EMachine == Config->EMachine)
return File;
if (const ELFFileBase *First = Symtab.getFirstELF())
error(MB.getBufferIdentifier() + " is incompatible with " +
First->getName());
error(MB.getBufferIdentifier() + " is incompatible with target architecture");
}
// Opens and parses a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
void LinkerDriver::addFile(StringRef Path) {
@ -139,13 +118,20 @@ void LinkerDriver::addFile(StringRef Path) {
readLinkerScript(MBRef);
return;
case file_magic::archive:
Symtab.addFile(make_unique<ArchiveFile>(MBRef));
if (WholeArchive) {
auto File = make_unique<ArchiveFile>(MBRef);
for (MemoryBufferRef &MB : File->getMembers())
Files.push_back(createELFFile<ObjectFile>(MB));
OwningArchives.emplace_back(std::move(File));
return;
}
Files.push_back(make_unique<ArchiveFile>(MBRef));
return;
case file_magic::elf_shared_object:
Symtab.addFile(createELFInputFile<SharedFile>(MBRef));
Files.push_back(createELFFile<SharedFile>(MBRef));
return;
default:
Symtab.addFile(createELFInputFile<ObjectFile>(MBRef));
Files.push_back(createELFFile<ObjectFile>(MBRef));
}
}
@ -156,12 +142,31 @@ getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") {
return Default;
}
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
initSymbols();
// Parse command line options.
opt::InputArgList Args = Parser.parse(ArgsArr);
createFiles(Args);
switch (Config->ElfKind) {
case ELF32LEKind:
link<ELF32LE>(Args);
return;
case ELF32BEKind:
link<ELF32BE>(Args);
return;
case ELF64LEKind:
link<ELF64LE>(Args);
return;
case ELF64BEKind:
link<ELF64BE>(Args);
return;
default:
error("-m or at least a .o file required");
}
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_L))
Config->InputSearchPaths.push_back(Arg->getValue());
@ -211,17 +216,51 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->Static = false;
break;
case OPT_whole_archive:
Config->WholeArchive = true;
WholeArchive = true;
break;
case OPT_no_whole_archive:
Config->WholeArchive = false;
WholeArchive = false;
break;
}
}
if (Symtab.getObjectFiles().empty())
if (Files.empty())
error("no input files.");
// Set machine type if -m is not given.
if (Config->ElfKind == ELFNoneKind) {
for (std::unique_ptr<InputFile> &File : Files) {
auto *F = dyn_cast<ELFFileBase>(File.get());
if (!F)
continue;
Config->ElfKind = F->getELFKind();
Config->EMachine = F->getEMachine();
break;
}
}
// Check if all files are for the same machine type.
for (std::unique_ptr<InputFile> &File : Files) {
auto *F = dyn_cast<ELFFileBase>(File.get());
if (!F)
continue;
if (F->getELFKind() == Config->ElfKind &&
F->getEMachine() == Config->EMachine)
continue;
StringRef A = F->getName();
StringRef B = Files[0]->getName();
if (auto *Arg = Args.getLastArg(OPT_m))
B = Arg->getValue();
error(A + " is incompatible with " + B);
}
}
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
for (std::unique_ptr<InputFile> &F : Files)
Symtab.addFile(std::move(F));
for (auto *Arg : Args.filtered(OPT_undefined))
Symtab.addUndefinedSym(Arg->getValue());
@ -229,5 +268,5 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->OutputFile = "a.out";
// Write the result to the file.
writeResult(&Symtab);
writeResult<ELFT>(&Symtab);
}

View File

@ -34,15 +34,20 @@ private:
class LinkerDriver {
public:
void link(ArrayRef<const char *> Args);
void main(ArrayRef<const char *> Args);
void createFiles(llvm::opt::InputArgList &Args);
template <class ELFT> void link(llvm::opt::InputArgList &Args);
void addFile(StringRef Path);
private:
template <template <class> class T>
std::unique_ptr<ELFFileBase> createELFInputFile(MemoryBufferRef MB);
SymbolTable Symtab;
ArgParser Parser;
bool WholeArchive = false;
std::vector<std::unique_ptr<InputFile>> Files;
std::vector<std::unique_ptr<ArchiveFile>> OwningArchives;
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
};

View File

@ -232,7 +232,7 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
template <class ELFT>
DynamicSection<ELFT>::DynamicSection(SymbolTable &SymTab)
DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab)
: OutputSectionBase<ELFT::Is64Bits>(".dynamic", llvm::ELF::SHT_DYNAMIC,
llvm::ELF::SHF_ALLOC |
llvm::ELF::SHF_WRITE),
@ -278,7 +278,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
if (FiniArraySec)
NumEntries += 2;
for (const std::unique_ptr<SharedFileBase> &F : SymTab.getSharedFiles()) {
for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) {
Out<ELFT>::DynStrTab->add(F->getSoName());
++NumEntries;
}
@ -355,7 +355,7 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
WriteArray(DT_INIT_ARRAY, DT_INIT_ARRAYSZ, InitArraySec);
WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec);
for (const std::unique_ptr<SharedFileBase> &F : SymTab.getSharedFiles())
for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles())
WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->getFileOff(F->getSoName()));
if (InitSym)
@ -521,7 +521,7 @@ bool lld::elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File,
template <class ELFT>
SymbolTableSection<ELFT>::SymbolTableSection(
SymbolTable &Table, StringTableSection<ELFT::Is64Bits> &StrTabSec)
SymbolTable<ELFT> &Table, StringTableSection<ELFT::Is64Bits> &StrTabSec)
: OutputSectionBase<ELFT::Is64Bits>(
StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
StrTabSec.isDynamic() ? llvm::ELF::SHT_DYNSYM : llvm::ELF::SHT_SYMTAB,
@ -563,14 +563,13 @@ template <class ELFT>
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
// Iterate over all input object files to copy their local symbols
// to the output symbol table pointed by Buf.
for (const std::unique_ptr<ObjectFileBase> &FileB : Table.getObjectFiles()) {
auto &File = cast<ObjectFile<ELFT>>(*FileB);
Elf_Sym_Range Syms = File.getLocalSymbols();
for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) {
Elf_Sym_Range Syms = File->getLocalSymbols();
for (const Elf_Sym &Sym : Syms) {
ErrorOr<StringRef> SymNameOrErr = Sym.getName(File.getStringTable());
ErrorOr<StringRef> SymNameOrErr = Sym.getName(File->getStringTable());
error(SymNameOrErr);
StringRef SymName = *SymNameOrErr;
if (!shouldKeepInSymtab<ELFT>(File, SymName, Sym))
if (!shouldKeepInSymtab<ELFT>(*File, SymName, Sym))
continue;
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
@ -584,9 +583,9 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
ESym->st_shndx = SHN_ABS;
} else {
if (SecIndex == SHN_XINDEX)
SecIndex = File.getObj().getExtendedSymbolTableIndex(
&Sym, File.getSymbolTable(), File.getSymbolTableShndx());
ArrayRef<InputSection<ELFT> *> Sections = File.getSections();
SecIndex = File->getObj().getExtendedSymbolTableIndex(
&Sym, File->getSymbolTable(), File->getSymbolTableShndx());
ArrayRef<InputSection<ELFT> *> Sections = File->getSections();
const InputSection<ELFT> *Section = Sections[SecIndex];
const OutputSection<ELFT> *OutSec = Section->getOutputSection();
ESym->st_shndx = OutSec->getSectionIndex();

View File

@ -23,7 +23,7 @@ namespace lld {
namespace elf2 {
class SymbolBody;
class SymbolTable;
template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <bool Is64Bits> class StringTableSection;
template <class ELFT> class InputSection;
@ -146,7 +146,7 @@ public:
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
SymbolTableSection(SymbolTable &Table,
SymbolTableSection(SymbolTable<ELFT> &Table,
StringTableSection<ELFT::Is64Bits> &StrTabSec);
void finalize() override;
@ -159,7 +159,7 @@ private:
void writeLocalSymbols(uint8_t *&Buf);
void writeGlobalSymbols(uint8_t *&Buf);
SymbolTable &Table;
SymbolTable<ELFT> &Table;
StringTableSection<ELFT::Is64Bits> &StrTabSec;
unsigned NumVisible = 0;
unsigned NumLocals = 0;
@ -265,7 +265,7 @@ class DynamicSection final : public OutputSectionBase<ELFT::Is64Bits> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
public:
DynamicSection(SymbolTable &SymTab);
DynamicSection(SymbolTable<ELFT> &SymTab);
void finalize() override;
void writeTo(uint8_t *Buf) override;
@ -274,7 +274,7 @@ public:
OutputSection<ELFT> *FiniArraySec = nullptr;
private:
SymbolTable &SymTab;
SymbolTable<ELFT> &SymTab;
const ELFSymbolBody<ELFT> *InitSym = nullptr;
const ELFSymbolBody<ELFT> *FiniSym = nullptr;
};

View File

@ -20,22 +20,17 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf2;
SymbolTable::SymbolTable() {}
template <class ELFT> SymbolTable<ELFT>::SymbolTable() {}
bool SymbolTable::shouldUseRela() const {
template <class ELFT> bool SymbolTable<ELFT>::shouldUseRela() const {
ELFKind K = getFirstELF()->getELFKind();
return K == ELF64LEKind || K == ELF64BEKind;
}
void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
template <class ELFT>
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
if (auto *AF = dyn_cast<ArchiveFile>(File.get())) {
File.release();
ArchiveFiles.emplace_back(AF);
if (Config->WholeArchive) {
for (MemoryBufferRef &MBRef : AF->getMembers())
addFile(createELFFile<ObjectFile>(MBRef));
return;
}
ArchiveFiles.emplace_back(std::move(File));
AF->parse();
for (Lazy &Sym : AF->getLazySymbols())
addLazy(&Sym);
@ -72,54 +67,36 @@ static TargetInfo *createTarget(uint16_t EMachine) {
error("Unknown target machine");
}
void SymbolTable::addUndefinedSym(StringRef Name) {
switch (getFirstELF()->getELFKind()) {
case ELF32LEKind:
addUndefinedSym<ELF32LE>(Name);
break;
case ELF32BEKind:
addUndefinedSym<ELF32BE>(Name);
break;
case ELF64LEKind:
addUndefinedSym<ELF64LE>(Name);
break;
case ELF64BEKind:
addUndefinedSym<ELF64BE>(Name);
break;
default:
llvm_unreachable("Invalid kind");
}
}
template <class ELFT> void SymbolTable::addUndefinedSym(StringRef Name) {
resolve<ELFT>(new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Optional));
template <class ELFT> void SymbolTable<ELFT>::addUndefinedSym(StringRef Name) {
resolve(new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Optional));
}
template <class ELFT>
void SymbolTable::addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section,
typename ELFFile<ELFT>::uintX_t Value) {
void SymbolTable<ELFT>::addSyntheticSym(StringRef Name,
OutputSection<ELFT> &Section,
typename ELFFile<ELFT>::uintX_t Value) {
typedef typename DefinedSynthetic<ELFT>::Elf_Sym Elf_Sym;
auto ESym = new (Alloc) Elf_Sym;
memset(ESym, 0, sizeof(Elf_Sym));
ESym->st_value = Value;
auto Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, *ESym, Section);
resolve<ELFT>(Sym);
resolve(Sym);
}
template <class ELFT> void SymbolTable::addIgnoredSym(StringRef Name) {
template <class ELFT> void SymbolTable<ELFT>::addIgnoredSym(StringRef Name) {
auto Sym = new (Alloc)
DefinedAbsolute<ELFT>(Name, DefinedAbsolute<ELFT>::IgnoreUndef);
resolve<ELFT>(Sym);
resolve(Sym);
}
template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
template <class ELFT> void SymbolTable<ELFT>::init(uint16_t EMachine) {
Target.reset(createTarget(EMachine));
if (Config->Shared)
return;
EntrySym = new (Alloc) Undefined<ELFT>(
Config->Entry.empty() ? Target->getDefaultEntry() : Config->Entry,
Undefined<ELFT>::Required);
resolve<ELFT>(EntrySym);
resolve(EntrySym);
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol is magical
// and is used to produce a R_386_GOTPC relocation.
@ -133,52 +110,34 @@ template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
// an undefined symbol in the .o files.
// Given that the symbol is effectively unused, we just create a dummy
// hidden one to avoid the undefined symbol error.
addIgnoredSym<ELFT>("_GLOBAL_OFFSET_TABLE_");
addIgnoredSym("_GLOBAL_OFFSET_TABLE_");
}
template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
template <class ELFT> void SymbolTable<ELFT>::addELFFile(ELFFileBase *File) {
const ELFFileBase *Old = getFirstELF();
if (auto *O = dyn_cast<ObjectFileBase>(File))
if (auto *O = dyn_cast<ObjectFile<ELFT>>(File))
ObjectFiles.emplace_back(O);
else if (auto *S = dyn_cast<SharedFile<ELFT>>(File))
SharedFiles.emplace_back(S);
if (!Old)
init<ELFT>(File->getEMachine());
init(File->getEMachine());
if (auto *O = dyn_cast<ObjectFileBase>(File)) {
for (SymbolBody *Body : O->getSymbols())
resolve<ELFT>(Body);
resolve(Body);
}
if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
resolve<ELFT>(&Body);
}
}
void SymbolTable::addELFFile(ELFFileBase *File) {
switch (File->getELFKind()) {
case ELF32LEKind:
addELFFile<ELF32LE>(File);
break;
case ELF32BEKind:
addELFFile<ELF32BE>(File);
break;
case ELF64LEKind:
addELFFile<ELF64LE>(File);
break;
case ELF64BEKind:
addELFFile<ELF64BE>(File);
break;
default:
llvm_unreachable("Invalid kind");
resolve(&Body);
}
}
template <class ELFT>
void SymbolTable::reportConflict(const Twine &Message, const SymbolBody &Old,
const SymbolBody &New, bool Warning) {
void SymbolTable<ELFT>::reportConflict(const Twine &Message,
const SymbolBody &Old,
const SymbolBody &New, bool Warning) {
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
@ -187,13 +146,12 @@ void SymbolTable::reportConflict(const Twine &Message, const SymbolBody &Old,
ELFFileBase *OldFile = nullptr;
ELFFileBase *NewFile = nullptr;
for (const std::unique_ptr<ObjectFileBase> &F : ObjectFiles) {
const auto &File = cast<ObjectFile<ELFT>>(*F);
Elf_Sym_Range Syms = File.getObj().symbols(File.getSymbolTable());
for (const std::unique_ptr<ObjectFile<ELFT>> &File : ObjectFiles) {
Elf_Sym_Range Syms = File->getObj().symbols(File->getSymbolTable());
if (&OldE > Syms.begin() && &OldE < Syms.end())
OldFile = F.get();
OldFile = File.get();
if (&NewE > Syms.begin() && &NewE < Syms.end())
NewFile = F.get();
NewFile = File.get();
}
std::string Msg = (Message + ": " + Old.getName() + " in " +
@ -207,7 +165,7 @@ void SymbolTable::reportConflict(const Twine &Message, const SymbolBody &Old,
// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
Symbol *Sym = insert(New);
if (Sym->Body == New)
return;
@ -233,8 +191,7 @@ template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
}
if (New->isTLS() != Existing->isTLS())
reportConflict<ELFT>("TLS attribute mismatch for symbol", *Existing, *New,
false);
reportConflict("TLS attribute mismatch for symbol", *Existing, *New, false);
// compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
// equivalent (conflicting), or more preferable, respectively.
@ -242,11 +199,11 @@ template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
if (comp < 0)
Sym->Body = New;
else if (comp == 0)
reportConflict<ELFT>("duplicate symbol", *Existing, *New,
Config->AllowMultipleDefinition);
reportConflict("duplicate symbol", *Existing, *New,
Config->AllowMultipleDefinition);
}
Symbol *SymbolTable::insert(SymbolBody *New) {
template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
// Find an existing Symbol or create and insert a new one.
StringRef Name = New->getName();
Symbol *&Sym = Symtab[Name];
@ -259,7 +216,7 @@ Symbol *SymbolTable::insert(SymbolBody *New) {
return Sym;
}
void SymbolTable::addLazy(Lazy *New) {
template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *New) {
Symbol *Sym = insert(New);
if (Sym->Body == New)
return;
@ -284,7 +241,7 @@ void SymbolTable::addLazy(Lazy *New) {
addMemberFile(New);
}
void SymbolTable::addMemberFile(Lazy *Body) {
template <class ELFT> void SymbolTable<ELFT>::addMemberFile(Lazy *Body) {
std::unique_ptr<InputFile> File = Body->getMember();
// getMember returns nullptr if the member was already read from the library.
@ -294,20 +251,7 @@ void SymbolTable::addMemberFile(Lazy *Body) {
addFile(std::move(File));
}
namespace lld {
namespace elf2 {
template void SymbolTable::addSyntheticSym(StringRef, OutputSection<ELF32LE> &,
ELFFile<ELF32LE>::uintX_t);
template void SymbolTable::addSyntheticSym(StringRef, OutputSection<ELF32BE> &,
ELFFile<ELF32BE>::uintX_t);
template void SymbolTable::addSyntheticSym(StringRef, OutputSection<ELF64LE> &,
ELFFile<ELF64LE>::uintX_t);
template void SymbolTable::addSyntheticSym(StringRef, OutputSection<ELF64BE> &,
ELFFile<ELF64BE>::uintX_t);
template void SymbolTable::addIgnoredSym<ELF32LE>(StringRef);
template void SymbolTable::addIgnoredSym<ELF32BE>(StringRef);
template void SymbolTable::addIgnoredSym<ELF64LE>(StringRef);
template void SymbolTable::addIgnoredSym<ELF64BE>(StringRef);
}
}
template class lld::elf2::SymbolTable<ELF32LE>;
template class lld::elf2::SymbolTable<ELF32BE>;
template class lld::elf2::SymbolTable<ELF64LE>;
template class lld::elf2::SymbolTable<ELF64BE>;

View File

@ -27,7 +27,7 @@ struct Symbol;
// an undefined symbol. Or, if there's a conflict between a lazy and a
// undefined, it'll read an archive member to read a real definition
// to replace the lazy symbol. The logic is implemented in resolve().
class SymbolTable {
template <class ELFT> class SymbolTable {
public:
SymbolTable();
@ -47,11 +47,11 @@ public:
return Symtab;
}
const std::vector<std::unique_ptr<ObjectFileBase>> &getObjectFiles() const {
const std::vector<std::unique_ptr<ObjectFile<ELFT>>> &getObjectFiles() const {
return ObjectFiles;
}
const std::vector<std::unique_ptr<SharedFileBase>> &getSharedFiles() const {
const std::vector<std::unique_ptr<SharedFile<ELFT>>> &getSharedFiles() const {
return SharedFiles;
}
@ -63,27 +63,22 @@ public:
void addUndefinedSym(StringRef Name);
template <class ELFT>
void addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section,
typename llvm::object::ELFFile<ELFT>::uintX_t Value);
template <class ELFT> void addIgnoredSym(StringRef Name);
void addIgnoredSym(StringRef Name);
private:
Symbol *insert(SymbolBody *New);
template <class ELFT> void addELFFile(ELFFileBase *File);
void addELFFile(ELFFileBase *File);
void addLazy(Lazy *New);
void addMemberFile(Lazy *Body);
template <class ELFT> void addUndefinedSym(StringRef Name);
template <class ELFT> void init(uint16_t EMachine);
template <class ELFT> void resolve(SymbolBody *Body);
template <class ELFT>
void init(uint16_t EMachine);
void resolve(SymbolBody *Body);
void reportConflict(const Twine &Message, const SymbolBody &Old,
const SymbolBody &New, bool Warning);
std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
std::vector<std::unique_ptr<InputFile>> ArchiveFiles;
// The order the global symbols are in is not defined. We can use an arbitrary
// order, but it has to be reproducible. That is true even when cross linking.
@ -98,9 +93,9 @@ private:
llvm::DenseSet<StringRef> Comdats;
// The writer needs to infer the machine type from the object files.
std::vector<std::unique_ptr<ObjectFileBase>> ObjectFiles;
std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
std::vector<std::unique_ptr<SharedFileBase>> SharedFiles;
std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
llvm::DenseSet<StringRef> IncludedSoNames;
SymbolBody *EntrySym = nullptr;

View File

@ -71,7 +71,7 @@ public:
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
Writer(SymbolTable &S) : Symtab(S) {}
Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
void run();
private:
@ -101,7 +101,7 @@ private:
unsigned getNumSections() const { return OutputSections.size() + 1; }
llvm::BumpPtrAllocator PAlloc;
SymbolTable &Symtab;
SymbolTable<ELFT> &Symtab;
std::vector<ProgramHeader<ELFT> *> PHDRs;
ProgramHeader<ELFT> PhdrPHDR{PT_PHDR, PF_R, 0, 0};
ProgramHeader<ELFT> FileHeaderPHDR{PT_LOAD, PF_R, 0, 0};
@ -114,7 +114,7 @@ private:
};
} // anonymous namespace
template <class ELFT> static void doWriteResult(SymbolTable *Symtab) {
template <class ELFT> void lld::elf2::writeResult(SymbolTable<ELFT> *Symtab) {
// Initialize output sections that are handled by Writer specially.
// Don't reorder because the order of initialization matters.
InterpSection<ELFT::Is64Bits> Interp;
@ -143,25 +143,6 @@ template <class ELFT> static void doWriteResult(SymbolTable *Symtab) {
Writer<ELFT>(*Symtab).run();
}
void lld::elf2::writeResult(SymbolTable *Symtab) {
switch (Symtab->getFirstELF()->getELFKind()) {
case ELF32LEKind:
doWriteResult<object::ELF32LE>(Symtab);
return;
case ELF32BEKind:
doWriteResult<object::ELF32BE>(Symtab);
return;
case ELF64LEKind:
doWriteResult<object::ELF64LE>(Symtab);
return;
case ELF64BEKind:
doWriteResult<object::ELF64BE>(Symtab);
return;
default:
llvm_unreachable("Invalid kind");
}
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
if (!Config->DiscardAll)
@ -260,7 +241,7 @@ void Writer<ELFT>::scanRelocs(const InputSection<ELFT> &C) {
}
template <class ELFT>
static void reportUndefined(const SymbolTable &S, const SymbolBody &Sym) {
static void reportUndefined(const SymbolTable<ELFT> &S, const SymbolBody &Sym) {
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
@ -270,11 +251,10 @@ static void reportUndefined(const SymbolTable &S, const SymbolBody &Sym) {
const Elf_Sym &SymE = cast<ELFSymbolBody<ELFT>>(Sym).Sym;
ELFFileBase *SymFile = nullptr;
for (const std::unique_ptr<ObjectFileBase> &F : S.getObjectFiles()) {
const auto &File = cast<ObjectFile<ELFT>>(*F);
Elf_Sym_Range Syms = File.getObj().symbols(File.getSymbolTable());
for (const std::unique_ptr<ObjectFile<ELFT>> &File : S.getObjectFiles()) {
Elf_Sym_Range Syms = File->getObj().symbols(File->getSymbolTable());
if (&SymE > Syms.begin() && &SymE < Syms.end())
SymFile = F.get();
SymFile = File.get();
}
std::string Message = "undefined symbol: " + Sym.getName().str();
@ -289,13 +269,12 @@ static void reportUndefined(const SymbolTable &S, const SymbolBody &Sym) {
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
auto &File = cast<ObjectFile<ELFT>>(*FileB);
for (const Elf_Sym &Sym : File.getLocalSymbols()) {
ErrorOr<StringRef> SymNameOrErr = Sym.getName(File.getStringTable());
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (const Elf_Sym &Sym : F->getLocalSymbols()) {
ErrorOr<StringRef> SymNameOrErr = Sym.getName(F->getStringTable());
error(SymNameOrErr);
StringRef SymName = *SymNameOrErr;
if (!shouldKeepInSymtab<ELFT>(File, SymName, Sym))
if (!shouldKeepInSymtab<ELFT>(*F, SymName, Sym))
continue;
Out<ELFT>::SymTab->addSymbol(SymName, true);
}
@ -387,18 +366,17 @@ template <class ELFT> void Writer<ELFT>::createSections() {
for (StringRef Name :
{"__preinit_array_start", "__preinit_array_end", "__init_array_start",
"__init_array_end", "__fini_array_start", "__fini_array_end"})
Symtab.addIgnoredSym<ELFT>(Name);
Symtab.addIgnoredSym(Name);
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
// to avoid the undefined symbol error.
if (!isOutputDynamic())
Symtab.addIgnoredSym<ELFT>("__tls_get_addr");
Symtab.addIgnoredSym("__tls_get_addr");
for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
auto &File = cast<ObjectFile<ELFT>>(*FileB);
for (InputSection<ELFT> *C : File.getSections()) {
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
for (InputSection<ELFT> *C : F->getSections()) {
if (!C || C == &InputSection<ELFT>::Discarded)
continue;
const Elf_Shdr *H = C->getSectionHdr();
@ -425,8 +403,8 @@ template <class ELFT> void Writer<ELFT>::createSections() {
auto AddStartEnd = [&](StringRef Start, StringRef End,
OutputSection<ELFT> *OS) {
if (OS) {
Symtab.addSyntheticSym<ELFT>(Start, *OS, 0);
Symtab.addSyntheticSym<ELFT>(End, *OS, OS->getSize());
Symtab.addSyntheticSym(Start, *OS, 0);
Symtab.addSyntheticSym(End, *OS, OS->getSize());
}
};
@ -651,3 +629,8 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections)
Sec->writeTo(Buf + Sec->getFileOff());
}
template void lld::elf2::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
template void lld::elf2::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
template void lld::elf2::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
template void lld::elf2::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);

View File

@ -13,10 +13,9 @@
namespace lld {
namespace elf2 {
class SymbolTable;
void writeResult(SymbolTable *Symtab);
template <class ELFT> class SymbolTable;
template <class ELFT> void writeResult(SymbolTable<ELFT> *Symtab);
}
}

View File

@ -25,22 +25,22 @@
// RUN: not ld.lld2 -m elf64ppc %ta.o -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=A-ONLY %s
// A-ONLY: a.o is incompatible with target architecture
// A-ONLY: a.o is incompatible with elf64ppc
// RUN: not ld.lld2 -m elf64ppc %tb.o -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=B-ONLY %s
// B-ONLY: b.o is incompatible with target architecture
// B-ONLY: b.o is incompatible with elf64ppc
// RUN: not ld.lld2 -m elf64ppc %tc.o -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=C-ONLY %s
// C-ONLY: c.o is incompatible with target architecture
// C-ONLY: c.o is incompatible with elf64ppc
// RUN: not ld.lld2 -m elf_i386 %tc.o %ti686.so -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=C-AND-SO-I386 %s
// C-AND-SO-I386: c.o is incompatible with target architecture
// C-AND-SO-I386: c.o is incompatible with elf_i386
// RUN: not ld.lld2 -m elf_i386 %ti686.so %tc.o -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=SO-AND-C-I386 %s
// SO-AND-C-I386: c.o is incompatible with {{.*}}i686.so
// SO-AND-C-I386: c.o is incompatible with elf_i386
// REQUIRES: x86,arm

8
lld/test/elf2/no-obj.s Normal file
View File

@ -0,0 +1,8 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: llvm-ar rcs %t.a %t.o
// RUN: not ld.lld2 -o %t2 -u _start %t.a 2>&1 | FileCheck %s
// CHECK: -m or at least a .o file required
.global _start
_start: