ELF2: Move Target and entry initialization from SymbolTable to Driver.

SymbolTable was not a right place for initialization. We had to do that
because Driver didn't know what type of ELF objects are being handled.
We taught Driver that, so we can now move this code to Driver.

llvm-svn: 249904
This commit is contained in:
Rui Ueyama 2015-10-09 21:12:40 +00:00
parent 6e98cd32dc
commit ff77768569
5 changed files with 61 additions and 63 deletions

View File

@ -18,6 +18,8 @@
namespace lld {
namespace elf2 {
class SymbolBody;
enum ELFKind {
ELFNoneKind,
ELF32LEKind,
@ -27,6 +29,7 @@ enum ELFKind {
};
struct Configuration {
SymbolBody *EntrySym = nullptr;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
llvm::StringRef Fini;

View File

@ -12,6 +12,7 @@
#include "Error.h"
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Target.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@ -70,6 +71,26 @@ static void setELFType(StringRef Emul) {
error(Twine("Unknown emulation: ") + Emul);
}
static TargetInfo *createTarget() {
switch (Config->EMachine) {
case EM_386:
return new X86TargetInfo();
case EM_AARCH64:
return new AArch64TargetInfo();
case EM_ARM:
return new ARMTargetInfo();
case EM_MIPS:
return new MipsTargetInfo();
case EM_PPC:
return new PPCTargetInfo();
case EM_PPC64:
return new PPC64TargetInfo();
case EM_X86_64:
return new X86_64TargetInfo();
}
error("Unknown target machine");
}
// Makes a path by concatenating Dir and File.
// If Dir starts with '=' the result will be preceded by Sysroot,
// which can be set with --sysroot command line switch.
@ -257,12 +278,33 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
Target.reset(createTarget());
if (!Config->Shared) {
// Add entry symbol.
Config->EntrySym = Symtab.addUndefined(
Config->Entry.empty() ? Target->getDefaultEntry() : Config->Entry);
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
// is magical and is used to produce a R_386_GOTPC relocation.
// The R_386_GOTPC relocation value doesn't actually depend on the
// symbol value, so it could use an index of STN_UNDEF which, according
// to the spec, means the symbol value is 0.
// Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
// the object file.
// The situation is even stranger on x86_64 where the assembly doesn't
// need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
// 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.
Symtab.addIgnoredSym("_GLOBAL_OFFSET_TABLE_");
}
for (std::unique_ptr<InputFile> &F : Files)
Symtab.addFile(std::move(F));
for (auto *Arg : Args.filtered(OPT_undefined))
Symtab.addUndefinedSym(Arg->getValue());
Symtab.addUndefinedOpt(Arg->getValue());
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";

View File

@ -11,7 +11,6 @@
#include "Config.h"
#include "Error.h"
#include "Symbols.h"
#include "Target.h"
using namespace llvm;
using namespace llvm::object;
@ -47,28 +46,18 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
addELFFile(cast<ELFFileBase>(File.release()));
}
static TargetInfo *createTarget(uint16_t EMachine) {
switch (EMachine) {
case EM_386:
return new X86TargetInfo();
case EM_AARCH64:
return new AArch64TargetInfo();
case EM_ARM:
return new ARMTargetInfo();
case EM_MIPS:
return new MipsTargetInfo();
case EM_PPC:
return new PPCTargetInfo();
case EM_PPC64:
return new PPC64TargetInfo();
case EM_X86_64:
return new X86_64TargetInfo();
}
error("Unknown target machine");
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
auto *Sym = new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Required);
resolve(Sym);
return Sym;
}
template <class ELFT> void SymbolTable<ELFT>::addUndefinedSym(StringRef Name) {
resolve(new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Optional));
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
auto *Sym = new (Alloc) Undefined<ELFT>(Name, Undefined<ELFT>::Optional);
resolve(Sym);
return Sym;
}
template <class ELFT>
@ -89,40 +78,12 @@ template <class ELFT> void SymbolTable<ELFT>::addIgnoredSym(StringRef Name) {
resolve(Sym);
}
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(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.
// The R_386_GOTPC relocation value doesn't actually depend on the
// symbol value, so it could use an index of STN_UNDEF which, according to the
// spec, means the symbol value is 0.
// Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
// the object file.
// The situation is even stranger on x86_64 where the assembly doesn't
// need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
// 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("_GLOBAL_OFFSET_TABLE_");
}
template <class ELFT> void SymbolTable<ELFT>::addELFFile(ELFFileBase *File) {
const ELFFileBase *Old = getFirstELF();
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(File->getEMachine());
if (auto *O = dyn_cast<ObjectFileBase>(File)) {
for (SymbolBody *Body : O->getSymbols())
resolve(Body);

View File

@ -55,17 +55,10 @@ public:
return SharedFiles;
}
SymbolBody *getEntrySym() const {
if (!EntrySym)
return nullptr;
return EntrySym->repl();
}
void addUndefinedSym(StringRef Name);
SymbolBody *addUndefined(StringRef Name);
SymbolBody *addUndefinedOpt(StringRef Name);
void addSyntheticSym(StringRef Name, OutputSection<ELFT> &Section,
typename llvm::object::ELFFile<ELFT>::uintX_t Value);
void addIgnoredSym(StringRef Name);
private:
@ -97,8 +90,6 @@ private:
std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
llvm::DenseSet<StringRef> IncludedSoNames;
SymbolBody *EntrySym = nullptr;
};
} // namespace elf2

View File

@ -580,8 +580,9 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC;
EHdr->e_machine = FirstObj.getEMachine();
EHdr->e_version = EV_CURRENT;
SymbolBody *Entry = Symtab.getEntrySym();
EHdr->e_entry = Entry ? getSymVA<ELFT>(cast<ELFSymbolBody<ELFT>>(*Entry)) : 0;
if (Config->EntrySym)
if (auto *E = dyn_cast<ELFSymbolBody<ELFT>>(Config->EntrySym->repl()))
EHdr->e_entry = getSymVA<ELFT>(*E);
EHdr->e_phoff = ProgramHeaderOff;
EHdr->e_shoff = SectionHeaderOff;
EHdr->e_ehsize = sizeof(Elf_Ehdr);