mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-01 12:43:47 +00:00
[ELF2] Add a new ELF linker based on the new PE/COFF linker.
Differential Revision: http://reviews.llvm.org/D11188 llvm-svn: 243161
This commit is contained in:
parent
b9e045af44
commit
84487f1174
@ -97,3 +97,4 @@ endif()
|
||||
|
||||
add_subdirectory(docs)
|
||||
add_subdirectory(COFF)
|
||||
add_subdirectory(ELF)
|
||||
|
20
lld/ELF/CMakeLists.txt
Normal file
20
lld/ELF/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
set(LLVM_TARGET_DEFINITIONS Options.td)
|
||||
tablegen(LLVM Options.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(ELFOptionsTableGen)
|
||||
|
||||
add_llvm_library(lldELF2
|
||||
Chunks.cpp
|
||||
Driver.cpp
|
||||
DriverUtils.cpp
|
||||
InputFiles.cpp
|
||||
SymbolTable.cpp
|
||||
Symbols.cpp
|
||||
Writer.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
Object
|
||||
Option
|
||||
Support
|
||||
)
|
||||
|
||||
add_dependencies(lldELF2 ELFOptionsTableGen)
|
48
lld/ELF/Chunks.cpp
Normal file
48
lld/ELF/Chunks.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
//===- Chunks.cpp ---------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Chunks.h"
|
||||
#include "Driver.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
template <class ELFT>
|
||||
SectionChunk<ELFT>::SectionChunk(object::ELFFile<ELFT> *Obj,
|
||||
const Elf_Shdr *Header)
|
||||
: Obj(Obj), Header(Header) {
|
||||
// Initialize SectionName.
|
||||
ErrorOr<StringRef> Name = Obj->getSectionName(Header);
|
||||
error(Name);
|
||||
SectionName = *Name;
|
||||
|
||||
Align = Header->sh_addralign;
|
||||
}
|
||||
|
||||
template <class ELFT> void SectionChunk<ELFT>::writeTo(uint8_t *Buf) {
|
||||
if (Header->sh_type == SHT_NOBITS)
|
||||
return;
|
||||
// Copy section contents from source object file to output file.
|
||||
ArrayRef<uint8_t> Data = *Obj->getSectionContents(Header);
|
||||
memcpy(Buf + FileOff, Data.data(), Data.size());
|
||||
|
||||
// FIXME: Relocations
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
template class SectionChunk<object::ELF32LE>;
|
||||
template class SectionChunk<object::ELF32BE>;
|
||||
template class SectionChunk<object::ELF64LE>;
|
||||
template class SectionChunk<object::ELF64BE>;
|
||||
}
|
||||
}
|
93
lld/ELF/Chunks.h
Normal file
93
lld/ELF/Chunks.h
Normal file
@ -0,0 +1,93 @@
|
||||
//===- Chunks.h -----------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_CHUNKS_H
|
||||
#define LLD_ELF_CHUNKS_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
||||
class Defined;
|
||||
template <class ELFT> class ObjectFile;
|
||||
class OutputSection;
|
||||
|
||||
// A Chunk represents a chunk of data that will occupy space in the
|
||||
// output (if the resolver chose that). It may or may not be backed by
|
||||
// a section of an input file. It could be linker-created data, or
|
||||
// doesn't even have actual data (if common or bss).
|
||||
class Chunk {
|
||||
public:
|
||||
virtual ~Chunk() = default;
|
||||
|
||||
// Returns the size of this chunk (even if this is a common or BSS.)
|
||||
virtual size_t getSize() const = 0;
|
||||
|
||||
// Write this chunk to a mmap'ed file, assuming Buf is pointing to
|
||||
// beginning of the file. Because this function may use VA values
|
||||
// of other chunks for relocations, you need to set them properly
|
||||
// before calling this function.
|
||||
virtual void writeTo(uint8_t *Buf) = 0;
|
||||
|
||||
// The writer sets and uses the addresses.
|
||||
uint64_t getVA() { return VA; }
|
||||
uint64_t getFileOff() { return FileOff; }
|
||||
uint32_t getAlign() { return Align; }
|
||||
void setVA(uint64_t V) { VA = V; }
|
||||
void setFileOff(uint64_t V) { FileOff = V; }
|
||||
|
||||
// Returns the section name if this is a section chunk.
|
||||
// It is illegal to call this function on non-section chunks.
|
||||
virtual StringRef getSectionName() const = 0;
|
||||
|
||||
// An output section has pointers to chunks in the section, and each
|
||||
// chunk has a back pointer to an output section.
|
||||
void setOutputSection(OutputSection *O) { Out = O; }
|
||||
OutputSection *getOutputSection() { return Out; }
|
||||
|
||||
protected:
|
||||
// The VA of this chunk in the output. The writer sets a value.
|
||||
uint64_t VA = 0;
|
||||
|
||||
// The offset from beginning of the output file. The writer sets a value.
|
||||
uint64_t FileOff = 0;
|
||||
|
||||
// The output section for this chunk.
|
||||
OutputSection *Out = nullptr;
|
||||
|
||||
// The alignment of this chunk. The writer uses the value.
|
||||
uint32_t Align = 1;
|
||||
};
|
||||
|
||||
// A chunk corresponding a section of an input file.
|
||||
template <class ELFT> class SectionChunk : public Chunk {
|
||||
typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
|
||||
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
|
||||
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
|
||||
|
||||
public:
|
||||
SectionChunk(llvm::object::ELFFile<ELFT> *Obj, const Elf_Shdr *Header);
|
||||
size_t getSize() const override { return Header->sh_size; }
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
StringRef getSectionName() const override { return SectionName; }
|
||||
|
||||
private:
|
||||
// A file this chunk was created from.
|
||||
llvm::object::ELFFile<ELFT> *Obj;
|
||||
|
||||
const Elf_Shdr *Header;
|
||||
StringRef SectionName;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
27
lld/ELF/Config.h
Normal file
27
lld/ELF/Config.h
Normal file
@ -0,0 +1,27 @@
|
||||
//===- Config.h -----------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_CONFIG_H
|
||||
#define LLD_ELF_CONFIG_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
||||
struct Configuration {
|
||||
llvm::StringRef OutputFile;
|
||||
};
|
||||
|
||||
extern Configuration *Config;
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
104
lld/ELF/Driver.cpp
Normal file
104
lld/ELF/Driver.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
//===- Driver.cpp ---------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Driver.h"
|
||||
#include "Config.h"
|
||||
#include "Writer.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
Configuration *Config;
|
||||
LinkerDriver *Driver;
|
||||
|
||||
void link(ArrayRef<const char *> Args) {
|
||||
auto C = make_unique<Configuration>();
|
||||
Config = C.get();
|
||||
auto D = make_unique<LinkerDriver>();
|
||||
Driver = D.get();
|
||||
Driver->link(Args.slice(1));
|
||||
}
|
||||
|
||||
void error(Twine Msg) {
|
||||
errs() << Msg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void error(std::error_code EC, Twine Prefix) {
|
||||
if (!EC)
|
||||
return;
|
||||
error(Prefix + ": " + EC.message());
|
||||
}
|
||||
|
||||
void error(std::error_code EC) {
|
||||
if (!EC)
|
||||
return;
|
||||
error(EC.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Opens a file. Path has to be resolved already.
|
||||
// Newly created memory buffers are owned by this driver.
|
||||
MemoryBufferRef LinkerDriver::openFile(StringRef Path) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(Path);
|
||||
error(MBOrErr, Twine("cannot open ") + Path);
|
||||
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
|
||||
MemoryBufferRef MBRef = MB->getMemBufferRef();
|
||||
OwningMBs.push_back(std::move(MB)); // take ownership
|
||||
return MBRef;
|
||||
}
|
||||
|
||||
static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
|
||||
return std::unique_ptr<InputFile>(new ObjectFile<object::ELF64LE>(MB));
|
||||
}
|
||||
|
||||
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||
// Parse command line options.
|
||||
opt::InputArgList Args = Parser.parse(ArgsArr);
|
||||
|
||||
// Handle -o
|
||||
if (auto *Arg = Args.getLastArg(OPT_output))
|
||||
Config->OutputFile = Arg->getValue();
|
||||
if (Config->OutputFile.empty())
|
||||
error("-o must be specified.");
|
||||
|
||||
// Create a list of input files.
|
||||
std::vector<MemoryBufferRef> Inputs;
|
||||
|
||||
for (auto *Arg : Args.filtered(OPT_INPUT)) {
|
||||
StringRef Path = Arg->getValue();
|
||||
Inputs.push_back(openFile(Path));
|
||||
}
|
||||
|
||||
if (Inputs.empty())
|
||||
error("no input files.");
|
||||
|
||||
// Create a symbol table.
|
||||
SymbolTable<object::ELF64LE> Symtab;
|
||||
|
||||
// Parse all input files and put all symbols to the symbol table.
|
||||
// The symbol table will take care of name resolution.
|
||||
for (MemoryBufferRef MB : Inputs) {
|
||||
std::unique_ptr<InputFile> File = createFile(MB);
|
||||
Symtab.addFile(std::move(File));
|
||||
}
|
||||
|
||||
// Make sure we have resolved all symbols.
|
||||
Symtab.reportRemainingUndefines();
|
||||
|
||||
// Write the result.
|
||||
Writer<object::ELF64LE> Out(&Symtab);
|
||||
Out.write(Config->OutputFile);
|
||||
}
|
67
lld/ELF/Driver.h
Normal file
67
lld/ELF/Driver.h
Normal file
@ -0,0 +1,67 @@
|
||||
//===- Driver.h -----------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_DRIVER_H
|
||||
#define LLD_ELF_DRIVER_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
||||
class LinkerDriver;
|
||||
extern LinkerDriver *Driver;
|
||||
|
||||
class InputFile;
|
||||
|
||||
// Entry point of the ELF linker.
|
||||
void link(ArrayRef<const char *> Args);
|
||||
|
||||
void error(Twine Msg);
|
||||
void error(std::error_code EC, Twine Prefix);
|
||||
void error(std::error_code EC);
|
||||
template <typename T> void error(const ErrorOr<T> &V, Twine Prefix) {
|
||||
error(V.getError(), Prefix);
|
||||
}
|
||||
template <typename T> void error(const ErrorOr<T> &V) { error(V.getError()); }
|
||||
|
||||
class ArgParser {
|
||||
public:
|
||||
// Parses command line options.
|
||||
llvm::opt::InputArgList parse(ArrayRef<const char *> Args);
|
||||
};
|
||||
|
||||
class LinkerDriver {
|
||||
public:
|
||||
void link(ArrayRef<const char *> Args);
|
||||
|
||||
private:
|
||||
ArgParser Parser;
|
||||
|
||||
// Opens a file. Path has to be resolved already.
|
||||
MemoryBufferRef openFile(StringRef Path);
|
||||
|
||||
// Driver is the owner of all opened files.
|
||||
// InputFiles have MemoryBufferRefs to them.
|
||||
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
|
||||
};
|
||||
|
||||
// Create enum with OPT_xxx values for each option in Options.td
|
||||
enum {
|
||||
OPT_INVALID = 0,
|
||||
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
|
||||
#include "Options.inc"
|
||||
#undef OPTION
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
63
lld/ELF/DriverUtils.cpp
Normal file
63
lld/ELF/DriverUtils.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
//===- DriverUtils.cpp ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains utility functions for the driver. Because there
|
||||
// are so many small functions, we created this separate file to make
|
||||
// Driver.cpp less cluttered.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Driver.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
// Create OptTable
|
||||
|
||||
// Create prefix string literals used in Options.td
|
||||
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
|
||||
#include "Options.inc"
|
||||
#undef PREFIX
|
||||
|
||||
// Create table mapping all options defined in Options.td
|
||||
static const opt::OptTable::Info infoTable[] = {
|
||||
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
|
||||
{ \
|
||||
X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \
|
||||
OPT_##ALIAS, X6 \
|
||||
} \
|
||||
,
|
||||
#include "Options.inc"
|
||||
#undef OPTION
|
||||
};
|
||||
|
||||
class ELFOptTable : public opt::OptTable {
|
||||
public:
|
||||
ELFOptTable() : OptTable(infoTable, array_lengthof(infoTable)) {}
|
||||
};
|
||||
|
||||
// Parses a given list of options.
|
||||
opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
|
||||
// Make InputArgList from string vectors.
|
||||
ELFOptTable Table;
|
||||
unsigned MissingIndex;
|
||||
unsigned MissingCount;
|
||||
|
||||
opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
|
||||
if (MissingCount)
|
||||
error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
|
||||
"\", expected " + Twine(MissingCount) +
|
||||
(MissingCount == 1 ? " argument.\n" : " arguments"));
|
||||
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
|
||||
error(Twine("unknown argument: ") + Arg->getSpelling());
|
||||
return Args;
|
||||
}
|
78
lld/ELF/InputFiles.cpp
Normal file
78
lld/ELF/InputFiles.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
//===- InputFiles.cpp -----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "InputFiles.h"
|
||||
#include "Chunks.h"
|
||||
#include "Symbols.h"
|
||||
#include "Driver.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace llvm::ELF;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
|
||||
// Parse a memory buffer as a ELF file.
|
||||
std::error_code EC;
|
||||
ELFObj = llvm::make_unique<ELFFile<ELFT>>(MB.getBuffer(), EC);
|
||||
error(EC);
|
||||
|
||||
// Read section and symbol tables.
|
||||
initializeChunks();
|
||||
initializeSymbols();
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
|
||||
uint64_t Size = ELFObj->getNumSections();
|
||||
Chunks.reserve(Size);
|
||||
for (const Elf_Shdr &Sec : ELFObj->sections()) {
|
||||
if (Sec.sh_flags & SHF_ALLOC) {
|
||||
auto *C = new (Alloc) SectionChunk<ELFT>(this->getObj(), &Sec);
|
||||
Chunks.push_back(C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
|
||||
const Elf_Shdr *Symtab = ELFObj->getDotSymtabSec();
|
||||
ErrorOr<StringRef> StringTableOrErr =
|
||||
ELFObj->getStringTableForSymtab(*Symtab);
|
||||
error(StringTableOrErr.getError());
|
||||
StringRef StringTable = *StringTableOrErr;
|
||||
|
||||
Elf_Sym_Range Syms = ELFObj->symbols();
|
||||
Syms = Elf_Sym_Range(Syms.begin() + 1, Syms.end());
|
||||
auto NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
SymbolBodies.reserve(NumSymbols);
|
||||
for (const Elf_Sym &Sym : Syms) {
|
||||
if (SymbolBody *Body = createSymbolBody(StringTable, &Sym))
|
||||
SymbolBodies.push_back(Body);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
const Elf_Sym *Sym) {
|
||||
ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
|
||||
error(NameOrErr.getError());
|
||||
StringRef Name = *NameOrErr;
|
||||
if (Sym->isUndefined())
|
||||
return new (Alloc) Undefined(Name);
|
||||
return new (Alloc) DefinedRegular<ELFT>(Name);
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
template class elf2::ObjectFile<llvm::object::ELF32LE>;
|
||||
template class elf2::ObjectFile<llvm::object::ELF32BE>;
|
||||
template class elf2::ObjectFile<llvm::object::ELF64LE>;
|
||||
template class elf2::ObjectFile<llvm::object::ELF64BE>;
|
||||
}
|
||||
}
|
78
lld/ELF/InputFiles.h
Normal file
78
lld/ELF/InputFiles.h
Normal file
@ -0,0 +1,78 @@
|
||||
//===- InputFiles.h -------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_INPUT_FILES_H
|
||||
#define LLD_ELF_INPUT_FILES_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
class SymbolBody;
|
||||
class Chunk;
|
||||
|
||||
// The root class of input files.
|
||||
class InputFile {
|
||||
public:
|
||||
enum Kind { ObjectKind };
|
||||
Kind kind() const { return FileKind; }
|
||||
virtual ~InputFile() {}
|
||||
|
||||
// Returns symbols defined by this file.
|
||||
virtual ArrayRef<SymbolBody *> getSymbols() = 0;
|
||||
|
||||
// Reads a file (constructors don't do that).
|
||||
virtual void parse() = 0;
|
||||
|
||||
protected:
|
||||
explicit InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
|
||||
MemoryBufferRef MB;
|
||||
|
||||
private:
|
||||
const Kind FileKind;
|
||||
};
|
||||
|
||||
// .o file.
|
||||
template <class ELFT> class ObjectFile : public InputFile {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
|
||||
|
||||
public:
|
||||
explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
|
||||
static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
|
||||
void parse() override;
|
||||
ArrayRef<Chunk *> getChunks() { return Chunks; }
|
||||
ArrayRef<SymbolBody *> getSymbols() override { return SymbolBodies; }
|
||||
|
||||
// Returns the underying ELF file.
|
||||
llvm::object::ELFFile<ELFT> *getObj() { return ELFObj.get(); }
|
||||
|
||||
private:
|
||||
void initializeChunks();
|
||||
void initializeSymbols();
|
||||
|
||||
SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
|
||||
|
||||
std::unique_ptr<llvm::object::ELFFile<ELFT>> ELFObj;
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
|
||||
// List of all chunks defined by this file. This includes both section
|
||||
// chunks and non-section chunks for common symbols.
|
||||
std::vector<Chunk *> Chunks;
|
||||
|
||||
// List of all symbols referenced or defined by this file.
|
||||
std::vector<SymbolBody *> SymbolBodies;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
8
lld/ELF/Options.td
Normal file
8
lld/ELF/Options.td
Normal file
@ -0,0 +1,8 @@
|
||||
include "llvm/Option/OptParser.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Utility Functions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def output : Separate<["-"], "o">, MetaVarName<"<path>">,
|
||||
HelpText<"Path to file to write output">;
|
12
lld/ELF/README.md
Normal file
12
lld/ELF/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
The New ELF Linker
|
||||
==================
|
||||
This directory contains a port of the new PE/COFF linker for ELF.
|
||||
|
||||
Overall Design
|
||||
--------------
|
||||
See COFF/README.md for details on the design.
|
||||
|
||||
Capabilities
|
||||
------------
|
||||
This linker can currently generate a valid ELF file that can be run on linux
|
||||
from a single input file.
|
87
lld/ELF/SymbolTable.cpp
Normal file
87
lld/ELF/SymbolTable.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
//===- SymbolTable.cpp ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SymbolTable.h"
|
||||
#include "Driver.h"
|
||||
#include "Symbols.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
template <class ELFT> SymbolTable<ELFT>::SymbolTable() {
|
||||
resolve(new (Alloc) Undefined("_start"));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
|
||||
File->parse();
|
||||
InputFile *FileP = File.release();
|
||||
auto *P = cast<ObjectFile<ELFT>>(FileP);
|
||||
addObject(P);
|
||||
return;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void SymbolTable<ELFT>::addObject(ObjectFile<ELFT> *File) {
|
||||
ObjectFiles.emplace_back(File);
|
||||
for (SymbolBody *Body : File->getSymbols())
|
||||
if (Body->isExternal())
|
||||
resolve(Body);
|
||||
}
|
||||
|
||||
template <class ELFT> void SymbolTable<ELFT>::reportRemainingUndefines() {
|
||||
for (auto &I : Symtab) {
|
||||
Symbol *Sym = I.second;
|
||||
if (auto *Undef = dyn_cast<Undefined>(Sym->Body))
|
||||
error(Twine("undefined symbol: ") + Undef->getName());
|
||||
}
|
||||
}
|
||||
|
||||
// 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<ELFT>::resolve(SymbolBody *New) {
|
||||
// Find an existing Symbol or create and insert a new one.
|
||||
StringRef Name = New->getName();
|
||||
Symbol *&Sym = Symtab[Name];
|
||||
if (!Sym) {
|
||||
Sym = new (Alloc) Symbol(New);
|
||||
New->setBackref(Sym);
|
||||
return;
|
||||
}
|
||||
New->setBackref(Sym);
|
||||
|
||||
// compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
|
||||
// equivalent (conflicting), or more preferable, respectively.
|
||||
SymbolBody *Existing = Sym->Body;
|
||||
int comp = Existing->compare(New);
|
||||
if (comp < 0)
|
||||
Sym->Body = New;
|
||||
if (comp == 0)
|
||||
error(Twine("duplicate symbol: ") + Name);
|
||||
}
|
||||
|
||||
template <class ELFT> std::vector<Chunk *> SymbolTable<ELFT>::getChunks() {
|
||||
std::vector<Chunk *> Res;
|
||||
for (std::unique_ptr<ObjectFile<ELFT>> &File : ObjectFiles) {
|
||||
ArrayRef<Chunk *> V = File->getChunks();
|
||||
Res.insert(Res.end(), V.begin(), V.end());
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
template class SymbolTable<object::ELF32LE>;
|
||||
template class SymbolTable<object::ELF32BE>;
|
||||
template class SymbolTable<object::ELF64LE>;
|
||||
template class SymbolTable<object::ELF64BE>;
|
||||
}
|
||||
}
|
58
lld/ELF/SymbolTable.h
Normal file
58
lld/ELF/SymbolTable.h
Normal file
@ -0,0 +1,58 @@
|
||||
//===- SymbolTable.h ------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_SYMBOL_TABLE_H
|
||||
#define LLD_ELF_SYMBOL_TABLE_H
|
||||
|
||||
#include "InputFiles.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
class Defined;
|
||||
struct Symbol;
|
||||
|
||||
// SymbolTable is a bucket of all known symbols, including defined,
|
||||
// undefined, or lazy symbols (the last one is symbols in archive
|
||||
// files whose archive members are not yet loaded).
|
||||
//
|
||||
// We put all symbols of all files to a SymbolTable, and the
|
||||
// SymbolTable selects the "best" symbols if there are name
|
||||
// conflicts. For example, obviously, a defined symbol is better than
|
||||
// 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().
|
||||
template <class ELFT> class SymbolTable {
|
||||
public:
|
||||
SymbolTable();
|
||||
|
||||
void addFile(std::unique_ptr<InputFile> File);
|
||||
|
||||
// Print an error message on undefined symbols.
|
||||
void reportRemainingUndefines();
|
||||
|
||||
// Returns a list of chunks of selected symbols.
|
||||
std::vector<Chunk *> getChunks();
|
||||
|
||||
// The writer needs to infer the machine type from the object files.
|
||||
std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
|
||||
|
||||
private:
|
||||
void addObject(ObjectFile<ELFT> *File);
|
||||
|
||||
void resolve(SymbolBody *Body);
|
||||
|
||||
std::unordered_map<StringRef, Symbol *> Symtab;
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
57
lld/ELF/Symbols.cpp
Normal file
57
lld/ELF/Symbols.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//===- Symbols.cpp --------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Symbols.h"
|
||||
#include "Chunks.h"
|
||||
|
||||
using namespace llvm::object;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
template <class ELFT>
|
||||
DefinedRegular<ELFT>::DefinedRegular(StringRef Name)
|
||||
: Defined(DefinedRegularKind), Name(Name) {}
|
||||
|
||||
// Returns 1, 0 or -1 if this symbol should take precedence
|
||||
// over the Other, tie or lose, respectively.
|
||||
template <class ELFT> int DefinedRegular<ELFT>::compare(SymbolBody *Other) {
|
||||
if (Other->kind() < kind())
|
||||
return -Other->compare(this);
|
||||
auto *R = dyn_cast<DefinedRegular>(Other);
|
||||
if (!R)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Defined::compare(SymbolBody *Other) {
|
||||
if (Other->kind() < kind())
|
||||
return -Other->compare(this);
|
||||
if (isa<Defined>(Other))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Undefined::compare(SymbolBody *Other) {
|
||||
if (Other->kind() < kind())
|
||||
return -Other->compare(this);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class ELFT> StringRef DefinedRegular<ELFT>::getName() { return Name; }
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
template class DefinedRegular<llvm::object::ELF32LE>;
|
||||
template class DefinedRegular<llvm::object::ELF32BE>;
|
||||
template class DefinedRegular<llvm::object::ELF64LE>;
|
||||
template class DefinedRegular<llvm::object::ELF64BE>;
|
||||
}
|
||||
}
|
123
lld/ELF/Symbols.h
Normal file
123
lld/ELF/Symbols.h
Normal file
@ -0,0 +1,123 @@
|
||||
//===- Symbols.h ----------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_SYMBOLS_H
|
||||
#define LLD_ELF_SYMBOLS_H
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
||||
using llvm::object::ELFFile;
|
||||
|
||||
class Chunk;
|
||||
class InputFile;
|
||||
class SymbolBody;
|
||||
|
||||
// A real symbol object, SymbolBody, is usually accessed indirectly
|
||||
// through a Symbol. There's always one Symbol for each symbol name.
|
||||
// The resolver updates SymbolBody pointers as it resolves symbols.
|
||||
struct Symbol {
|
||||
explicit Symbol(SymbolBody *P) : Body(P) {}
|
||||
SymbolBody *Body;
|
||||
};
|
||||
|
||||
// The base class for real symbol classes.
|
||||
class SymbolBody {
|
||||
public:
|
||||
enum Kind {
|
||||
DefinedFirst,
|
||||
DefinedRegularKind,
|
||||
DefinedLast,
|
||||
UndefinedKind,
|
||||
};
|
||||
|
||||
Kind kind() const { return SymbolKind; }
|
||||
virtual ~SymbolBody() {}
|
||||
|
||||
// Returns true if this is an external symbol.
|
||||
virtual bool isExternal() { return true; }
|
||||
|
||||
// Returns the symbol name.
|
||||
virtual StringRef getName() = 0;
|
||||
|
||||
// A SymbolBody has a backreference to a Symbol. Originally they are
|
||||
// doubly-linked. A backreference will never change. But the pointer
|
||||
// in the Symbol may be mutated by the resolver. If you have a
|
||||
// pointer P to a SymbolBody and are not sure whether the resolver
|
||||
// has chosen the object among other objects having the same name,
|
||||
// you can access P->Backref->Body to get the resolver's result.
|
||||
void setBackref(Symbol *P) { Backref = P; }
|
||||
SymbolBody *getReplacement() { return Backref ? Backref->Body : this; }
|
||||
|
||||
// Decides which symbol should "win" in the symbol table, this or
|
||||
// the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
|
||||
// they are duplicate (conflicting) symbols.
|
||||
virtual int compare(SymbolBody *Other) = 0;
|
||||
|
||||
protected:
|
||||
SymbolBody(Kind K) : SymbolKind(K) {}
|
||||
|
||||
private:
|
||||
const Kind SymbolKind;
|
||||
Symbol *Backref = nullptr;
|
||||
};
|
||||
|
||||
// The base class for any defined symbols, including absolute symbols,
|
||||
// etc.
|
||||
class Defined : public SymbolBody {
|
||||
public:
|
||||
Defined(Kind K) : SymbolBody(K) {}
|
||||
|
||||
static bool classof(const SymbolBody *S) {
|
||||
Kind K = S->kind();
|
||||
return DefinedFirst <= K && K <= DefinedLast;
|
||||
}
|
||||
|
||||
int compare(SymbolBody *Other) override;
|
||||
};
|
||||
|
||||
// Regular defined symbols read from object file symbol tables.
|
||||
template <class ELFT> class DefinedRegular : public Defined {
|
||||
public:
|
||||
DefinedRegular(StringRef Name);
|
||||
|
||||
static bool classof(const SymbolBody *S) {
|
||||
return S->kind() == DefinedRegularKind;
|
||||
}
|
||||
|
||||
StringRef getName() override;
|
||||
int compare(SymbolBody *Other) override;
|
||||
|
||||
private:
|
||||
StringRef Name;
|
||||
};
|
||||
|
||||
// Undefined symbols.
|
||||
class Undefined : public SymbolBody {
|
||||
public:
|
||||
explicit Undefined(StringRef N) : SymbolBody(UndefinedKind), Name(N) {}
|
||||
|
||||
static bool classof(const SymbolBody *S) {
|
||||
return S->kind() == UndefinedKind;
|
||||
}
|
||||
StringRef getName() override { return Name; }
|
||||
|
||||
int compare(SymbolBody *Other) override;
|
||||
|
||||
private:
|
||||
StringRef Name;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
161
lld/ELF/Writer.cpp
Normal file
161
lld/ELF/Writer.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
//===- Writer.cpp ---------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Writer.h"
|
||||
#include "Chunks.h"
|
||||
#include "Driver.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
using namespace llvm::object;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
static const int PageSize = 4096;
|
||||
|
||||
template <class ELFT> Writer<ELFT>::Writer(SymbolTable<ELFT> *T) : Symtab(T) {}
|
||||
template <class ELFT> Writer<ELFT>::~Writer() {}
|
||||
|
||||
// The main function of the writer.
|
||||
template <class ELFT> void Writer<ELFT>::write(StringRef OutputPath) {
|
||||
createSections();
|
||||
assignAddresses();
|
||||
openFile(OutputPath);
|
||||
writeHeader();
|
||||
writeSections();
|
||||
error(Buffer->commit());
|
||||
}
|
||||
|
||||
void OutputSection::setVA(uint64_t VA) {
|
||||
Header.sh_addr = VA;
|
||||
for (Chunk *C : Chunks)
|
||||
C->setVA(C->getVA() + VA);
|
||||
}
|
||||
|
||||
void OutputSection::setFileOffset(uint64_t Off) {
|
||||
if (Header.sh_size == 0)
|
||||
return;
|
||||
Header.sh_offset = Off;
|
||||
for (Chunk *C : Chunks)
|
||||
C->setFileOff(C->getFileOff() + Off);
|
||||
}
|
||||
|
||||
void OutputSection::addChunk(Chunk *C) {
|
||||
Chunks.push_back(C);
|
||||
C->setOutputSection(this);
|
||||
uint64_t Off = Header.sh_size;
|
||||
Off = RoundUpToAlignment(Off, C->getAlign());
|
||||
C->setVA(Off);
|
||||
C->setFileOff(Off);
|
||||
Off += C->getSize();
|
||||
Header.sh_size = Off;
|
||||
}
|
||||
|
||||
static int compare(const Chunk *A, const Chunk *B) {
|
||||
return A->getSectionName() < B->getSectionName();
|
||||
}
|
||||
|
||||
// Create output section objects and add them to OutputSections.
|
||||
template <class ELFT> void Writer<ELFT>::createSections() {
|
||||
std::vector<Chunk *> Chunks = Symtab->getChunks();
|
||||
if (Chunks.empty())
|
||||
return;
|
||||
std::sort(Chunks.begin(), Chunks.end(), compare);
|
||||
|
||||
Chunk *Prev = nullptr;
|
||||
OutputSection *Sec = nullptr;
|
||||
for (Chunk *C : Chunks) {
|
||||
if (Prev == nullptr || Prev->getSectionName() != C->getSectionName()) {
|
||||
Sec = new (CAlloc.Allocate()) OutputSection(C->getSectionName());
|
||||
OutputSections.push_back(Sec);
|
||||
Prev = C;
|
||||
}
|
||||
Sec->addChunk(C);
|
||||
}
|
||||
}
|
||||
|
||||
// Visits all sections to assign incremental, non-overlapping RVAs and
|
||||
// file offsets.
|
||||
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||
SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>) +
|
||||
sizeof(Elf_Shdr_Impl<ELFT>) *
|
||||
OutputSections.size(),
|
||||
PageSize);
|
||||
uint64_t VA = 0x1000; // The first page is kept unmapped.
|
||||
uint64_t FileOff = SizeOfHeaders;
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
Sec->setVA(VA);
|
||||
Sec->setFileOffset(FileOff);
|
||||
VA += RoundUpToAlignment(Sec->getSize(), PageSize);
|
||||
FileOff += RoundUpToAlignment(Sec->getSize(), 8);
|
||||
}
|
||||
SizeOfImage = SizeOfHeaders + RoundUpToAlignment(VA - 0x1000, PageSize);
|
||||
FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||
uint8_t *Buf = Buffer->getBufferStart();
|
||||
auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
|
||||
EHdr->e_ident[EI_MAG0] = 0x7F;
|
||||
EHdr->e_ident[EI_MAG1] = 0x45;
|
||||
EHdr->e_ident[EI_MAG2] = 0x4C;
|
||||
EHdr->e_ident[EI_MAG3] = 0x46;
|
||||
EHdr->e_ident[EI_CLASS] = ELFCLASS64;
|
||||
EHdr->e_ident[EI_DATA] = ELFDATA2LSB;
|
||||
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
|
||||
EHdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
|
||||
|
||||
EHdr->e_type = ET_EXEC;
|
||||
EHdr->e_machine = EM_X86_64;
|
||||
EHdr->e_version = EV_CURRENT;
|
||||
EHdr->e_entry = 0x401000;
|
||||
EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
|
||||
EHdr->e_shoff = 0;
|
||||
EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
|
||||
EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
|
||||
EHdr->e_phnum = 1;
|
||||
EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
|
||||
EHdr->e_shnum = 0;
|
||||
EHdr->e_shstrndx = 0;
|
||||
|
||||
auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
|
||||
PHdrs->p_type = PT_LOAD;
|
||||
PHdrs->p_flags = PF_R | PF_X;
|
||||
PHdrs->p_offset = 0x0000;
|
||||
PHdrs->p_vaddr = 0x400000;
|
||||
PHdrs->p_paddr = PHdrs->p_vaddr;
|
||||
PHdrs->p_filesz = FileSize;
|
||||
PHdrs->p_memsz = FileSize;
|
||||
PHdrs->p_align = 0x4000;
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
|
||||
std::error_code EC = FileOutputBuffer::create(Path, FileSize, Buffer,
|
||||
FileOutputBuffer::F_executable);
|
||||
error(EC, Twine("failed to open ") + Path);
|
||||
}
|
||||
|
||||
// Write section contents to a mmap'ed file.
|
||||
template <class ELFT> void Writer<ELFT>::writeSections() {
|
||||
uint8_t *Buf = Buffer->getBufferStart();
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
for (Chunk *C : Sec->getChunks())
|
||||
C->writeTo(Buf);
|
||||
}
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
template class Writer<ELF32LE>;
|
||||
template class Writer<ELF32BE>;
|
||||
template class Writer<ELF64LE>;
|
||||
template class Writer<ELF64BE>;
|
||||
}
|
||||
}
|
74
lld/ELF/Writer.h
Normal file
74
lld/ELF/Writer.h
Normal file
@ -0,0 +1,74 @@
|
||||
//===- Writer.h -----------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_WRITER_H
|
||||
#define LLD_ELF_WRITER_H
|
||||
|
||||
#include "SymbolTable.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
// OutputSection represents a section in an output file. It's a
|
||||
// container of chunks. OutputSection and Chunk are 1:N relationship.
|
||||
// Chunks cannot belong to more than one OutputSections. The writer
|
||||
// creates multiple OutputSections and assign them unique,
|
||||
// non-overlapping file offsets and VAs.
|
||||
class OutputSection {
|
||||
public:
|
||||
OutputSection(StringRef Name) : Name(Name), Header({}) {}
|
||||
void setVA(uint64_t);
|
||||
void setFileOffset(uint64_t);
|
||||
void addChunk(Chunk *C);
|
||||
std::vector<Chunk *> &getChunks() { return Chunks; }
|
||||
|
||||
// Returns the size of the section in the output file.
|
||||
uint64_t getSize() { return Header.sh_size; }
|
||||
|
||||
// Set offset into the string table storing this section name.
|
||||
// Used only when the name is longer than 8 bytes.
|
||||
void setStringTableOff(uint32_t V) { StringTableOff = V; }
|
||||
|
||||
private:
|
||||
StringRef Name;
|
||||
llvm::ELF::Elf64_Shdr Header;
|
||||
uint32_t StringTableOff = 0;
|
||||
std::vector<Chunk *> Chunks;
|
||||
};
|
||||
|
||||
// The writer writes a SymbolTable result to a file.
|
||||
template <class ELFT> class Writer {
|
||||
public:
|
||||
explicit Writer(SymbolTable<ELFT> *T);
|
||||
~Writer();
|
||||
void write(StringRef Path);
|
||||
|
||||
private:
|
||||
void createSections();
|
||||
void assignAddresses();
|
||||
void openFile(StringRef OutputPath);
|
||||
void writeHeader();
|
||||
void writeSections();
|
||||
|
||||
SymbolTable<ELFT> *Symtab;
|
||||
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
|
||||
llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
|
||||
std::vector<OutputSection *> OutputSections;
|
||||
|
||||
uint64_t FileSize;
|
||||
uint64_t SizeOfImage;
|
||||
uint64_t SizeOfHeaders;
|
||||
|
||||
std::vector<std::unique_ptr<Chunk>> Chunks;
|
||||
};
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
@ -146,6 +146,10 @@ namespace coff {
|
||||
bool link(llvm::ArrayRef<const char *> args);
|
||||
}
|
||||
|
||||
namespace elf2 {
|
||||
void link(llvm::ArrayRef<const char *> args);
|
||||
}
|
||||
|
||||
/// Driver for lld unit tests
|
||||
class CoreDriver : public Driver {
|
||||
public:
|
||||
|
@ -24,6 +24,7 @@ add_llvm_library(lldDriver
|
||||
lldCOFF
|
||||
lldPECOFF
|
||||
lldELF
|
||||
lldELF2
|
||||
lldAArch64ELFTarget
|
||||
lldARMELFTarget
|
||||
lldHexagonELFTarget
|
||||
|
@ -69,6 +69,7 @@ public:
|
||||
enum class Flavor {
|
||||
invalid,
|
||||
gnu_ld, // -flavor gnu
|
||||
gnu_ld2, // -flavor gnu2
|
||||
win_link, // -flavor link
|
||||
win_link2, // -flavor link2
|
||||
darwin_ld, // -flavor darwin
|
||||
@ -85,6 +86,7 @@ struct ProgramNameParts {
|
||||
static Flavor strToFlavor(StringRef str) {
|
||||
return llvm::StringSwitch<Flavor>(str)
|
||||
.Case("gnu", Flavor::gnu_ld)
|
||||
.Case("gnu2", Flavor::gnu_ld2)
|
||||
.Case("link", Flavor::win_link)
|
||||
.Case("lld-link", Flavor::win_link)
|
||||
.Case("link2", Flavor::win_link2)
|
||||
@ -202,6 +204,9 @@ bool UniversalDriver::link(llvm::MutableArrayRef<const char *> args,
|
||||
switch (flavor) {
|
||||
case Flavor::gnu_ld:
|
||||
return GnuLdDriver::linkELF(args, diagnostics);
|
||||
case Flavor::gnu_ld2:
|
||||
elf2::link(args);
|
||||
return true;
|
||||
case Flavor::darwin_ld:
|
||||
return DarwinLdDriver::linkMachO(args, diagnostics);
|
||||
case Flavor::win_link:
|
||||
|
78
lld/test/elf2/basic.test
Normal file
78
lld/test/elf2/basic.test
Normal file
@ -0,0 +1,78 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
# RUN: lld -flavor gnu2 %t -o %t2
|
||||
# RUN: llvm-readobj -file-headers -program-headers %t2 | FileCheck %s
|
||||
# REQUIRES: x86
|
||||
|
||||
# exits with return code 42 on linux
|
||||
.globl _start;
|
||||
_start:
|
||||
mov $60, %rax
|
||||
mov $42, %rdi
|
||||
syscall
|
||||
|
||||
# CHECK: ElfHeader {
|
||||
# CHECK-NEXT: Ident {
|
||||
# CHECK-NEXT: Magic: (7F 45 4C 46)
|
||||
# CHECK-NEXT: Class: 64-bit (0x2)
|
||||
# CHECK-NEXT: DataEncoding: LittleEndian (0x1)
|
||||
# CHECK-NEXT: FileVersion: 1
|
||||
# CHECK-NEXT: OS/ABI: GNU/Linux (0x3)
|
||||
# CHECK-NEXT: ABIVersion: 0
|
||||
# CHECK-NEXT: Unused: (00 00 00 00 00 00 00)
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Type: Executable (0x2)
|
||||
# CHECK-NEXT: Machine: EM_X86_64 (0x3E)
|
||||
# CHECK-NEXT: Version: 1
|
||||
# CHECK-NEXT: Entry: 0x401000
|
||||
# CHECK-NEXT: ProgramHeaderOffset: 0x40
|
||||
# CHECK-NEXT: SectionHeaderOffset: 0x0
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: HeaderSize: 64
|
||||
# CHECK-NEXT: ProgramHeaderEntrySize: 56
|
||||
# CHECK-NEXT: ProgramHeaderCount: 1
|
||||
# CHECK-NEXT: SectionHeaderEntrySize: 64
|
||||
# CHECK-NEXT: SectionHeaderCount: 0
|
||||
# CHECK-NEXT: StringTableSectionIndex: 0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ProgramHeaders [
|
||||
# CHECK-NEXT: ProgramHeader {
|
||||
# CHECK-NEXT: Type: PT_LOAD (0x1)
|
||||
# CHECK-NEXT: Offset: 0x0
|
||||
# CHECK-NEXT: VirtualAddress: 0x400000
|
||||
# CHECK-NEXT: PhysicalAddress: 0x400000
|
||||
# CHECK-NEXT: FileSize: 4112
|
||||
# CHECK-NEXT: MemSize: 4112
|
||||
# CHECK-NEXT: Flags [ (0x5)
|
||||
# CHECK-NEXT: PF_R (0x4)
|
||||
# CHECK-NEXT: PF_X (0x1)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Alignment: 16384
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
# RUN: not lld -flavor gnu2 %t 2>&1 | FileCheck --check-prefix=NO_O %s
|
||||
# NO_O: -o must be specified.
|
||||
|
||||
# RUN: not lld -flavor gnu2 %t.foo -o %t2 2>&1 | \
|
||||
# RUN: FileCheck --check-prefix=MISSING %s
|
||||
# MISSING: cannot open {{.*}}.foo: {{[Nn]}}o such file or directory
|
||||
|
||||
# RUN: not lld -flavor gnu2 -o %t2 2>&1 | \
|
||||
# RUN: FileCheck --check-prefix=NO_INPUT %s
|
||||
# NO_INPUT: no input files.
|
||||
|
||||
# RUN: mkdir -p %t.dir
|
||||
# RUN: not lld -flavor gnu2 %t.dir -o %t2 2>&1 | \
|
||||
# RUN: FileCheck --check-prefix=CANNOT_OPEN %s
|
||||
# CANNOT_OPEN: cannot open {{.*}}.dir: {{[Ii]}}s a directory
|
||||
|
||||
# RUN: not lld -flavor gnu2 %t -o 2>&1 | FileCheck --check-prefix=NO_O_VAL %s
|
||||
# NO_O_VAL: missing arg value for "-o", expected 1 argument.
|
||||
|
||||
# RUN: not lld -flavor gnu2 --foo 2>&1 | FileCheck --check-prefix=UNKNOWN %s
|
||||
# UNKNOWN: unknown argument: --foo
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
# RUN: not lld -flavor gnu2 %t %t -o %t2 2>&1 | FileCheck --check-prefix=DUP %s
|
||||
# DUP: duplicate symbol: _start
|
8
lld/test/elf2/undef.test
Normal file
8
lld/test/elf2/undef.test
Normal file
@ -0,0 +1,8 @@
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
# RUN: not lld -flavor gnu2 %t -o %t2 2>&1 | FileCheck %s
|
||||
# CHECK: undefined symbol: foo
|
||||
# REQUIRES: x86
|
||||
|
||||
.globl _start;
|
||||
_start:
|
||||
call foo
|
Loading…
x
Reference in New Issue
Block a user