Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ELF2] Add a new ELF linker based on the new PE/COFF linker.
Differential Revision: http://reviews.llvm.org/D11188 llvm-svn: 243161
- Loading branch information
Showing
23 changed files
with
1,255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,3 +97,4 @@ endif() | |
|
||
add_subdirectory(docs) | ||
add_subdirectory(COFF) | ||
add_subdirectory(ELF) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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>; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.