| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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>; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| include "llvm/Option/OptParser.td" | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| /// Utility Functions | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def output : Separate<["-"], "o">, MetaVarName<"<path>">, | ||
| HelpText<"Path to file to write output">; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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>; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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>; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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>; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |