[llvm-commits] [lld] patch for ELF Writer to get it to 'Hello world'
Shankar Easwaran
shankare at codeaurora.org
Mon Dec 17 07:15:21 PST 2012
Hi,
Attached is a patch to get the linker for Hexagon to get to 'Hello world'.
The changes are :-
1) Adds a ELF Layout class to WriterELF, becomes much easier to control
section ordering
2) Adds Section/Segment semantics to the ELF linker
3) Easier to add Linker script support in the future.
Attached is the patch ? Let me know if its ok to commit ?
Thanks
Shankar Easwaran
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation
-------------- next part --------------
Index: include/lld/ReaderWriter/WriterELF.h
===================================================================
--- include/lld/ReaderWriter/WriterELF.h (revision 169997)
+++ include/lld/ReaderWriter/WriterELF.h (working copy)
@@ -48,7 +48,7 @@
const uint16_t Type,
const uint16_t Machine,
uint64_t pointerWidth = 4,
- uint64_t baseAddress = 0x400000,
+ uint64_t baseAddress = 0,
uint64_t pageSize = 0x1000)
: _is64Bit(Is64Bit)
, _endianness(endian)
Index: include/lld/Core/DefinedAtom.h
===================================================================
--- include/lld/Core/DefinedAtom.h (revision 169997)
+++ include/lld/Core/DefinedAtom.h (working copy)
@@ -97,6 +97,7 @@
enum Merge {
mergeNo, // Another atom with same name is error
+ mergeByContent, // Merge sections using content
mergeAsTentative, // Is ANSI C tentative defintion, can be coalesced
mergeAsWeak, // is C++ inline definition that was not inlined,
// but address was not taken, so atom can be hidden
@@ -147,8 +148,9 @@
enum ContentPermissions {
perm___ = 0, // mapped as unaccessible
permR__ = 8, // mapped read-only
- permR_X = 8 + 2, // mapped readable and executable
- permRW_ = 8 + 4, // mapped readable and writable
+ permRW_ = 8 + 2, // mapped readable and writable
+ permR_X = 8 + 4, // mapped readable and executable
+ permRWX = 8 + 4 + 2, // mapped readable and writable and executable
permRW_L = 8 + 4 + 1, // initially mapped r/w, then made read-only
// loader writable
};
Index: lib/ReaderWriter/ELF/ELFAtoms.h
===================================================================
--- lib/ReaderWriter/ELF/ELFAtoms.h (revision 0)
+++ lib/ReaderWriter/ELF/ELFAtoms.h (revision 0)
@@ -0,0 +1,472 @@
+#ifndef LLD_ELFATOMS_H_
+#define LLD_ELFATOMS_H_
+
+#include "lld/Core/LLVM.h"
+#include <memory>
+#include <vector>
+
+namespace lld {
+/// \brief Relocation References: Defined Atoms may contain
+/// references that will need to be patched before
+/// the executable is written.
+template <llvm::support::endianness target_endianness, bool is64Bits>
+class ELFReference final : public Reference {
+
+ typedef llvm::object::Elf_Rel_Impl
+ <target_endianness, is64Bits, false> Elf_Rel;
+ typedef llvm::object::Elf_Rel_Impl
+ <target_endianness, is64Bits, true> Elf_Rela;
+public:
+
+ ELFReference(const Elf_Rela *rela, uint64_t offset, const Atom *target)
+ : _target(target)
+ , _targetSymbolIndex(rela->getSymbol())
+ , _offsetInAtom(offset)
+ , _addend(rela->r_addend)
+ , _kind(rela->getType()) {}
+
+ ELFReference(const Elf_Rel *rel, uint64_t offset, const Atom *target)
+ : _target(target)
+ , _targetSymbolIndex(rel->getSymbol())
+ , _offsetInAtom(offset)
+ , _addend(0)
+ , _kind(rel->getType()) {}
+
+
+ virtual uint64_t offsetInAtom() const {
+ return _offsetInAtom;
+ }
+
+ virtual Kind kind() const {
+ return _kind;
+ }
+
+ virtual void setKind(Kind kind) {
+ _kind = kind;
+ }
+
+ virtual const Atom *target() const {
+ return _target;
+ }
+
+/// \brief targetSymbolIndex: This is the symbol table index that contains
+/// the target reference.
+ uint64_t targetSymbolIndex() const {
+ return _targetSymbolIndex;
+ }
+
+ virtual Addend addend() const {
+ return _addend;
+ }
+
+ virtual void setAddend(Addend A) {
+ _addend = A;
+ }
+
+ virtual void setTarget(const Atom *newAtom) {
+ _target = newAtom;
+ }
+private:
+ const Atom *_target;
+ uint64_t _targetSymbolIndex;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+ Kind _kind;
+};
+
+
+/// \brief ELFAbsoluteAtom: These atoms store symbols that are fixed to a
+/// particular address. This atom has no content its address will be used by
+/// the writer to fixup references that point to it.
+template<llvm::support::endianness target_endianness, bool is64Bits>
+class ELFAbsoluteAtom final : public AbsoluteAtom {
+
+ typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
+
+public:
+ ELFAbsoluteAtom(const File &file,
+ llvm::StringRef name,
+ const Elf_Sym *symbol,
+ uint64_t value)
+ : _owningFile(file)
+ , _name(name)
+ , _symbol(symbol)
+ , _value(value)
+ {}
+
+ virtual const class File &file() const {
+ return _owningFile;
+ }
+
+ virtual Scope scope() const {
+ if (!_symbol)
+ return scopeGlobal;
+ if (_symbol->st_other == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
+ return scopeTranslationUnit;
+ else
+ return scopeGlobal;
+ }
+
+ virtual llvm::StringRef name() const {
+ return _name;
+ }
+
+ virtual uint64_t value() const {
+ return _value;
+ }
+
+private:
+ const File &_owningFile;
+ llvm::StringRef _name;
+ const Elf_Sym *_symbol;
+ uint64_t _value;
+};
+
+
+/// \brief ELFUndefinedAtom: These atoms store undefined symbols and are
+/// place holders that will be replaced by defined atoms later in the
+/// linking process.
+template<llvm::support::endianness target_endianness, bool is64Bits>
+class ELFUndefinedAtom final: public UndefinedAtom {
+
+ typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
+
+public:
+ ELFUndefinedAtom(const File &file,
+ llvm::StringRef name,
+ const Elf_Sym *symbol)
+ : _owningFile(file)
+ , _name(name)
+ , _symbol(symbol)
+ {}
+
+ virtual const class File &file() const {
+ return _owningFile;
+ }
+
+ virtual llvm::StringRef name() const {
+ return _name;
+ }
+
+ // FIXME What distinguishes a symbol in ELF that can help
+ // decide if the symbol is undefined only during build and not
+ // runtime? This will make us choose canBeNullAtBuildtime and
+ // canBeNullAtRuntime
+ //
+ virtual CanBeNull canBeNull() const {
+
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return CanBeNull::canBeNullAtBuildtime;
+ else
+ return CanBeNull::canBeNullNever;
+ }
+
+private:
+ const File &_owningFile;
+ llvm::StringRef _name;
+ const Elf_Sym *_symbol;
+};
+
+
+/// \brief ELFDefinedAtom: This atom stores defined symbols and will contain
+/// either data or code.
+template<llvm::support::endianness target_endianness, bool is64Bits>
+class ELFDefinedAtom final: public DefinedAtom {
+
+ typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
+ typedef llvm::object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
+
+public:
+ ELFDefinedAtom(const File &file,
+ llvm::StringRef symbolName,
+ llvm::StringRef sectionName,
+ const Elf_Sym *symbol,
+ const Elf_Shdr *section,
+ llvm::ArrayRef<uint8_t> contentData,
+ unsigned int referenceStart,
+ unsigned int referenceEnd,
+ std::vector<ELFReference
+ <target_endianness, is64Bits> *> &referenceList)
+
+ : _owningFile(file)
+ , _symbolName(symbolName)
+ , _sectionName(sectionName)
+ , _symbol(symbol)
+ , _section(section)
+ , _contentData(contentData)
+ , _referenceStartIndex(referenceStart)
+ , _referenceEndIndex(referenceEnd)
+ , _referenceList(referenceList) {
+ static uint64_t orderNumber = 0;
+ _ordinal = ++orderNumber;
+ }
+
+ virtual const class File &file() const {
+ return _owningFile;
+ }
+
+ virtual llvm::StringRef name() const {
+ return _symbolName;
+ }
+
+ virtual uint64_t ordinal() const {
+ return _ordinal;
+ }
+
+ virtual uint64_t size() const {
+
+ // Common symbols are not allocated in object files,
+ // so use st_size to tell how many bytes are required.
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return (uint64_t)_symbol->st_size;
+
+ return _contentData.size();
+
+ }
+
+ virtual Scope scope() const {
+ if (_symbol->st_other == llvm::ELF::STV_HIDDEN)
+ return scopeLinkageUnit;
+ else if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
+ return scopeGlobal;
+ else
+ return scopeTranslationUnit;
+ }
+
+ // FIXME Need to revisit this in future.
+
+ virtual Interposable interposable() const {
+ return interposeNo;
+ }
+
+ // FIXME What ways can we determine this in ELF?
+
+ virtual Merge merge() const {
+
+ if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
+ return mergeAsWeak;
+
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ return mergeAsTentative;
+
+ return mergeNo;
+ }
+
+ virtual ContentType contentType() const {
+
+ ContentType ret = typeUnknown;
+ uint64_t flags = _section->sh_flags;
+
+ switch (_section->sh_type) {
+ case llvm::ELF::SHT_PROGBITS:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ switch (flags) {
+ case llvm::ELF::SHF_EXECINSTR:
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ ret = typeCode;
+ break;
+ case llvm::ELF::SHF_WRITE:
+ ret = typeData;
+ break;
+ case llvm::ELF::SHF_MERGE:
+ case llvm::ELF::SHF_STRINGS:
+ ret = typeConstant;
+ break;
+ default:
+ ret = typeCode;
+ break;
+ }
+ break;
+ case llvm::ELF::SHT_NOBITS:
+ ret = typeZeroFill;
+ break;
+ case llvm::ELF::SHT_NULL:
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+ ret = typeZeroFill;
+ break;
+ }
+
+ return ret;
+ }
+
+ virtual Alignment alignment() const {
+ // Unallocated common symbols specify their alignment
+ // constraints in st_value.
+ if ((_symbol->getType() == llvm::ELF::STT_COMMON)
+ || _symbol->st_shndx == llvm::ELF::SHN_COMMON) {
+ return Alignment(llvm::Log2_64(_symbol->st_value));
+ }
+ return Alignment(llvm::Log2_64(_section->sh_addralign),
+ _symbol->st_value % _section->sh_addralign);
+ }
+
+ // Do we have a choice for ELF? All symbols
+ // live in explicit sections.
+ virtual SectionChoice sectionChoice() const {
+ return sectionCustomRequired;
+ }
+
+ virtual llvm::StringRef customSectionName() const {
+ if ((contentType() == typeZeroFill) ||
+ (_symbol->st_shndx == llvm::ELF::SHN_COMMON))
+ return ".bss";
+ return _sectionName;
+ }
+
+ // It isn't clear that __attribute__((used)) is transmitted to
+ // the ELF object file.
+ virtual DeadStripKind deadStrip() const {
+ return deadStripNormal;
+ }
+
+ virtual ContentPermissions permissions() const {
+
+ uint64_t flags = _section->sh_flags;
+ switch (_section->sh_type) {
+ // permRW_L is for sections modified by the runtime
+ // loader.
+ case llvm::ELF::SHT_REL:
+ case llvm::ELF::SHT_RELA:
+ return permRW_L;
+
+ case llvm::ELF::SHT_PROGBITS:
+ flags &= ~llvm::ELF::SHF_ALLOC;
+ switch (flags) {
+ // Code
+ case llvm::ELF::SHF_EXECINSTR:
+ return permR_X;
+ case (llvm::ELF::SHF_WRITE|llvm::ELF::SHF_EXECINSTR):
+ return permRWX;
+ // Data
+ case llvm::ELF::SHF_WRITE:
+ return permRW_;
+ // Strings
+ case llvm::ELF::SHF_MERGE:
+ case llvm::ELF::SHF_STRINGS:
+ return permR__;
+
+ default:
+ if (flags & llvm::ELF::SHF_WRITE)
+ return permRW_;
+ return permR__;
+ }
+
+ case llvm::ELF::SHT_NOBITS:
+ return permRW_;
+
+ default:
+ return perm___;
+ }
+ }
+
+ virtual bool isThumb() const {
+ return false;
+ }
+
+ // FIXME Not Sure if ELF supports alias atoms. Find out more.
+ virtual bool isAlias() const {
+ return false;
+ }
+
+ virtual llvm::ArrayRef<uint8_t> rawContent() const {
+ return _contentData;
+ }
+
+ DefinedAtom::reference_iterator begin() const {
+ uintptr_t index = _referenceStartIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const {
+ uintptr_t index = _referenceEndIndex;
+ const void *it = reinterpret_cast<const void*>(index);
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *It) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ assert(index >= _referenceStartIndex);
+ assert(index < _referenceEndIndex);
+ return ((_referenceList)[index]);
+ }
+
+ void incrementIterator(const void*& It) const {
+ uintptr_t index = reinterpret_cast<uintptr_t>(It);
+ ++index;
+ It = reinterpret_cast<const void*>(index);
+ }
+
+private:
+
+ const File &_owningFile;
+ llvm::StringRef _symbolName;
+ llvm::StringRef _sectionName;
+ const Elf_Sym *_symbol;
+ const Elf_Shdr *_section;
+ // _contentData will hold the bits that make up the atom.
+ llvm::ArrayRef<uint8_t> _contentData;
+
+ uint64_t _ordinal;
+ unsigned int _referenceStartIndex;
+ unsigned int _referenceEndIndex;
+ std::vector<ELFReference<target_endianness, is64Bits> *> &_referenceList;
+}; // ELFDefinedAtom
+
+
+//
+// Simple File
+//
+class SimpleFile : public File {
+public:
+ SimpleFile(StringRef path)
+ : File(path) {
+ }
+
+ virtual void addAtom(const Atom &atom) {
+ if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(&atom)) {
+ _definedAtoms._atoms.push_back(defAtom);
+ }
+ else if (const UndefinedAtom* undefAtom = dyn_cast<UndefinedAtom>(&atom)) {
+ _undefinedAtoms._atoms.push_back(undefAtom);
+ }
+ else if (const SharedLibraryAtom* slAtom =
+ dyn_cast<SharedLibraryAtom>(&atom)) {
+ _sharedLibraryAtoms._atoms.push_back(slAtom);
+ }
+ else if (const AbsoluteAtom* abAtom = dyn_cast<AbsoluteAtom>(&atom)) {
+ _absoluteAtoms._atoms.push_back(abAtom);
+ }
+ else {
+ llvm_unreachable("atom has unknown definition kind");
+ }
+ }
+
+ virtual const atom_collection<DefinedAtom>& defined() const {
+ return _definedAtoms;
+ }
+ virtual const atom_collection<UndefinedAtom>& undefined() const {
+ return _undefinedAtoms;
+ }
+ virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
+ return _sharedLibraryAtoms;
+ }
+ virtual const atom_collection<AbsoluteAtom>& absolute() const {
+ return _absoluteAtoms;
+ }
+
+private:
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+} // namespace lld
+
+#endif
Index: lib/ReaderWriter/ELF/WriterELF.cpp
===================================================================
--- lib/ReaderWriter/ELF/WriterELF.cpp (revision 169997)
+++ lib/ReaderWriter/ELF/WriterELF.cpp (working copy)
@@ -22,6 +22,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Object/ELF.h"
@@ -34,1382 +35,2098 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include "ELFAtoms.h"
#include <map>
+#include <unordered_map>
#include <tuple>
#include <vector>
-#include <algorithm>
using namespace llvm;
using namespace llvm::object;
namespace lld {
namespace elf {
-// The group decides where sections of similar permissions reside
-// inside a file. This is also used to create program headers. Each group
-// will be in a new segment.
+template<support::endianness target_endianness, bool is64Bits>
+class ELFExecutableWriter;
-/// \name Chunk Groups
-/// Each "Chunk" should be arranged in a weak strict order
-/// This is done to minimize memory utilization when creating program segments.
-/// This will remain in place till a more felxible mechanism of moving chunks
-/// around and packing for memory efficiency is put in place.
-/// The Chunks are arranged by group numbers. Every switch from group A to B
-/// triggers a formation of new segment. Additionally segments are also made
-/// within a group if there are vast regions (multiple pages) of 0 for
-/// alignment constraints.
-enum {
-/// @{
-///Invalid group (default on creation)
- CG_INVALID = 0x0,
-///This is a "header" kind of chunk that goes at beginning of ELF file
- CG_HEADER = 0x1,
-///This is a section chunk with read write and execute permissions
- CG_RWX = 0x3,
-///This is a section chunk with read and execute permissions
- CG_RX = 0x4,
-///This is a section chunk with read permission
- CG_R = 0x5,
-///This is a section chunk with read and write permissions
- CG_RW = 0x6,
-///This is a section chunk with write and execute permissions
- CG_WX = 0x7,
-///This is a section chunk with write permission
- CG_W = 0x8,
-///This is a section chunk with execute permission
- CG_X = 0x9,
-///This is a section which is no loaded by program loader
- CG_NO_LOAD = 0xFE,
-///This is ELF file metadata that goes at end of file
- CG_FILE_END = 0xFF
-/// @}
-};
+/// \brief The ELFWriter class is a base class for the linker to write
+/// various kinds of ELF files.
+class ELFWriter : public Writer {
+ public:
+ ELFWriter() { }
-template<support::endianness target_endianness, bool is64Bits>
-class ELFWriter;
+ public:
+ /// \brief builds the chunks that needs to be written to the output
+ /// ELF file
+ virtual void buildChunks(const lld::File &file) = 0;
-template<support::endianness target_endianness, bool is64Bits>
-class StockSectionChunk;
+ /// \brief Writes the chunks into the output file specified by path
+ virtual error_code writeFile(const lld::File &File, StringRef path) = 0;
-/// \brief A Chunk is a contiguous range of space.
+ /// \brief Writes the chunks into the output file specified by path
+ virtual int64_t addressOfAtom(const Atom *atom) = 0;
+
+ /// \brief Return the processing function to apply Relocations
+ virtual KindHandler *kindHandler() = 0;
+};
+
+/// \brief A chunk is a contiguous region of space
template<support::endianness target_endianness, bool is64Bits>
class Chunk {
public:
- LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
+
+ /// \brief Describes the type of Chunk
+ enum Kind {
+ ELFHeader, // ELF Header
+ ProgramHeader, // Program Header
+ Segment, // Segment
+ Section, // Section
+ SectionHeader // Section header
+ };
+ Chunk(StringRef name, Kind kind) : _name(name),
+ _kind(kind),
+ _fsize(0),
+ _msize(0),
+ _align2(0),
+ _order(0),
+ _ordinal(1),
+ _start(0),
+ _fileoffset(0) {}
virtual ~Chunk() {}
- virtual StringRef segmentName() const = 0;
- virtual bool occupiesNoDiskSpace();
- virtual void write(uint8_t *fileBuffer) = 0;
- void assignFileOffset(uint64_t &curOff, uint64_t &curAddr);
- virtual const char *info() = 0;
- uint64_t size() const;
- uint64_t address() const;
- uint64_t fileOffset() const;
- uint64_t align2() const;
- static uint64_t alignTo(uint64_t value, uint8_t align2);
- uint64_t ordinal() const { return _ordinal;}
- void setOrdinal(uint64_t newVal) { _ordinal = newVal;}
- void setGroup(uint16_t val) { _group = val;}
- uint16_t group() const { return _group;}
- void init();
- bool isLoadable() { return _isLoadable; }
- void isLoadable(uint64_t val) { _isLoadable = val; }
- enum class Kind {
- Header, // This is a header chunk
- Section // chunk represents a section
- };
- Kind getChunkKind() const { return _cKind; }
-private:
- const Kind _cKind;
+ // Does the chunk occupy disk space
+ virtual bool occupiesNoDiskSpace() {
+ return false;
+ }
+ // The name of the chunk
+ StringRef name() const { return _name; }
+ // Kind of chunk
+ Kind kind() const { return _kind; }
+ int64_t filesize() const { return _fsize; }
+ int64_t align2() const { return _align2; }
+ void appendAtom() const;
+
+ // Align the chunk, this doesnot take modulus into account
+ static int64_t alignTo(int64_t value, int64_t align2) {
+ return ((value + align2 - 1) & ~(align2 - 1));
+ }
+ // The ordinal value of the chunk
+ int64_t ordinal() const { return _ordinal;}
+ void setOrdinal(int64_t newVal) { _ordinal = newVal;}
+ // The order in which the chunk would appear in the output file
+ int64_t order() const { return _order; }
+ void setOrder(int32_t order) { _order = order; }
+ // Output file offset of the chunk
+ int64_t fileOffset() const { return _fileoffset; }
+ void setFileOffset(int64_t offset) { _fileoffset = offset; }
+ // Output start address of the chunk
+ void setStart(int64_t start) { _start = start; }
+ int64_t startAddr() const { return _start; }
+ // Does the chunk occupy memory during execution ?
+ int64_t memsize() const { return _msize; }
+ void setMemSize(int64_t msize) { _msize = msize; }
+ // Writer the chunk
+ virtual void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) = 0;
+ // Finalize the chunk before writing
+ virtual void finalize() = 0;
+ static inline bool classof(Chunk<target_endianness, is64Bits> *s) {
+ return true;
+ }
+
protected:
- Chunk();
- Chunk(Kind K): _cKind(K) { this->init();}
- uint64_t _size;
- uint64_t _address;
- uint64_t _fileOffset;
- uint64_t _align2;
- uint64_t _ordinal;
- uint16_t _group;
- bool _isLoadable;
+ StringRef _name;
+ Kind _kind;
+ int64_t _fsize;
+ int64_t _msize;
+ int64_t _align2;
+ int32_t _order;
+ int64_t _ordinal;
+ int64_t _start;
+ int64_t _fileoffset;
};
-template<support::endianness target_endianness, bool is64Bits>
-static void swapChunkPositions(Chunk<target_endianness, is64Bits>&a,
- Chunk<target_endianness, is64Bits>&b) {
- uint64_t tempOrdinal;
- if (a.ordinal() == b.ordinal()) return;
- tempOrdinal = a.ordinal();
- a.setOrdinal(b.ordinal());
- b.setOrdinal(tempOrdinal);
-}
+///
+/// \brief The ELFLayoutOptions encapsulates the options used by all Layouts
+/// Examples of the ELFLayoutOptions would be a script that would be used
+/// to drive the layout
+///
+class ELFLayoutOptions
+{
+public:
+ ELFLayoutOptions() { }
-template<support::endianness target_endianness, bool is64Bits>
-bool chunkGroupSort(Chunk<target_endianness, is64Bits> *A,
- Chunk<target_endianness, is64Bits> *B) {
- if (A->group() == CG_INVALID || B->group() == CG_INVALID)
- llvm_unreachable("Invalid group number");
- return A->group() < B->group();
-}
+ ELFLayoutOptions(StringRef &linker_script) : _script(linker_script)
+ {}
+ // parse the linker script
+ error_code parseLinkerScript();
+
+ // Is the current section present in the linker script
+ bool isSectionPresent();
+
+private:
+ StringRef _script;
+
+};
+
+///
+/// \brief The ELFLayout is an abstract class for managing the final layout for
+/// the kind of binaries(Shared Libraries / Relocatables / Executables 0
+/// Each architecture (Hexagon, PowerPC, MIPS) would have a concrete
+/// subclass derived from ELFLayout for generating each binary thats
+// needed by the lld linker
+///
+class ELFLayout
+{
+public:
+ typedef int32_t SectionOrder;
+ typedef int32_t SegmentType;
+ typedef int32_t Flags;
+
+public:
+ // Return the order the section would appear in the output file
+ virtual SectionOrder getSectionOrder(const StringRef name,
+ int32_t contentType,
+ int32_t contentPerm) = 0;
+ // append the Atom to the layout and create
+ // appropriate sections
+ virtual error_code addAtom(const Atom *atom) = 0;
+ // find the Atom Address in the current layout
+ virtual bool findAtomAddrByName(const StringRef name, int64_t &addr) = 0;
+ // associates a section to a segment
+ virtual void assignSectionsToSegments() = 0;
+ // associates a virtual address to the segment, section, and the atom
+ virtual void assignVirtualAddress() = 0;
+ // associates a file offset to the segment, section and the atom
+ virtual void assignFileOffset() = 0;
+
+public:
+ ELFLayout() {}
+ ELFLayout(WriterOptionsELF &writerOptions,
+ ELFLayoutOptions &layoutOptions) : _writerOptions(writerOptions),
+ _layoutOptions(layoutOptions) { }
+ virtual ~ELFLayout() { }
+
+private:
+ WriterOptionsELF _writerOptions;
+ ELFLayoutOptions _layoutOptions;
+};
+
+
+/// \brief A section contains a set of atoms that have similiar properties
+/// The atoms that have similiar properties are merged to form a section
template<support::endianness target_endianness, bool is64Bits>
-struct ChunkComparator {
- bool operator()(uint16_t A, Chunk<target_endianness, is64Bits> *B) {
- return A < B->group();
+class Section : public Chunk<target_endianness, is64Bits> {
+public:
+ // The Kind of section that the object represents
+ enum Kind {
+ Default,
+ SymbolTable,
+ StringTable,
+ };
+ // Create a section object, the section is set to the default type if the
+ // caller doesnot set it
+ Section(const StringRef sectionName,
+ const int32_t contentType,
+ const int32_t contentPermissions,
+ const int32_t order,
+ const Kind kind = Default) :
+ Chunk<target_endianness, is64Bits>(sectionName,
+ Chunk<target_endianness, is64Bits>::Section) {
+ _contentType = contentType;
+ _contentPermissions = contentPermissions;
+ _sectionKind = kind;
+ _link = 0;
+ _entsize = 0;
+ _shinfo = 0;
+ this->setOrder(order);
}
- bool operator()(Chunk<target_endianness, is64Bits> *A, uint16_t B) {
- return A->group() < B;
+
+ // return the section kind
+ Kind sectionKind() const {
+ return _sectionKind;
}
-#if defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 2
- bool operator()(Chunk<target_endianness, is64Bits> *A,
- Chunk<target_endianness, is64Bits> *B) {
- return A->group() < B->group();
- }
-#endif
-};
-/// Pair of atom and offset in section.
-typedef std::tuple<const DefinedAtom*, uint64_t> AtomInfo;
+ // append an atom to a Section
+ // The atom gets pushed into a vector that contains
+ // the atom, the atom file offset, the atom virtual address
+ // the atom file offset is aligned appropriately as set by the Reader
+ void appendAtom(const Atom *atom) {
+ Atom::Definition atomType = atom->definition();
+ const DefinedAtom* definedAtom = dyn_cast<DefinedAtom>(atom);
+ assert(atom != nullptr && "Expecting the atom to be a DefinedAtom");
+ DefinedAtom::Alignment atomAlign = definedAtom->alignment();
+ int64_t align2 = 1 << atomAlign.powerOf2;
+ uint64_t foffset = this->filesize();
+ uint64_t moffset = this->memsize();
-/// \brief A SectionChunk represents ELF sections
-template<support::endianness target_endianness, bool is64Bits>
-class SectionChunk : public Chunk<target_endianness, is64Bits> {
-public:
- virtual StringRef segmentName() const { return _segmentName; }
- virtual bool occupiesNoDiskSpace();
- virtual const char *info();
- StringRef sectionName() { return _sectionName; }
- uint64_t shStrtableOffset(){ return _offsetInStringTable; }
- void setShStrtableOffset (uint64_t val) {
- _offsetInStringTable = val; }
- uint32_t flags() { return _flags; }
- uint32_t type() const { return _type; }
- uint64_t link() { return _link; }
- void link(uint64_t val) { _link = val; }
- uint16_t shinfo() { return _shinfo; }
- uint64_t entsize() { return _entsize; }
- SectionChunk(StringRef secName, StringRef segName, bool loadable,
- uint64_t flags , uint64_t link, uint64_t info ,
- uint64_t type, uint64_t entsz, const WriterOptionsELF &op,
- ELFWriter<target_endianness, is64Bits> &writer);
+ // align the atom to the required modulus
+ // align the file offset and the memory offset seperately
+ // this is required so that BSS symbols are handled properly as the
+ // BSS symbols only occupy memory size and not file size
+ uint64_t requiredModulus = atomAlign.modulus;
+ uint64_t fcurrentModulus = (foffset % align2);
+ uint64_t mcurrentModulus = (moffset % align2);
+ // align the file offset
+ if (fcurrentModulus != requiredModulus) {
+ if (requiredModulus > fcurrentModulus)
+ foffset += requiredModulus - fcurrentModulus;
+ else
+ foffset += align2 + requiredModulus - fcurrentModulus;
+ }
+ // align memory offset
+ if (mcurrentModulus != requiredModulus) {
+ if (requiredModulus > mcurrentModulus)
+ moffset += requiredModulus - mcurrentModulus;
+ else
+ moffset += align2 + requiredModulus - mcurrentModulus;
+ }
+ switch (atomType) {
+ case Atom::definitionRegular:
+ switch(definedAtom->contentType()) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeData:
+ _atoms.push_back(std::make_pair(atom, std::make_pair(foffset, 0)));
+ this->_fsize = foffset + definedAtom->size();
+ this->_msize = moffset + definedAtom->size();
+ break;
+ case DefinedAtom::typeZeroFill:
+ _atoms.push_back(std::make_pair(atom, std::make_pair(moffset, 0)));
+ this->_msize = moffset + definedAtom->size();
+ break;
+ default:
+ this->_fsize = foffset + definedAtom->size();
+ this->_msize = moffset + definedAtom->size();
+ break;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ // Set the section alignment to the largest alignment
+ if (this->_align2 < align2)
+ this->_align2 = align2;
+ }
+
+ /// \brief Set the virtual address of each Atom in the Section
+ /// This routine gets called after the linker fixes up
+ /// the virtual address of the section
+ void assignVirtualAddress(int64_t &addr) {
+ for (auto ai = _atoms.begin(); ai != _atoms.end(); ++ai) {
+ ai->second.second = addr + ai->second.first;
+ }
+ addr += this->memsize();
+ }
+
+ /// \brief Set the file offset of each Atom in the section
+ /// This routine gets called after the linker fixes
+ /// up the section offset
+ void assignOffset(int64_t offset) {
+ for (auto ai = _atoms.begin(); ai != _atoms.end(); ++ai) {
+ ai->second.first = offset + ai->second.first;
+ }
+ }
+
+ /// \brief Find the Atom address given a name, this is needed to
+ /// to properly apply relocation
+ bool findAtomAddrByName(const StringRef name, int64_t &addr) {
+ for (auto ai = _atoms.begin(); ai != _atoms.end(); ++ai) {
+ if (ai->first->name() == name) {
+ addr = ai->second.second;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// \brief Does the Atom occupy any disk space
+ bool occupiesNoDiskSpace() const {
+ if (_contentType == DefinedAtom::typeZeroFill)
+ return true;
+ return false;
+ }
+
+ /// \brief The permission of the section is the most
+ /// restrictive permission of all atoms that the
+ /// section contains
+ void setContentPermissions(int32_t perm) {
+ if (perm > _contentPermissions)
+ _contentPermissions = perm;
+ }
+
+ /// \brief Get the section flags, defined by the permissions
+ /// of the section
+ int64_t flags() {
+ switch (_contentPermissions) {
+ case DefinedAtom::perm___:
+ return 0;
+
+ case DefinedAtom::permR__:
+ return llvm::ELF::SHF_ALLOC;
+ case DefinedAtom::permR_X:
+ return (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
+
+ case DefinedAtom::permRW_:
+ case DefinedAtom::permRW_L:
+ return (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE);
+
+ case DefinedAtom::permRWX:
+ return (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_EXECINSTR);
+
+ default:
+ break;
+ }
+ return llvm::ELF::SHF_ALLOC;
+ }
+
+ /// \brief Return the raw flags, we need this to sort segments
+ int64_t atomflags() const {
+ return _contentPermissions;
+ }
+
+ /// \brief Return the section type, the returned value is recorded
+ /// in the sh_type field of the Section Header
+ int type() {
+ switch (_contentType) {
+ case DefinedAtom::typeCode:
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeConstant:
+ return llvm::ELF::SHT_PROGBITS;
+
+ case DefinedAtom::typeZeroFill:
+ return llvm::ELF::SHT_NOBITS;
+
+ // Case to handle section types
+ // Symtab, String Table ...
+ default:
+ return _contentType;
+ }
+ }
+
+ /// \brief Returns the section link field, the returned value is
+ /// recorded in the sh_link field of the Section Header
+ int link() const {
+ return _link;
+ }
+
+ void setLink(int32_t link) {
+ _link = link;
+ }
+
+ /// \brief Returns the section entsize field, the returned value is
+ /// recorded in the sh_entsize field of the Section Header
+ int entsize() const {
+ return _entsize;
+ }
+
+ /// \brief Returns the shinfo field, the returned value is
+ /// recorded in the sh_info field of the Section Header
+ int shinfo() const {
+ return _shinfo;
+ }
+
+ /// \brief Records the segmentType, that this section belongs to
+ void setSegment(const ELFLayout::SegmentType segmentType) {
+ _segmentType = segmentType;
+ }
+
+ /// \brief convert the segment type to a String for diagnostics
+ /// and printing purposes
+ StringRef segmentKindToStr() const {
+ switch(_segmentType) {
+ case llvm::ELF::PT_INTERP:
+ return "INTERP";
+ case llvm::ELF::PT_LOAD:
+ return "LOAD";
+ case llvm::ELF::PT_GNU_EH_FRAME:
+ return "EH_FRAME";
+ case llvm::ELF::PT_NOTE:
+ return "NOTE";
+ case llvm::ELF::PT_DYNAMIC:
+ return "DYNAMIC";
+ case llvm::ELF::PT_GNU_RELRO:
+ return "RELRO";
+ case llvm::ELF::PT_NULL:
+ return "NULL";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ /// \brief for LLVM style RTTI information
+ static inline bool classof(Section<target_endianness, is64Bits> *s) {
+ return true;
+ }
+
static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
- return c->getChunkKind() == Chunk<target_endianness, is64Bits>::Kind
- ::Section;
+ return c->kind() == Chunk<target_endianness, is64Bits>::Section;
}
+
+ /// \brief Finalize the section contents before writing
+ void finalize() { }
+
+ /// \brief Write the section and the atom contents to the buffer
+ void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) {
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ for (auto ai = _atoms.begin(); ai != _atoms.end(); ++ai) {
+ const DefinedAtom* definedAtom = llvm::dyn_cast<DefinedAtom>(ai->first);
+ // Copy raw content of atom to file buffer.
+ ArrayRef<uint8_t> content = definedAtom->rawContent();
+ uint64_t contentSize = content.size();
+ if (contentSize == 0)
+ continue;
+ uint8_t *atomContent = chunkBuffer + ((ai)->second.first);
+ std::copy_n(content.data(), contentSize, atomContent);
+ for (auto ref = definedAtom->begin(); ref != definedAtom->end(); ++ref) {
+ uint32_t offset = ref->offsetInAtom();
+ uint64_t targetAddress = 0;
+ if ( ref->target() != nullptr )
+ targetAddress = writer->addressOfAtom(ref->target());
+ uint64_t fixupAddress = writer->addressOfAtom(ai->first) + offset;
+ // apply the relocation
+ writer->kindHandler()->applyFixup(ref->kind(), ref->addend(),
+ &atomContent[offset],
+ fixupAddress,
+ targetAddress);
+ }
+ }
+ }
+
+ /// Atom Iterators
+ typedef typename std::vector<std::pair<const Atom *,
+ std::pair<int64_t, int64_t>>>::iterator atom_iter;
+
+ atom_iter atoms_begin() { return _atoms.begin(); }
+
+ atom_iter atoms_end() { return _atoms.end(); }
+
protected:
- uint64_t _link;
- uint64_t _shinfo;
- uint16_t _entsize;
- StringRef _segmentName;
- StringRef _sectionName;
- const WriterOptionsELF &_options;
- ELFWriter<target_endianness, is64Bits> &_writer;
- uint64_t _flags;
- uint64_t _type;
- uint64_t _offsetInStringTable;
-};
+ int32_t _contentType;
+ int32_t _contentPermissions;
+ Kind _sectionKind;
+ // An Atom is appended to the vector with the following fields
+ // field1 : Atom
+ // field2 : fileoffset (initially set with a base offset of 0)
+ // field3 : virtual address
+ std::vector<std::pair<const Atom *, std::pair<int64_t, int64_t>>> _atoms;
+ ELFLayout::SegmentType _segmentType;
+ int64_t _entsize;
+ int64_t _shinfo;
+ int64_t _link;
+};
+/// \brief A MergedSection represents a set of sections grouped by the same name
+/// The output file that gets written by the linker has sections grouped
+/// by similiar names
template<support::endianness target_endianness, bool is64Bits>
-bool IsBss(const Chunk<target_endianness, is64Bits> *A) {
- if (auto X = llvm::dyn_cast<SectionChunk<target_endianness, is64Bits>>(A))
- return X->type() != ELF::SHT_NOBITS;
- llvm_unreachable("Call to a non section type chunk");
- // adding a non-reachable return bool for making compiler happy
- return false;
-}
+class MergedSection {
+public:
+ MergedSection(StringRef name) : _name(name) {
+ _hasSegment = false;
+ _ordinal = 0;
+ _flags = 0;
+ _size = 0;
+ _memsize = 0;
+ _fileOffset = 0;
+ _startAddr = 0;
+ _shinfo = 0;
+ _entsize = 0;
+ _link = 0;
+ _align2 = 0;
+ _kind = 0;
+ _type = 0;
+ }
+
+ // Set the MergedSection is associated with a segment
+ void setHasSegment() { _hasSegment = true; }
-/// \brief Return pointer to a defined atom whose name is specified as parameter
-/// if present in the specified section.
-/// When all the atoms are resolved, get addresses and offsets, we
-/// have atoms with unique names. Only then this routine is guaranteed
-/// to return the atom of interest. This routine is useful in finding atoms
-/// which are special such as entry point to a file
-template<support::endianness target_endianness, bool is64Bits>
-static const DefinedAtom* findDefinedAtomByName(StringRef name,
- StockSectionChunk<target_endianness,
- is64Bits> *sec) {
- ArrayRef<AtomInfo> atoms = sec->atoms();
- for (auto ai = atoms.begin(); ai != atoms.end(); ai++) {
- if ((std::get<0>(*ai))->name() == name )
- return std::get<0>(*ai);
+ // Sets the ordinal
+ void setOrdinal(int64_t ordinal) {
+ ordinal = ordinal;
}
- return nullptr;
-}
-/// \brief A StockSectionChunk is a section created by linker with all
-/// attributes concluded from the defined atom contained within.
-template<support::endianness target_endianness, bool is64Bits>
-class StockSectionChunk : public SectionChunk<target_endianness, is64Bits> {
-public:
- virtual StringRef segmentName() const { return this->_segmentName; }
- void appendAtom(const DefinedAtom*);
- virtual void write(uint8_t *filebuffer);
- const ArrayRef<AtomInfo> atoms() const;
- StockSectionChunk(StringRef sectionName, bool loadable,
- DefinedAtom::ContentType type,
- const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &writer);
+ // Sets the Memory size
+ void setMemSize(int64_t memsz) {
+ _memsize = memsz;
+ }
+
+ // Sets the size fo the merged Section
+ void setSize(int64_t fsiz) {
+ _size = fsiz;
+ }
+
+ // The offset of the first section contained in the merged section
+ // is contained here
+ void setFileOffset(int64_t foffset) {
+ _fileOffset = foffset;
+ }
+
+ // Sets the starting address of the section
+ void setAddr(int64_t addr) {
+ _startAddr = addr;
+ }
+
+ // Appends a section into the list of sections that are part of this Merged
+ // Section
+ void appendSection(Chunk<target_endianness, is64Bits> *c) {
+ Section<target_endianness, is64Bits> *section;
+ if (c->align2() > _align2)
+ _align2 = c->align2();
+ if (c->kind() == Chunk<target_endianness, is64Bits>::Section) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(c);
+ _link = section->link();
+ _shinfo = section->shinfo();
+ _entsize = section->entsize();
+ _type = section->type();
+ if (_flags < section->flags())
+ _flags = section->flags();
+ }
+ _kind = c->kind();
+ _sections.push_back(c);
+ }
+
+ // Iterators
+ typedef typename std::vector<Chunk<target_endianness, is64Bits> *>::iterator
+ chunk_iter;
+
+ chunk_iter begin_sections() { return _sections.begin(); }
+
+ chunk_iter end_sections() { return _sections.end(); }
+
+ // The below functions returns the properties of the MergeSection
+ bool hasSegment() const { return _hasSegment; }
+
+ StringRef name() const { return _name; }
+
+ int64_t shinfo() const { return _shinfo; }
+
+ int64_t align2() const { return _align2; }
+
+ int64_t link() const { return _link; }
+
+ int64_t type() const { return _type; }
+
+ int64_t startAddr() const { return _startAddr; }
+
+ int64_t ordinal() const { return _ordinal; }
+
+ int64_t kind() const { return _kind; }
+
+ int64_t filesize() const { return _size; }
+
+ int64_t entsize() const { return _entsize; }
+
+ int64_t fileOffset() const { return _fileOffset; }
+
+ int64_t flags() const { return _flags; }
+
+ int64_t memsize() { return _memsize; }
+
private:
- std::vector<AtomInfo> _atoms;
+ StringRef _name;
+ bool _hasSegment;
+ int64_t _ordinal;
+ int64_t _flags;
+ int64_t _size;
+ int64_t _memsize;
+ int64_t _fileOffset;
+ int64_t _startAddr;
+ int64_t _shinfo;
+ int64_t _entsize;
+ int64_t _link;
+ int64_t _align2;
+ int64_t _kind;
+ int64_t _type;
+ std::vector<Chunk<target_endianness, is64Bits> *> _sections;
};
-
-/// \brief An ELFHeaderChunk represents the Elf[32/64]_Ehdr structure at the
-/// start of an ELF executable file.
+
+/// \brief A segment can be divided into segment slices
+/// depending on how the segments can be split
template<support::endianness target_endianness, bool is64Bits>
-class ELFHeaderChunk : public Chunk<target_endianness, is64Bits> {
+class SegmentSlice {
public:
- LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
- typedef object::Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr;
+ typedef typename std::vector<Chunk<target_endianness, is64Bits> *>::iterator
+ chunk_iter;
- ELFHeaderChunk(const WriterOptionsELF &options,
- const File &file);
+ SegmentSlice() { }
- void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
- void e_type(uint16_t type) { _eh.e_type = type; }
- void e_machine(uint16_t machine) { _eh.e_machine = machine; }
- void e_version(uint32_t version) { _eh.e_version = version; }
- void e_entry(uint64_t entry) { _eh.e_entry = entry; }
- void e_phoff(uint64_t phoff) { _eh.e_phoff = phoff; }
- void e_shoff(uint64_t shoff) { _eh.e_shoff = shoff; }
- void e_flags(uint32_t flags) { _eh.e_flags = flags; }
- void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; }
- void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
- void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; }
- void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
- void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
- void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
- uint64_t size() { return sizeof (Elf_Ehdr); }
+ // Set the segment slice so that it begins at the offset specified
+ // by fileoffset and set the start of the slice to be s and the end
+ // of the slice to be e
+ void set(int64_t fileoffset, int32_t s, int e) {
+ _startChunk = s;
+ _endChunk = e;
+ _offset = fileoffset;
+ }
- virtual StringRef segmentName() const;
- virtual void write(uint8_t *fileBuffer);
- virtual const char *info();
- static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
- return c->getChunkKind() == Chunk<target_endianness, is64Bits>::Kind
- ::Header;
+ // Set the segment slice start and end iterators
+ // This is used to walk through the sections that are part of the
+ // Segment slice
+ void setChunks(chunk_iter start, chunk_iter end) {
+ startChunkIter = start;
+ endChunkIter = end;
}
+
+ // Return the fileOffset of the slice
+ int64_t fileOffset() const { return _offset; }
+
+ // Return the size of the slice
+ int64_t fileSize() const { return _size; }
+
+ // Return the start of the slice
+ int32_t startChunk() const { return _startChunk; }
+
+ // Return the start address of the slice
+ int64_t startAddr() const { return _addr; }
+
+ // Return the memory size of the slice
+ int64_t memsize() const { return _memsize; }
+
+ // Return the alignment of the slice
+ int64_t align2() const { return _align2; }
+
+ void setSize(int64_t sz) { _size = sz; }
+
+ void setMemSize(int64_t memsz) { _memsize = memsz; }
+
+ void setStart(int64_t addr) { _addr = addr; }
+
+ void setAlign(int64_t align) { _align2 = align; }
+
+ static bool compare_slices(SegmentSlice<target_endianness, is64Bits> *a,
+ SegmentSlice<target_endianness, is64Bits> *b) {
+ return (a->startChunk() < b->startChunk());
+ }
+
+ // Functions to run through the slice
+ chunk_iter chunks_begin() { return startChunkIter; }
+
+ chunk_iter chunks_end() { return endChunkIter; }
+
private:
- Elf_Ehdr _eh;
+ int32_t _startChunk;
+ int32_t _endChunk;
+ chunk_iter startChunkIter;
+ chunk_iter endChunkIter;
+ int64_t _addr;
+ int64_t _offset;
+ int64_t _size;
+ int64_t _align2;
+ int64_t _memsize;
};
-/// \brief An ELFSectionHeaderChunk represents the Elf[32/64]_Shdr structure
-/// that is placed right after the ELFHeader.
-///
+/// \brief A segment contains a set of sections, that have similiar properties
+// the sections are already seperated based on different flags and properties
+// the segment is just a way to concatenate sections to segments
template<support::endianness target_endianness, bool is64Bits>
-class ELFSectionHeaderChunk : public Chunk<target_endianness, is64Bits> {
+class Segment : public Chunk<target_endianness, is64Bits> {
public:
- LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
- typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
- ELFSectionHeaderChunk(const WriterOptionsELF &Options,
- ELFWriter<target_endianness, is64Bits>&);
- void createHeaders();
- virtual StringRef segmentName() const;
- virtual void write(uint8_t *filebuffer);
- virtual const char *info();
- void computeSize();
- uint16_t count();
- uint16_t size();
- void fixOffsets();
- const ArrayRef<Elf_Shdr*> sectionInfo() {
- return _sectionInfo;
+ typedef typename std::vector
+ <SegmentSlice<target_endianness, is64Bits> *>::iterator slice_iter;
+ typedef typename
+ std::vector<Chunk<target_endianness, is64Bits> *>::iterator chunk_iter;
+
+ Segment(const StringRef name,
+ const ELFLayout::SegmentType type,
+ const WriterOptionsELF &options):
+ Chunk<target_endianness, is64Bits>(name,
+ Chunk<target_endianness, is64Bits>::Segment),
+ _options(options) {
+ _segmentType = type;
+ _flags = 0;
+ _atomflags = 0;
+ this->_align2 = 0;
+ this->_fsize = 0;
}
+
+ // append a section to a segment
+ void append(Section<target_endianness, is64Bits> *section) {
+ _chunks.push_back(section);
+ if (_flags < section->flags())
+ _flags = section->flags();
+ if (_atomflags < section->atomflags())
+ _atomflags = section->atomflags();
+ if (this->_align2 < section->align2()) {
+ this->_align2 = section->align2();
+ }
+ }
+
+ /// Sort segments depending on the property
+ /// If we have a Program Header segment, it should appear first
+ /// If we have a INTERP segment, that should appear after the Program Header
+ /// All Loadable segments appear next in this order
+ /// All Read Write Execute segments follow
+ /// All Read Execute segments appear next
+ /// All Read only segments appear first
+ /// All Write execute segments follow
+ static bool compare_segments(Chunk<target_endianness, is64Bits> *a,
+ Chunk<target_endianness, is64Bits> *b)
+ {
+
+ Segment<target_endianness, is64Bits> *sega =
+ llvm::dyn_cast<Segment<target_endianness, is64Bits>>(a);
+ Segment<target_endianness, is64Bits> *segb =
+ llvm::dyn_cast<Segment<target_endianness, is64Bits>>(b);
+ if (sega->atomflags() < segb->atomflags())
+ return false;
+ return true;
+ }
+
+ // \brief Start assigning file offset to the segment chunks
+ // The fileoffset needs to be page at the start of the segment
+ // and in addition the fileoffset needs to be aligned to the
+ // max section alignment within the segment. This is required
+ // so that the ELF property p_poffset % p_align = p_vaddr mod p_align
+ // holds true
+ void assignOffset(int64_t startOffset) {
+ int startChunk = 0;
+ int currChunk = 0;
+ chunk_iter startChunkIter, endChunkIter;
+ // slice align is set to the max alignment of the chunks that are
+ // contained in the slice
+ int64_t sliceAlign = 0;
+ // Current slice size
+ int64_t curSliceSize = 0;
+ // Current Slice File Offset
+ int64_t curSliceFileOffset = 0;
+
+ Section<target_endianness, is64Bits> *section;
+ startChunkIter = _chunks.begin();
+ endChunkIter = _chunks.end();
+ startChunk = currChunk;
+ bool isFirstSection = true;
+ for (auto ci = _chunks.begin(); ci != _chunks.end(); ++ci) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ci);
+ if (isFirstSection) {
+ // align the startOffset to the section alignment
+ int64_t newOffset = Chunk<target_endianness, is64Bits>::alignTo
+ (startOffset, section->align2());
+ curSliceFileOffset = newOffset;
+ sliceAlign = section->align2();
+ this->setFileOffset(startOffset);
+ section->setFileOffset(newOffset);
+ curSliceSize = section->filesize();
+ isFirstSection = false;
+ } else {
+ uint64_t curOffset = curSliceFileOffset + curSliceSize;
+ uint64_t newOffset = Chunk<target_endianness, is64Bits>::alignTo
+ (curOffset, section->align2());
+ SegmentSlice<target_endianness, is64Bits> *slice = nullptr;
+ // If the newOffset computed is more than a page away, lets create
+ // a seperate segment, so that memory is not used up while running
+ if ((newOffset - curOffset) > _options.pageSize()) {
+ for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+ if ((*sei)->startChunk() == startChunk) {
+ slice = *sei;
+ break;
+ }
+ }
+ if (!slice) {
+ slice = new SegmentSlice<target_endianness, is64Bits>();
+ _segmentSlices.push_back(slice);
+ }
+ slice->set(curSliceFileOffset, startChunk, currChunk);
+ slice->setChunks(startChunkIter, endChunkIter);
+ slice->setSize(curSliceSize);
+ slice->setAlign(sliceAlign);
+ int64_t newPageOffset = Chunk<target_endianness, is64Bits>::alignTo
+ (curOffset, _options.pageSize());
+ newOffset = Chunk<target_endianness, is64Bits>::alignTo
+ (newPageOffset, section->align2());
+ curSliceFileOffset = newOffset;
+ startChunkIter = endChunkIter;
+ startChunk = currChunk;
+ section->setFileOffset(curSliceFileOffset);
+ curSliceSize = newOffset - curSliceFileOffset + section->filesize();
+ sliceAlign = section->align2();
+ }
+ else {
+ if (sliceAlign < section->align2())
+ sliceAlign = section->align2();
+ section->setFileOffset(newOffset);
+ curSliceSize = newOffset - curSliceFileOffset + section->filesize();
+ }
+ }
+ currChunk++;
+ endChunkIter = ci;
+ }
+ SegmentSlice<target_endianness, is64Bits> *slice = nullptr;
+ for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+ if ((*sei)->startChunk() == startChunk) {
+ slice = *sei;
+ break;
+ }
+ }
+ if (!slice) {
+ slice = new SegmentSlice<target_endianness, is64Bits>();
+ _segmentSlices.push_back(slice);
+ }
+ slice->set(curSliceFileOffset, startChunk, currChunk);
+ slice->setChunks(startChunkIter, _chunks.end());
+ slice->setSize(curSliceSize);
+ slice->setAlign(sliceAlign);
+ this->_fsize = curSliceFileOffset - startOffset + curSliceSize;
+ std::stable_sort(slices_begin(), slices_end(),
+ SegmentSlice<target_endianness, is64Bits>::compare_slices);
+ }
+
+ /// \brief Assign virtual addresses to the slices
+ void assignVirtualAddress(int64_t &addr, bool isFirstSegment) {
+ Section<target_endianness, is64Bits> *section;
+ for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+ bool firstSlice = (sei == slices_begin());
+ // The first segment has distinct since it contains the
+ // ELF header and the Program Header, if we get to the first segment
+ // and the first slice, set it to the baseaddress
+ // which is the segment address
+ if (isFirstSegment && firstSlice) {
+ (*sei)->setStart(this->startAddr());
+ }
+ else {
+ // Align to a page
+ addr = Chunk<target_endianness, is64Bits>::alignTo(addr,
+ _options.pageSize());
+ // Align to the slice alignment
+ addr = Chunk<target_endianness, is64Bits>::alignTo(addr,
+ (*sei)->align2());
+ }
+ bool startAddressSet = false;
+ for (auto ci = (*sei)->chunks_begin(); ci != (*sei)->chunks_end(); ++ci) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ci);
+ // Align the section address
+ addr = Chunk<target_endianness, is64Bits>::alignTo(addr,
+ section->align2());
+ if (!isFirstSegment && !startAddressSet) {
+ (*sei)->setStart(addr);
+ startAddressSet = true;
+ }
+ section->setStart(addr);
+ section->assignVirtualAddress(addr);
+ section->setMemSize(addr - section->startAddr());
+ }
+ (*sei)->setMemSize(addr - (*sei)->startAddr());
+ }
+ }
+
+ slice_iter slices_begin() {
+ return _segmentSlices.begin();
+ }
+
+ slice_iter slices_end() {
+ return _segmentSlices.end();
+ }
+
+ // Write the Segment
+ void write(ELFWriter *writer, OwningPtr<FileOutputBuffer> &buffer) {
+ for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+ for (auto ci = (*sei)->chunks_begin(); ci != (*sei)->chunks_end(); ++ci) {
+ (*ci)->write(writer, buffer);
+ }
+ }
+ }
+
+ // Finalize the segment, before we want to write to the output file
+ void finalize() { }
+
+ // For LLVM RTTI
+ static inline bool classof(Segment<target_endianness, is64Bits> *s) {
+ return true;
+ }
+
static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
- return c->getChunkKind() == Chunk<target_endianness, is64Bits>::Kind
- ::Header;
+ return c->kind() == Chunk<target_endianness, is64Bits>::Segment;
}
+ // Getters
+ int32_t sectionCount() const {
+ return _chunks.size();
+ }
+
+ ELFLayout::SegmentType segmentType() { return _segmentType; }
+
+ int pgsz() const { return _options.pageSize(); }
+
+ int64_t atomflags() const { return _atomflags; }
+
+ int64_t flags() const {
+ int64_t fl = 0;
+ if (_flags & llvm::ELF::SHF_ALLOC)
+ fl |= llvm::ELF::PF_R;
+ if (_flags & llvm::ELF::SHF_WRITE)
+ fl |= llvm::ELF::PF_W;
+ if (_flags & llvm::ELF::SHF_EXECINSTR)
+ fl |= llvm::ELF::PF_X;
+ return fl;
+ }
+
+ int64_t numSlices() const {
+ return _segmentSlices.size();
+ }
+
private:
- const WriterOptionsELF &_options;
- ELFWriter<target_endianness, is64Bits> &_writer;
- llvm::BumpPtrAllocator _sectionAllocate;
- std::vector<Elf_Shdr*> _sectionInfo;
+ std::vector<Chunk<target_endianness, is64Bits> *> _chunks;
+ std::vector<SegmentSlice<target_endianness, is64Bits> *> _segmentSlices;
+ ELFLayout::SegmentType _segmentType;
+ int64_t _flags;
+ int64_t _atomflags;
+ const WriterOptionsELF _options;
};
-/// \brief Represents the shstr section.
-///
-/// This is a contiguous memory that has all the symbol strings each ending with
-/// null character. We might need more than one such chunks shstrtab for setting
-/// e_shstrndx in ELHHeaderChunk and strtab for use with symtab
+/// \brief The class represents the ELF String Table
template<support::endianness target_endianness, bool is64Bits>
-class ELFStringSectionChunk : public SectionChunk<target_endianness, is64Bits> {
+class ELFStringTable : public Section<target_endianness, is64Bits> {
+
public:
- ELFStringSectionChunk(const WriterOptionsELF &Options,
- ELFWriter<target_endianness, is64Bits> &writer,
- StringRef secName);
- virtual StringRef segmentName() const { return this->_segmentName; }
- uint64_t addString(StringRef symName);
- const char *info();
- virtual void write(uint8_t *filebuffer);
+ ELFStringTable(const char *str,
+ int32_t order):
+ Section<target_endianness, is64Bits>(str,
+ llvm::ELF::SHT_STRTAB,
+ DefinedAtom::perm___,
+ order,
+ Section<target_endianness, is64Bits>::StringTable) {
+ // the string table has a NULL entry for which
+ // add an empty string
+ _strings.push_back("");
+ this->_fsize = 1;
+ this->_align2 = 1;
+ this->setOrder(order);
+ }
+ static inline bool classof(ELFStringTable<target_endianness, is64Bits> *s) {
+ return true;
+ }
+
+ static inline bool classof(const Section<target_endianness, is64Bits> *c) {
+ return c->kind() == Section<target_endianness, is64Bits>::StringTable;
+ }
+
+ static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+ return c->kind() == Section<target_endianness, is64Bits>::StringTable;
+ }
+
+ int64_t addString(const StringRef symname) {
+ _strings.push_back(symname);
+ int64_t offset = this->_fsize;
+ this->_fsize += symname.size() + 1;
+ return offset;
+ }
+
+ void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) {
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto si = _strings.begin(); si != _strings.end(); ++si) {
+ memcpy(dest, si->data(), si->size());
+ dest += si->size();
+ memcpy(dest, "", 1);
+ dest += 1;
+ }
+ }
+
+ void finalize() { }
+
private:
- std::vector<StringRef> _stringSection;
+ std::vector<StringRef> _strings;
};
-/// \brief Represents the symtab section
-///
-/// ELFSymbolTableChunk represents the Symbol table as per ELF ABI
-/// This is a table with Elf[32/64]_Sym entries in it.
+/// \brief The ELFSymbolTable class represents the symbol table in a ELF file
template<support::endianness target_endianness, bool is64Bits>
-class ELFSymbolTableChunk : public SectionChunk<target_endianness, is64Bits> {
+class ELFSymbolTable : public Section<target_endianness, is64Bits> {
+
public:
typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
- ELFSymbolTableChunk(const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &writer,
- StringRef secName);
- virtual StringRef segmentName() const { return this->_segmentName; }
- void addSymbol(const Atom *a, uint16_t shndx);
- void addSymbol(Elf_Sym *x);
- void fixSymbolValue();
- const char *info();
- void setAttributes();
- virtual void write(uint8_t *fileBuffer);
+ ELFSymbolTable(const char *str,
+ int32_t order):
+ Section<target_endianness, is64Bits>(str,
+ llvm::ELF::SHT_SYMTAB,
+ 0,
+ order,
+ Section<target_endianness, is64Bits>::SymbolTable)
+
+ {
+ this->setOrder(order);
+ Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
+ memset ((void *)symbol,0, sizeof(Elf_Sym));
+ _symbolTable.push_back(symbol);
+ this->_entsize = sizeof(Elf_Sym);
+ this->_fsize = sizeof(Elf_Sym);
+ this->_align2 = sizeof(void *);
+ }
+
+ static inline bool classof(ELFSymbolTable<target_endianness, is64Bits> *s) {
+ return true;
+ }
+
+ static inline bool classof(const Section<target_endianness, is64Bits> *c) {
+ return c->kind() == Section<target_endianness, is64Bits>::SymbolTable;
+ }
+
+ static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+ return c->kind() == Section<target_endianness, is64Bits>::SymbolTable;
+ }
+
+ void addSymbol(const Atom *a, int32_t shndx, int64_t addr=0) {
+ Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
+ unsigned char b = 0, t = 0;
+ symbol->st_name = _stringSection->addString(a->name());
+ symbol->st_size = 0;
+ symbol->st_shndx = shndx;
+ symbol->st_value = 0;
+ symbol->st_other = ELF::STV_DEFAULT;
+ if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(a)){
+ symbol->st_size = da->size();
+ lld::DefinedAtom::ContentType ct;
+ switch (ct = da->contentType()){
+ case DefinedAtom::typeCode:
+ // TODO: add offset
+ symbol->st_value = addr;
+ t = ELF::STT_FUNC;
+ break;
+ case DefinedAtom::typeData:
+ // TODO: add offset
+ symbol->st_value = addr;
+ t = ELF::STT_OBJECT;
+ break;
+ case DefinedAtom::typeZeroFill:
+ t = ELF::STT_COMMON;
+ symbol->st_value = addr;
+ break;
+ default:
+ t = ELF::STT_NOTYPE;
+ }
+ if (da->scope() == DefinedAtom::scopeTranslationUnit)
+ b = ELF::STB_LOCAL;
+ else
+ b = ELF::STB_GLOBAL;
+ } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(a)){
+ t = ELF::STT_OBJECT;
+ symbol->st_shndx = ELF::SHN_ABS;
+ switch (aa->scope()) {
+ case AbsoluteAtom::scopeLinkageUnit:
+ symbol->st_other = ELF::STV_HIDDEN;
+ b = ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeTranslationUnit:
+ b = ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeGlobal:
+ b = ELF::STB_GLOBAL;
+ break;
+ }
+ symbol->st_value = aa->value();
+ }
+ else {
+ symbol->st_value = 0;
+ t = ELF::STT_NOTYPE;
+ b = ELF::STB_WEAK;
+ }
+ symbol->setBindingAndType(b, t);
+ _symbolTable.push_back(symbol);
+ this->_fsize += sizeof(Elf_Sym);
+ }
+
+ void setStringSection(ELFStringTable<target_endianness, is64Bits> *s) {
+ _stringSection = s;
+ }
+
+ void finalize() {
+ // sh_info should be one greater than last symbol with STB_LOCAL binding
+ // we sort the symbol table to keep all local symbols at the beginning
+ std::stable_sort(_symbolTable.begin(), _symbolTable.end(), ([]
+ (const Elf_Sym *A, const Elf_Sym *B) -> bool {
+ return (A->getBinding() < B->getBinding());}));
+ uint16_t shInfo = 0;
+ for (auto i : _symbolTable) {
+ if (i->getBinding() != ELF::STB_LOCAL)
+ break;
+ shInfo++;
+ }
+ this->_shinfo = shInfo;
+ this->setLink(_stringSection->ordinal());
+ }
+
+ void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) {
+
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto sti = _symbolTable.begin(); sti != _symbolTable.end(); ++sti) {
+ memcpy(dest, (*sti), sizeof(Elf_Sym));
+ dest += sizeof(Elf_Sym);
+ }
+ }
+
private:
+ ELFStringTable<target_endianness, is64Bits> *_stringSection;
std::vector<Elf_Sym*> _symbolTable;
- ELFStringSectionChunk<target_endianness, is64Bits> *_stringSection;
llvm::BumpPtrAllocator _symbolAllocate;
- std::map<Elf_Sym*, const Atom*> _symbolToAtom;
+ int64_t _link;
};
-/// \brief ELFProgramHeaderChunk represents the Elf[32/64]_Phdr structure near
-/// the start of an ELF executable file. ELFHeader's e_phentsize and e_phnum
-/// show the number of entries in table and size of each one.
+/// \brief An ELFHeader represents the Elf[32/64]_Ehdr structure at the
+/// start of an ELF executable file.
template<support::endianness target_endianness, bool is64Bits>
-class ELFProgramHeaderChunk : public Chunk<target_endianness, is64Bits> {
+class ELFHeader : public Chunk<target_endianness, is64Bits> {
public:
- LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
- typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
- ELFProgramHeaderChunk(const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &);
+ typedef object::Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr;
- virtual StringRef segmentName() const;
- virtual void write(uint8_t *filebuffer);
- virtual const char *info();
- void createPHeaders();
- uint64_t computeNumber();
+ ELFHeader():Chunk<target_endianness, is64Bits>("elfhdr",
+ Chunk<target_endianness, is64Bits>::ELFHeader)
+ {
+ for (int i=0; i < llvm::ELF::EI_NIDENT; ++i)
+ e_ident(i, 0);
+ e_ident(ELF::EI_MAG0, 0x7f);
+ e_ident(ELF::EI_MAG1, 'E');
+ e_ident(ELF::EI_MAG2, 'L');
+ e_ident(ELF::EI_MAG3, 'F');
+ e_ehsize(sizeof(Elf_Ehdr));
+ e_flags(2);
+ }
+ void e_ident(int I, unsigned char C) { _eh.e_ident[I] = C; }
+ void e_type(uint16_t type) { _eh.e_type = type; }
+ void e_machine(uint16_t machine) { _eh.e_machine = machine; }
+ void e_version(uint32_t version) { _eh.e_version = version; }
+ void e_entry(int64_t entry) { _eh.e_entry = entry; }
+ void e_phoff(int64_t phoff) { _eh.e_phoff = phoff; }
+ void e_shoff(int64_t shoff) { _eh.e_shoff = shoff; }
+ void e_flags(uint32_t flags) { _eh.e_flags = flags; }
+ void e_ehsize(uint16_t ehsize) { _eh.e_ehsize = ehsize; }
+ void e_phentsize(uint16_t phentsize) { _eh.e_phentsize = phentsize; }
+ void e_phnum(uint16_t phnum) { _eh.e_phnum = phnum; }
+ void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
+ void e_shnum(uint16_t shnum) { _eh.e_shnum = shnum; }
+ void e_shstrndx(uint16_t shstrndx) { _eh.e_shstrndx = shstrndx; }
+ int64_t filesize() { return sizeof (Elf_Ehdr); }
+
static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
- return c->getChunkKind() == Chunk<target_endianness, is64Bits>::Kind
- ::Header;
+ return c->Kind() == Chunk<target_endianness, is64Bits>::Header;
}
-private:
- typedef typename std::vector<SectionChunk<target_endianness, is64Bits>*>
- ::iterator secIterator;
- const WriterOptionsELF &_options;
- ELFWriter<target_endianness, is64Bits> &_writer;
- std::vector<Elf_Phdr*> _programHeaders;
- llvm::BumpPtrAllocator _headerAllocate;
- typedef std::pair<uint64_t, uint64_t> sectionRange;
- std::vector<sectionRange> _segments;
- std::map<uint16_t, uint16_t> _groupToPF;
+ void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) {
-};
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ uint8_t *atomContent = chunkBuffer + this->fileOffset();
+ memcpy(atomContent, &_eh, filesize());
+ }
-//===----------------------------------------------------------------------===//
-// Chunk
-//===----------------------------------------------------------------------===//
+ void finalize() { }
-template<support::endianness target_endianness, bool is64Bits>
-Chunk<target_endianness, is64Bits>::Chunk(){
- this->init();
-}
+private:
+ Elf_Ehdr _eh;
+};
+/// \brief An ELFProgramHeader represents the Elf[32/64]_Phdr structure at the
+/// start of an ELF executable file.
template<support::endianness target_endianness, bool is64Bits>
-void Chunk<target_endianness, is64Bits>::init(){
- this->_size = 0;
- this->_address = 0;
- this->_fileOffset = 0;
- this->_align2 = 0;
- this->_group = CG_INVALID;
- this->_isLoadable = false;
- // 0 and 1 are reserved. 0 for ELF header and 1 for program header.
- static uint64_t orderNumber = 0;
- _ordinal = orderNumber++;
-}
+class ELFProgramHeader : public Chunk<target_endianness, is64Bits> {
+public:
+ typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
-template<support::endianness target_endianness, bool is64Bits>
-bool Chunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
- return false;
-}
+ ELFProgramHeader():Chunk<target_endianness, is64Bits>("elfphdr",
+ Chunk<target_endianness, is64Bits>::ProgramHeader)
+ {
+ }
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::size() const {
- return _size;
-}
+ bool addSegment(Segment<target_endianness, is64Bits> *segment) {
+ Elf_Phdr *phdr = nullptr;
+ bool ret = false;
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::align2() const {
- return _align2;
-}
+ for (auto sei = segment->slices_begin(); sei != segment->slices_end();
+ ++sei) {
+ if (_phi == _ph.end()) {
+ phdr = new(_allocator.Allocate<Elf_Phdr>()) Elf_Phdr;
+ _ph.push_back(phdr);
+ _phi = _ph.end();
+ ret = true;
+ }
+ else {
+ phdr = (*_phi);
+ ++_phi;
+ }
+ phdr->p_type = segment->segmentType();
+ phdr->p_offset = (*sei)->fileOffset();
+ phdr->p_vaddr = (*sei)->startAddr();
+ phdr->p_paddr = (*sei)->startAddr();
+ phdr->p_filesz = (*sei)->fileSize();
+ phdr->p_memsz = (*sei)->memsize();
+ phdr->p_flags = segment->flags();
+ phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
+ segment->pgsz() : (*sei)->align2();
+ }
+ return ret;
+ }
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::address() const {
- return _address;
-}
+ void resetProgramHeaders() {
+ _phi = _ph.begin();
+ }
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::fileOffset() const {
- return _fileOffset;
-}
+ void setStart(int64_t addr) {
+ this->_start = Chunk<target_endianness, is64Bits>::alignTo(addr, 8);
+ this->_fsize = this->_start - addr;
+ }
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t Chunk<target_endianness, is64Bits>::
- alignTo(uint64_t value, uint8_t align2) {
- uint64_t align = 1 << align2;
- return (value + (align - 1)) & (-align);
-}
+ int64_t filesize() { return this->_fsize + (sizeof (Elf_Phdr) * _ph.size()); }
-template<support::endianness target_endianness, bool is64Bits>
-void Chunk<target_endianness, is64Bits>::
- assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) {
- if (occupiesNoDiskSpace()) {
- // FileOffset does not change, but virtual address does change.
- uint64_t alignedAddress =
- alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
- : 0);
- _address = alignedAddress;
- curAddress = alignedAddress + _size;
- } else {
- // FileOffset and address both move by _size amount after alignment.
- uint64_t alignPadding =
- alignTo(curAddress, _align2 ? static_cast<uint8_t>(llvm::Log2_64(_align2))
- : 0) - curAddress;
- _fileOffset = curOffset + alignPadding;
- _address = curAddress + alignPadding;
- curOffset = _fileOffset + _size;
- curAddress = _address + _size;
+ static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+ return c->Kind() == Chunk<target_endianness, is64Bits>::ProgramHeader;
}
- DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
- << " fileOffset="
- << format("0x%08X", _fileOffset)
- << " address="
- << format("0x%016X", _address)
- << " info=" << info() << "\n");
-}
+ void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) {
-//===----------------------------------------------------------------------===//
-// SectionChunk
-//===----------------------------------------------------------------------===//
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto phi = _ph.begin(); phi != _ph.end(); ++phi) {
+ memcpy(dest, (*phi), sizeof(Elf_Phdr));
+ dest += sizeof(Elf_Phdr);
+ }
+ }
-template<support::endianness target_endianness, bool is64Bits>
-SectionChunk<target_endianness, is64Bits>::
- SectionChunk(StringRef secName, StringRef segName, bool loadable,
- uint64_t flags , uint64_t link, uint64_t info , uint64_t type,
- uint64_t entsz, const WriterOptionsELF &op,
- ELFWriter<target_endianness, is64Bits> &writer)
- : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
- ::Kind::Section)
- , _link(link)
- , _shinfo(info)
- , _entsize(entsz)
- , _segmentName(segName)
- , _sectionName(secName)
- , _options(op)
- , _writer(writer)
- , _flags(flags)
- , _type(type)
- , _offsetInStringTable(0) {
- this->isLoadable(loadable);
-}
-//FIXME: We need to make decision here for every section created
-template<support::endianness target_endianness, bool is64Bits>
-bool SectionChunk<target_endianness, is64Bits>::occupiesNoDiskSpace() {
- return false;
-}
+ void finalize() { }
-template<support::endianness target_endianness, bool is64Bits>
-const char *SectionChunk<target_endianness, is64Bits>::info() {
- return _sectionName.data();
-}
+ int64_t entsize() {
+ return sizeof(Elf_Phdr);
+ }
-//===----------------------------------------------------------------------===//
-// StockSectionChunk
-//===----------------------------------------------------------------------===//
+ int64_t numHeaders() {
+ return _ph.size();
+ }
+private:
+ std::vector<Elf_Phdr *> _ph;
+ typedef typename std::vector<Elf_Phdr *>::iterator ph_iter;
+ ph_iter _phi;
+ llvm::BumpPtrAllocator _allocator;
+};
+
+/// \brief An ELFSectionHeader represents the Elf[32/64]_Shdr structure
+/// at the end of the file
template<support::endianness target_endianness, bool is64Bits>
-StockSectionChunk<target_endianness, is64Bits>::
- StockSectionChunk(StringRef secName, bool loadable,
- DefinedAtom::ContentType type,
- const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &writer)
- : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL",
- loadable, 0lu, 0lu, 0u, 0lu, 0lu,
- options, writer) {
- this->_segmentName = this->_isLoadable ? "PT_LOAD" : "PT_NULL" ;
- // If the section is custom loadable section, group should be set explicitly.
- // Stock non loadable section go as NO_LOAD and others will get their
- // group determined by the atoms contained within. Many constant
- // sections will have no symbols but the constants are referred as
- // offset from start symbol, hence there may not be any defined atoms being
- // appended to them, we force them at time of creation to CG_R
- this->setGroup(this->isLoadable() ? CG_INVALID : CG_NO_LOAD);
- switch(type) {
- case DefinedAtom::typeCode:
- this->_type = ELF::SHT_PROGBITS;
- break;
- case DefinedAtom::typeData:
- this->_type = ELF::SHT_PROGBITS;
- break;
- case DefinedAtom::typeZeroFill:
- this->_type = ELF::SHT_NOBITS;
- break;
- case DefinedAtom::typeConstant:
- this->_type = ELF::SHT_PROGBITS;
- this->_flags = ELF::SHF_ALLOC;
- this->setGroup(CG_R);
- break;
- default:
- llvm_unreachable("Unhandled content type for section!");
+class ELFSectionHeader : public Chunk<target_endianness, is64Bits> {
+public:
+ typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
+
+ ELFSectionHeader(int32_t order):Chunk<target_endianness, is64Bits>("shdr",
+ Chunk<target_endianness, is64Bits>::SectionHeader)
+ {
+ this->_fsize = 0;
+ this->_align2 = 8;
+ this->setOrder(order);
+ // The first element in the list is always NULL
+ Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+ ::memset(nullshdr, 0, sizeof (Elf_Shdr));
+ _sectionInfo.push_back(nullshdr);
+ this->_fsize += sizeof (Elf_Shdr);
}
-}
-
-template<support::endianness target_endianness, bool is64Bits>
-const ArrayRef<AtomInfo> StockSectionChunk<target_endianness, is64Bits>::
- atoms() const {
- return _atoms;
-}
+ uint16_t filesize() {
+ return sizeof(Elf_Shdr) * _sectionInfo.size();
+ }
-template<support::endianness target_endianness, bool is64Bits>
-void StockSectionChunk<target_endianness, is64Bits>::
- appendAtom(const DefinedAtom *atom) {
- static uint16_t groupArray[] = {CG_INVALID, CG_W, CG_R, CG_RW, CG_X,
- CG_WX, CG_RX, CG_RWX};
- // Figure out offset for atom in this section given alignment constraints.
- uint64_t offset = this->_size;
- DefinedAtom::Alignment atomAlign = atom->alignment();
- uint64_t align2 = 1 << atomAlign.powerOf2;
- uint64_t requiredModulus = atomAlign.modulus;
- uint64_t currentModulus = (offset % align2);
- if (currentModulus != requiredModulus) {
- if (requiredModulus > currentModulus)
- offset += requiredModulus - currentModulus;
- else
- offset += align2 + requiredModulus - currentModulus;
+ void appendSection(MergedSection<target_endianness, is64Bits> *section) {
+ Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
+ shdr->sh_name = _stringSection->addString(section->name());
+ shdr->sh_type = section->type();
+ shdr->sh_flags = section->flags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->startAddr();
+ shdr->sh_size = section->memsize();
+ shdr->sh_link = section->link();
+ shdr->sh_info = section->shinfo();
+ shdr->sh_addralign = section->align2();
+ shdr->sh_entsize = section->entsize();
+ _sectionInfo.push_back(shdr);
}
- // Record max alignment of any atom in this section.
- if (align2 > this->_align2)
- this->_align2 = align2;
- // Assign atom to this section with this offset.
- _atoms.emplace_back(atom, offset);
- // Update section size to include this atom.
- this->_size = offset + atom->size();
- // Update permissions
- DefinedAtom::ContentPermissions perms = atom->permissions();
-
- if ((perms & DefinedAtom::permR__) == DefinedAtom::permR__)
- this->_flags |= ELF::SHF_ALLOC;
- if ((perms & DefinedAtom::permRW_) == DefinedAtom::permRW_)
- this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
- if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
- this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
- if (atom->contentType() == DefinedAtom::typeZeroFill)
- this->_flags |= (ELF::SHF_ALLOC | ELF::SHF_WRITE);
- this->setGroup(groupArray[this->_flags]);
-}
-template<support::endianness target_endianness, bool is64Bits>
-void StockSectionChunk<target_endianness, is64Bits>
- ::write(uint8_t *chunkBuffer) {
- // Each section's content is just its atoms' content.
- for (const auto &ai : _atoms ) {
- // Copy raw content of atom to file buffer.
- ArrayRef<uint8_t> content = std::get<0>(ai)->rawContent();
- uint64_t contentSize = content.size();
- if (contentSize == 0)
- continue;
- uint8_t *atomContent = chunkBuffer + std::get<1>(ai);
- std::copy_n(content.data(), contentSize, atomContent);
+ void updateSection(Section<target_endianness, is64Bits> *section) {
+ Elf_Shdr *shdr = _sectionInfo[section->ordinal()];
+ shdr->sh_type = section->type();
+ shdr->sh_flags = section->flags();
+ shdr->sh_offset = section->fileOffset();
+ shdr->sh_addr = section->startAddr();
+ shdr->sh_size = section->filesize();
+ shdr->sh_link = section->link();
+ shdr->sh_info = section->shinfo();
+ shdr->sh_addralign = section->align2();
+ shdr->sh_entsize = section->entsize();
+ }
- for (const Reference *ref : *std::get<0>(ai)){
- uint32_t offset = ref->offsetInAtom();
- uint64_t targetAddress = 0;
+ static inline bool classof(const Chunk<target_endianness, is64Bits> *c) {
+ return c->getChunkKind() == Chunk<target_endianness, is64Bits>::SectionHeader;
+ }
- if ( ref->target() != nullptr )
- targetAddress = this->_writer.addressOfAtom(ref->target());
+ void setStringSection(ELFStringTable<target_endianness, is64Bits> *s) {
+ _stringSection = s;
+ }
- uint64_t fixupAddress = this->_writer.addressOfAtom(std::get<0>(ai)) +
- offset;
- this->_writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
- &atomContent[offset],
- fixupAddress,
- targetAddress);
+ void write(ELFWriter *writer,
+ OwningPtr<FileOutputBuffer> &buffer) {
+
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ uint8_t *dest = chunkBuffer + this->fileOffset();
+ for (auto shi = _sectionInfo.begin(); shi != _sectionInfo.end(); ++shi) {
+ memcpy(dest, (*shi), sizeof(Elf_Shdr));
+ dest += sizeof(Elf_Shdr);
}
+ _stringSection->write(writer, buffer);
}
-}
-//===----------------------------------------------------------------------===//
-// ELFStringSectionChunk
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFStringSectionChunk<target_endianness, is64Bits>::
- ELFStringSectionChunk(const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &writer,
- StringRef secName)
- : SectionChunk<target_endianness, is64Bits>(secName, "PT_NULL",
- false, 0lu, 0lu, 0lu,
- ELF::SHT_STRTAB, 0lu, options,
- writer) {
- // First Add a null character. It also occupies 1 byte
- _stringSection.emplace_back("");
- this->_size = 1;
- this->setGroup(CG_NO_LOAD);
-}
+ void finalize() { }
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t ELFStringSectionChunk<target_endianness, is64Bits>::
- addString(StringRef symName) {
- _stringSection.emplace_back(symName);
- uint64_t offset = this->_size;
- this->_size += symName.size() + 1;
+ int64_t entsize() {
+ return sizeof(Elf_Shdr);
+ }
- return offset;
-}
-
-// We need to unwrap the _stringSection and then make one large memory
-// chunk of null terminated strings
-template<support::endianness target_endianness, bool is64Bits>
-void ELFStringSectionChunk<target_endianness, is64Bits>::
- write(uint8_t *chunkBuffer) {
- uint64_t chunkOffset = 0;
-
- for (auto it : _stringSection) {
- ::memcpy(chunkBuffer + chunkOffset, it.data(), it.size());
- chunkOffset += it.size();
- ::memcpy(chunkBuffer + chunkOffset, "", 1);
- chunkOffset += 1;
+ int64_t numHeaders() {
+ return _sectionInfo.size();
}
-}
+private:
+ ELFStringTable<target_endianness, is64Bits> *_stringSection;
+ std::vector<Elf_Shdr*> _sectionInfo;
+ llvm::BumpPtrAllocator _sectionAllocate;
+};
+
+
+/// \brief The DefaultELFLayout class is used by the Writer to arrange
+/// sections and segments in the order determined by the target ELF
+/// format. The writer creates a single instance of the DefaultELFLayout
+/// class
template<support::endianness target_endianness, bool is64Bits>
-const char *ELFStringSectionChunk<target_endianness, is64Bits>::info() {
- return "String Table";
-}
+class DefaultELFLayout : public ELFLayout {
+public:
-//===----------------------------------------------------------------------===//
-// ELFSymbolTableChunk
-//===----------------------------------------------------------------------===//
-template< support::endianness target_endianness, bool is64Bits>
-ELFSymbolTableChunk<target_endianness, is64Bits>::ELFSymbolTableChunk
- (const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits> &writer,
- StringRef secName)
- : SectionChunk<target_endianness, is64Bits>(secName, StringRef("PT_NULL"),
- false, 0, 0, 0, ELF::SHT_SYMTAB,
- sizeof(Elf_Sym), options, writer)
-{
- _stringSection = this->_writer.strtab();
- Elf_Sym *symbol = new (_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
- memset ((void *)symbol,0, sizeof(Elf_Sym));
- _symbolTable.push_back(symbol);
- this->_link = 0;
- this->_entsize = sizeof(Elf_Sym);
- this->_size = sizeof(Elf_Sym);
- this->_align2 = this->_options.pointerWidth();
- this->setGroup(CG_NO_LOAD);
-}
+ // The order in which the sections appear in the output file
+ // If its determined, that the layout needs to change
+ // just changing the order of enumerations would essentially
+ // change the layout in the output file
+ enum DefaultSectionOrder {
+ ORDER_NOT_DEFINED = 0,
+ ORDER_INTERP,
+ ORDER_NOTE,
+ ORDER_HASH,
+ ORDER_DYNAMIC_SYMBOLS,
+ ORDER_DYNAMIC_STRINGS,
+ ORDER_INIT,
+ ORDER_TEXT,
+ ORDER_PLT,
+ ORDER_FINI,
+ ORDER_RODATA,
+ ORDER_EH_FRAME,
+ ORDER_EH_FRAMEHDR,
+ ORDER_CTORS,
+ ORDER_DTORS,
+ ORDER_DYNAMIC,
+ ORDER_GOT,
+ ORDER_GOT_PLT,
+ ORDER_DATA,
+ ORDER_BSS,
+ ORDER_OTHER,
+ ORDER_SECTION_STRINGS,
+ ORDER_SYMBOL_TABLE,
+ ORDER_STRING_TABLE,
+ ORDER_SECTION_HEADERS
+ };
-template< support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::fixSymbolValue(){
- for (auto sym : _symbolTable) {
- if ( sym->st_shndx != ELF::SHN_ABS) {
- sym->st_value = this->_writer.addressOfAtom(_symbolToAtom[sym]);
- }
- }
-}
+public:
-template< support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::addSymbol(Elf_Sym *sym){
- _symbolTable.push_back(sym);
- this->_size+= sizeof(Elf_Sym) ;
-}
+ // The Key used for creating Sections
+ // The sections are created using
+ // SectionName, [contentType, contentPermissions]
+ typedef std::pair<StringRef,
+ std::pair<int32_t, int32_t>> Key;
+ typedef typename std::vector<Chunk<target_endianness, is64Bits> *>::iterator
+ chunk_iter;
+ // The key used for Segments
+ // The segments are created using
+ // SegmentName, Segment flags
+ typedef std::pair<StringRef, int64_t> SegmentKey;
+ // Merged Sections contain the map of Sectionnames to a vector of sections,
+ // that have been merged to form a single section
+ typedef std::map<StringRef, MergedSection<target_endianness, is64Bits> *>
+ mergedSectionMap_t;
+ typedef typename std::vector
+ <MergedSection<target_endianness, is64Bits> *>::iterator merged_section_iter;
-/// \brief Add symbols to symbol table
-/// We examine each property of atom to infer the various st_* fields in Elf*_Sym
-template< support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>
- ::addSymbol(const Atom *a, uint16_t shndx) {
- Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
- unsigned char b = 0, t = 0;
- symbol->st_name = _stringSection->addString(a->name());
- _symbolToAtom[symbol] = a;
-// In relocatable files, st_value holds a section offset for a defined symbol.
-// st_value is an offset from the beginning of the section that st_shndx
-// identifies. After we assign file offsets we can set this value correctly.
- symbol->st_size = 0;
- symbol->st_shndx = shndx;
- symbol->st_value = 0;
-// FIXME: Need to change and account all STV* when visibilities are supported
- symbol->st_other = ELF::STV_DEFAULT;
- if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(a)){
- symbol->st_size = da->size();
- lld::DefinedAtom::ContentType ct;
- switch (ct = da->contentType()){
- case DefinedAtom::typeCode:
- t = ELF::STT_FUNC;
- break;
- case DefinedAtom::typeData:
- t = ELF::STT_OBJECT;
- break;
- case DefinedAtom::typeZeroFill:
- // In relocatable files, st_value holds alignment constraints for a symbol whose
- // section index is SHN_COMMON
- if (this->_options.type() == ELF::ET_REL){
- t = ELF::STT_COMMON;
- symbol->st_value = 1 << (da->alignment()).powerOf2;
- symbol->st_shndx = ELF::SHN_COMMON;
- }
- break;
- // TODO:: How to find STT_FILE symbols?
- default:
- t = ELF::STT_NOTYPE;
+ // HashKey for the Section
+ class HashKey {
+ public:
+ int64_t operator() (const Key &k) const {
+ // k.first = section Name
+ // k.second = [contentType, Permissions]
+ return llvm::HashString(k.first) + k.second.first + k.second.second;
}
-
- if (da->scope() == DefinedAtom::scopeTranslationUnit)
- b = ELF::STB_LOCAL;
- else if (da->merge() == DefinedAtom::mergeAsWeak)
- b = ELF::STB_WEAK;
- else
- b = ELF::STB_GLOBAL;
- } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(a)){
-//FIXME: Absolute atoms need more properties to differentiate each other
-// based on binding and type of symbol
- t = ELF::STT_OBJECT;
+ };
- switch (aa->scope()) {
- case AbsoluteAtom::scopeLinkageUnit:
- symbol->st_other = ELF::STV_HIDDEN;
- b = ELF::STB_LOCAL;
- break;
- case AbsoluteAtom::scopeTranslationUnit:
- b = ELF::STB_LOCAL;
- break;
- case AbsoluteAtom::scopeGlobal:
- b = ELF::STB_GLOBAL;
- break;
+ // HashKey for the Segment
+ class SegmentHashKey {
+ public:
+ int64_t operator() (const SegmentKey &k) const {
+ // k.first = SegmentName
+ // k.second = SegmentFlags
+ return llvm::HashString(k.first) + k.second;
}
- symbol->st_value = aa->value();
- } else {
- symbol->st_value = 0;
- t = ELF::STT_NOTYPE;
- b = ELF::STB_LOCAL;
- }
- symbol->setBindingAndType(b, t);
+ };
- _symbolTable.push_back(symbol);
- this->_size += sizeof(Elf_Sym);
-}
+ typedef std::unordered_map<Key,
+ Section<target_endianness, is64Bits>*, HashKey> sectionMap_t;
+ typedef std::unordered_map<SegmentKey,
+ Segment<target_endianness, is64Bits>*,
+ SegmentHashKey> segmentMap_t;
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::setAttributes() {
-// sh_info should be one greater than last symbol with STB_LOCAL binding
-// we sort the symbol table to keep all local symbols at the beginning
- std::stable_sort(_symbolTable.begin(), _symbolTable.end(), ([]
- (const Elf_Sym *A, const Elf_Sym *B) -> bool {
- return (A->getBinding() < B->getBinding());}));
- uint16_t shInfo = 0;
- for (auto i : _symbolTable) {
- if (i->getBinding() != ELF::STB_LOCAL)
- break;
- shInfo++;
- }
- this->_shinfo = shInfo;
-// we set the associated string table index in th sh_link member
- this->_link = this->_writer.strtab()->ordinal() - 1;
- this->_align2 = this->_options.pointerWidth();
-}
+ DefaultELFLayout(const WriterOptionsELF &options):_options(options) { }
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFSymbolTableChunk<target_endianness, is64Bits>::info() {
- return "Symbol Table";
-}
+ /// \brief Return the section order for a input section
+ virtual SectionOrder getSectionOrder(const StringRef name,
+ int32_t contentType,
+ int32_t contentPermissions) {
+ switch (contentType) {
+ case DefinedAtom::typeCode:
+ if (name.startswith(".eh_frame_hdr"))
+ return ORDER_EH_FRAMEHDR;
+ if (name.startswith(".eh_frame"))
+ return ORDER_EH_FRAME;
+ else if (name.startswith(".init"))
+ return ORDER_INIT;
+ else if (name.startswith(".fini"))
+ return ORDER_FINI;
+ else if (name.startswith(".hash"))
+ return ORDER_HASH;
+ else
+ return ORDER_TEXT;
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSymbolTableChunk<target_endianness, is64Bits>::
- write(uint8_t *chunkBuffer) {
- uint64_t chunkOffset = 0;
- for (auto it : _symbolTable) {
- ::memcpy(chunkBuffer + chunkOffset, it, this->_entsize);
- chunkOffset += this->_entsize;
+ case DefinedAtom::typeConstant:
+ return ORDER_RODATA;
+
+ case DefinedAtom::typeData:
+ return ORDER_DATA;
+
+ case DefinedAtom::typeZeroFill:
+ return ORDER_BSS;
+
+ default:
+ // If we get passed in a section push it to OTHER
+ if (contentPermissions == DefinedAtom::perm___)
+ return ORDER_OTHER;
+
+ return ORDER_NOT_DEFINED;
+ }
}
-}
-//===----------------------------------------------------------------------===//
-// ELFHeaderChunk
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFHeaderChunk<target_endianness, is64Bits>
- ::ELFHeaderChunk(const WriterOptionsELF &options,
- const File &File)
- : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
- ::Kind::Header){
- this->_size = size();
- e_ident(ELF::EI_MAG0, 0x7f);
- e_ident(ELF::EI_MAG1, 'E');
- e_ident(ELF::EI_MAG2, 'L');
- e_ident(ELF::EI_MAG3, 'F');
- e_ident(ELF::EI_CLASS, (options.is64Bit() ? ELF::ELFCLASS64
- : ELF::ELFCLASS32));
- e_ident(ELF::EI_DATA, (options.endianness() == llvm::support::big)
- ? ELF::ELFDATA2MSB
- : ELF::ELFDATA2LSB);
- e_ident(ELF::EI_VERSION, 1);
- e_ident(ELF::EI_OSABI, ELF::ELFOSABI_NONE);
+ /// \brief This maps the input sections to the output section names
+ StringRef getSectionName(const StringRef name) {
+ if (name.startswith(".text"))
+ return ".text";
+ if (name.startswith(".rodata"))
+ return ".rodata";
+ return name;
+ }
- e_type(options.type());
- e_machine(options.machine());
- e_version(1);
+ /// \brief Gets the segment for a output section
+ virtual ELFLayout::SegmentType getSegmentType(Section<target_endianness,
+ is64Bits> *section) const {
+ switch(section->order()) {
+ case ORDER_INTERP:
+ return llvm::ELF::PT_INTERP;
- e_entry(0ULL);
- e_phoff(0);
- e_shoff(0ULL);
-
- e_flags(2);
- e_ehsize(this->_size);
- e_phentsize(0);
- e_phnum(0);
- e_shentsize(0);
- e_shnum(0);
- e_shstrndx(0);
- this->setGroup(CG_HEADER);
-}
+ case ORDER_TEXT:
+ case ORDER_HASH:
+ case ORDER_DYNAMIC_SYMBOLS:
+ case ORDER_DYNAMIC_STRINGS:
+ case ORDER_INIT:
+ case ORDER_PLT:
+ case ORDER_FINI:
+ case ORDER_RODATA:
+ case ORDER_EH_FRAME:
+ case ORDER_EH_FRAMEHDR:
+ return llvm::ELF::PT_LOAD;
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFHeaderChunk<target_endianness, is64Bits>
- ::segmentName() const {
- return "ELF";
-}
+ case ORDER_NOTE:
+ return llvm::ELF::PT_NOTE;
-template<support::endianness target_endianness, bool is64Bits>
-void ELFHeaderChunk<target_endianness, is64Bits>
- ::write(uint8_t *chunkBuffer) {
- ::memcpy(chunkBuffer, &_eh, size());
-}
+ case ORDER_DYNAMIC:
+ return llvm::ELF::PT_DYNAMIC;
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFHeaderChunk<target_endianness, is64Bits>::info() {
- return "elf_header";
-}
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ case ORDER_GOT:
+ return llvm::ELF::PT_GNU_RELRO;
-//===----------------------------------------------------------------------===//
-// ELFSectionHeaderChunk
-// List of Section Headers:
-//[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
-//[ 0] NULL 00000000 000000 000000 00 0 0 0
-//[ 1] .text PROGBITS 00000000 000034 000040 00 AX 0 0 4
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFSectionHeaderChunk<target_endianness, is64Bits>
- ::ELFSectionHeaderChunk(const WriterOptionsELF& options,
- ELFWriter<target_endianness,
- is64Bits> &writer)
- : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
- ::Kind::Header)
- , _options(options)
- , _writer(writer) {
- this->_size = 0;
- this->_align2 = 0;
- // The first element in the list is always NULL
- Elf_Shdr *nullshdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
- ::memset(nullshdr, 0, sizeof (Elf_Shdr));
- _sectionInfo.push_back(nullshdr);
- this->_size += sizeof (Elf_Shdr);
- this->setGroup(CG_FILE_END);
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_BSS:
+ return llvm::ELF::PT_LOAD;
+
+ default:
+ return llvm::ELF::PT_NULL;
+ }
}
+ /// \brief Returns true/false depending on whether the section has a Output
+ // segment or not
+ static bool hasOutputSegment(Section<target_endianness,
+ is64Bits> *section) {
+ switch(section->order()) {
+ case ORDER_INTERP:
+ case ORDER_HASH:
+ case ORDER_DYNAMIC_SYMBOLS:
+ case ORDER_DYNAMIC_STRINGS:
+ case ORDER_INIT:
+ case ORDER_PLT:
+ case ORDER_TEXT:
+ case ORDER_FINI:
+ case ORDER_RODATA:
+ case ORDER_EH_FRAME:
+ case ORDER_EH_FRAMEHDR:
+ case ORDER_NOTE:
+ case ORDER_DYNAMIC:
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ case ORDER_GOT:
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_BSS:
+ return true;
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>::computeSize(){
- this->_size = (this->_writer.sectionChunks().size() + 1) * sizeof(Elf_Shdr);
-}
+ default:
+ return false;
+ }
+ }
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>::fixOffsets(){
- auto it = _sectionInfo.begin();
- auto sections = _writer.sectionChunks();
- // First section is a NULL section with no sh_offset fix
- (*it)->sh_offset = 0;
- (*it)->sh_addr = 0;
- ++it;
- for (auto &chunk : sections){
- (*it)->sh_offset = chunk->fileOffset();
- (*it)->sh_addr = chunk->address();
- ++it;
+ // Adds an atom to the section
+ virtual error_code addAtom(const Atom *atom) {
+ const DefinedAtom *definedAtom = dyn_cast<DefinedAtom> (atom);
+ const StringRef sectionName = getSectionName
+ (definedAtom->customSectionName());
+ const lld::DefinedAtom::ContentPermissions permissions =
+ definedAtom->permissions();
+ const lld::DefinedAtom::ContentType contentType =
+ definedAtom->contentType();
+ const Key key(sectionName, std::make_pair(contentType, permissions));
+ const std::pair<Key, Section<target_endianness, is64Bits> *>
+ currentSection(key, nullptr);
+ std::pair<typename sectionMap_t::iterator, bool>
+ sectionInsert(_sectionMap.insert(currentSection));
+ Section<target_endianness, is64Bits> *section;
+ // the section is already in the map
+ if (!sectionInsert.second) {
+ section = sectionInsert.first->second;
+ section->setContentPermissions(permissions);
+ }
+ else {
+ SectionOrder section_order = getSectionOrder(sectionName,
+ contentType,
+ permissions);
+ section = new (_allocator.Allocate
+ <Section<target_endianness, is64Bits>>())
+ Section<target_endianness, is64Bits>
+ (sectionName, contentType,
+ permissions, section_order);
+ sectionInsert.first->second = section;
+ section->setOrder(section_order);
+ _sections.push_back(section);
+ }
+ section->appendAtom(atom);
+ return error_code::success();
}
-}
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>::createHeaders(){
- ELFStringSectionChunk<target_endianness, is64Bits> *str = _writer.shstrtab();
+ // Merge sections with the same name into a MergedSection
+ void mergeSimiliarSections()
+ {
+ MergedSection<target_endianness, is64Bits> *mergedSection;
+
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ const std::pair<StringRef, MergedSection<target_endianness, is64Bits> *>
+ currentMergedSection((*si)->name(),
+ nullptr);
+ std::pair<typename mergedSectionMap_t::iterator, bool>
+ mergedSectionInsert
+ (_mergedSectionMap.insert(currentMergedSection));
+ if (!mergedSectionInsert.second) {
+ mergedSection = mergedSectionInsert.first->second;
+ }
+ else {
+ mergedSection = new (_allocator.Allocate
+ <MergedSection<target_endianness, is64Bits>>())
+ MergedSection<target_endianness, is64Bits>((*si)->name());
+ _mergedSections.push_back(mergedSection);
+ mergedSectionInsert.first->second = mergedSection;
+ }
+ mergedSection->appendSection(*si);
+ }
+ }
- for (const auto &chunk : _writer.sectionChunks()) {
- Elf_Shdr *shdr = new (_sectionAllocate.Allocate<Elf_Shdr>()) Elf_Shdr;
- StringRef Name = chunk->sectionName();
- if (chunk->shStrtableOffset() == 0){
- chunk->setShStrtableOffset(str->addString(Name));
+ void assignSectionsToSegments()
+ {
+ // sort the sections by their order as defined by the layout
+ std::stable_sort(_sections.begin(), _sections.end(), ([]
+ (Chunk<target_endianness, is64Bits> *A,
+ Chunk<target_endianness, is64Bits> *B) ->
+ bool { return (A->order() < B->order());}));
+ // Merge all sections
+ mergeSimiliarSections();
+ // Set the ordinal after sorting the sections
+ int ordinal = 1;
+ for (auto msi = _mergedSections.begin(); msi != _mergedSections.end();
+ ++msi) {
+ (*msi)->setOrdinal(ordinal);
+ for (auto ai = (*msi)->begin_sections(); ai != (*msi)->end_sections();
+ ++ai) {
+ (*ai)->setOrdinal(ordinal);
+ }
+ ++ordinal;
}
- shdr->sh_name = chunk->shStrtableOffset();
+ Section<target_endianness, is64Bits> *section;
+ Segment<target_endianness, is64Bits> *segment;
+ for (auto msi = merged_sections_begin(); msi != merged_sections_end();
+ ++msi) {
+ for (auto ai = (*msi)->begin_sections(); ai != (*msi)->end_sections();
+ ++ai) {
+ if ((*ai)->kind() == Chunk<target_endianness, is64Bits>::Section) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ai);
+ if (!hasOutputSegment(section))
+ continue;
+ (*msi)->setHasSegment();
+ section->setSegment(getSegmentType(section));
+ const StringRef segmentName = section->segmentKindToStr();
+ // Use the flags of the merged Section for the segment
+ const SegmentKey key(segmentName, (*msi)->flags());
+ const std::pair<SegmentKey, Segment<target_endianness, is64Bits> *>
+ currentSegment(key, nullptr);
+ std::pair<typename segmentMap_t::iterator, bool>
+ segmentInsert(_segmentMap.insert(currentSegment));
- shdr->sh_type = chunk->type();
- shdr->sh_flags = chunk->flags();
- // TODO: At the time of creation of this section header, we will not have
- // any address and offset info. We revisit this after assigning the file
- // offsets.
- shdr->sh_offset = chunk->fileOffset();
- shdr->sh_addr = chunk->address();
- shdr->sh_size = chunk->size();
- shdr->sh_link = chunk->link() ;
- shdr->sh_info = chunk->shinfo();
- shdr->sh_addralign = chunk->align2();
- shdr->sh_entsize = chunk->entsize();
+ if (!segmentInsert.second) {
+ segment = segmentInsert.first->second;
+ }
+ else {
+ segment = new (_allocator.Allocate
+ <Segment<target_endianness, is64Bits>>())
+ Segment<target_endianness, is64Bits>
+ (segmentName, getSegmentType(section),
+ _options);
+ segmentInsert.first->second = segment;
+ _segments.push_back(segment);
+ }
+ segment->append(section);
+ }
+ }
+ }
+ }
- _sectionInfo.push_back(shdr);
- this->_size += sizeof (Elf_Shdr);
- _writer.symtab()->setAttributes();
+ void addSection(Chunk<target_endianness, is64Bits> *c) {
+ _sections.push_back(c);
}
-}
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFSectionHeaderChunk<target_endianness, is64Bits>
- ::segmentName() const {
- return "PT_NULL";
-}
-
-template<support::endianness target_endianness, bool is64Bits>
-void ELFSectionHeaderChunk<target_endianness, is64Bits>
- ::write(uint8_t *chunkBuffer) {
- for (const auto si : _sectionInfo) {
- ::memcpy(chunkBuffer, si, sizeof(*si));
- chunkBuffer += sizeof (*si);
+ void findSectionByOrder(chunk_iter *chunk, DefaultSectionOrder s) {
+ for (auto ai = sections_begin(); ai != sections_end(); ++ai) {
+ if ((*ai)->order() == s) {
+ chunk = *ai;
+ return;
+ }
+ }
+ chunk = sections_end();
}
-}
+ void findSectionByName(chunk_iter *chunk, StringRef s) {
+ for (auto ai = sections_begin(); ai != sections_end(); ++ai) {
+ if ((*ai)->name() == s) {
+ chunk = *ai;
+ return;
+ }
+ }
+ chunk = sections_end();
+ }
-template<support::endianness target_endianness, bool is64Bits>
-uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::count() {
- return _sectionInfo.size();
-}
-template<support::endianness target_endianness, bool is64Bits>
-uint16_t ELFSectionHeaderChunk<target_endianness, is64Bits>::size() {
- return sizeof (Elf_Shdr);
-}
+ void assignFileOffset() {
+ Segment<target_endianness, is64Bits> *segment;
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
- return "elf_section_header";
-}
+ std::sort(_segments.begin(), _segments.end(),
+ Segment<target_endianness, is64Bits>::compare_segments);
+ int ordinal = 0;
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ segment = llvm::dyn_cast<Segment<target_endianness, is64Bits>>(*si);
+ segment->setOrdinal(++ordinal);
+ }
+ // Compute the number of segments that might be needed, so that the
+ // size of the program header can be computed
+ int64_t offset = 0;
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ segment = llvm::dyn_cast<Segment<target_endianness, is64Bits>>(*si);
+ segment->assignOffset(offset);
+ offset += segment->filesize();
+ }
+ }
-//===----------------------------------------------------------------------===//
-// ELFProgramHeaderChunk
-//===----------------------------------------------------------------------===//
-template<support::endianness target_endianness, bool is64Bits>
-ELFProgramHeaderChunk<target_endianness, is64Bits>
- ::ELFProgramHeaderChunk(const WriterOptionsELF &options,
- ELFWriter<target_endianness, is64Bits>
- &writer)
- : Chunk<target_endianness, is64Bits>(Chunk<target_endianness, is64Bits>
- ::Kind::Header)
- , _options(options)
- , _writer(writer) {
- this->_align2 = 0;
- this->setGroup(CG_HEADER);
- _groupToPF[CG_RWX] = ELF::PF_R | ELF::PF_W | ELF::PF_X;
- _groupToPF[CG_RW] = ELF::PF_R | ELF::PF_W;
- _groupToPF[CG_RX] = ELF::PF_R | ELF::PF_X;
- _groupToPF[CG_R] = ELF::PF_R;
- _groupToPF[CG_W] = ELF::PF_W;
- _groupToPF[CG_WX] = ELF::PF_W | ELF::PF_X;
- _groupToPF[CG_X] = ELF::PF_X;
+ void setELFHeader(ELFHeader<target_endianness, is64Bits> *e) {
+ _elfHeader = e;
}
-template<support::endianness target_endianness, bool is64Bits>
-void ELFProgramHeaderChunk<target_endianness, is64Bits>::createPHeaders() {
+ void setProgramHeader(ELFProgramHeader<target_endianness, is64Bits> *p) {
+ _programHeader = p;
+ }
- //TODO Once dynamic linking is supported, implement PHDR segment
- // Implement mechanism inside this class to correctly find
- // attributes for sections such as eh_frame, note etc
- // when they are supported.
- const uint16_t seg[] = { CG_RWX, CG_RX, CG_R, CG_RW, CG_WX, CG_W, CG_X };
- std::pair<secIterator, secIterator> sectionPair;
- auto sections = _writer.sectionChunks();
- _programHeaders.clear();
- this->_size = 0;
- for (auto group : seg) {
- uint64_t size = 0, mSize = 0;
- sectionPair = std::equal_range(sections.begin(), sections.end(),
- group, ChunkComparator<target_endianness,
- is64Bits>());
- if (sectionPair.first != sectionPair.second) {
- // FIXME: fix occupiesNoDiskSpace() function in Chunks class
- auto segBegin = sectionPair.first, segEnd = segBegin + 1;
- // Since this group has a section, atleast this is a part of segment
- size = (*segBegin)->occupiesNoDiskSpace() ? 0 : (*segBegin)->size();
- mSize = (*segBegin)->size();
+ void assignVirtualAddress() {
+ int32_t numSlices = 0;
+ int64_t startAddress = _options.baseAddress();
- for (; segEnd != sectionPair.second; segEnd++) {
- // This means there are more than 1 sections of same permissions
- if ((*segEnd)->fileOffset() - (*segBegin)->fileOffset() - size >
- _options.pageSize()) {
- // we have a case where padding zeros span more than a page
- // we can skip those pages.
- Elf_Phdr *phdr = new(_headerAllocate.Allocate<Elf_Phdr>()) Elf_Phdr;
- phdr->p_type = ELF::PT_LOAD;
- phdr->p_offset = (*segBegin)->fileOffset();
- phdr->p_vaddr = (*segBegin)->address();
- phdr->p_paddr = phdr->p_vaddr;
- phdr->p_filesz = size;
- // memory size may be more than file size if there are sections
- // that do not occupy space on disk such as .bss
- phdr->p_memsz = mSize;
- phdr->p_flags = _groupToPF[group];
- phdr->p_align = _options.pageSize();
- _programHeaders.push_back(phdr);
- this->_size += sizeof(Elf_Phdr);
- segBegin = segEnd;
- size = (*segBegin)->occupiesNoDiskSpace() ? 0 : (*segBegin)->size();
- mSize = (*segBegin)->size();
- } else {
- size = (*segEnd)->fileOffset() - (*segBegin)->fileOffset() +
- ((*segEnd)->occupiesNoDiskSpace() ? 0 : (*segEnd)->size()) ;
- mSize = (*segEnd)->fileOffset() - (*segBegin)->fileOffset() +
- (*segEnd)->size();
+ // Add the ELF Header
+ if (_elfHeader) {
+ _elfHeader->setFileOffset(0);
+ _elfHeader->setStart(startAddress);
+ }
+ // Add the program header
+ if (_programHeader) {
+ _programHeader->setStart(int64_t(startAddress + _elfHeader->filesize()));
+ _programHeader->setFileOffset(_elfHeader->filesize());
+ }
+ Segment<target_endianness, is64Bits> *segment;
+ bool newSegmentHeaderAdded = true;
+ while (true) {
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ segment = llvm::dyn_cast<Segment<target_endianness, is64Bits>>(*si);
+ newSegmentHeaderAdded = _programHeader->addSegment(segment);
+ numSlices += segment->numSlices();
+ }
+ if (!newSegmentHeaderAdded)
+ break;
+ int64_t fileoffset = _elfHeader->filesize() + _programHeader->filesize();
+ int64_t address = startAddress;
+ // Fix the offsets after adding the program header
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ segment = llvm::dyn_cast<Segment<target_endianness, is64Bits>>(*si);
+ // Align the segment to a page boundary
+ fileoffset = Chunk<target_endianness, is64Bits>::alignTo(fileoffset,
+ _options.pageSize());
+ segment->assignOffset(fileoffset);
+ fileoffset = segment->fileOffset() + segment->filesize();
+ }
+ // start assigning virtual addresses
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ segment = llvm::dyn_cast<Segment<target_endianness, is64Bits>>(*si);
+ segment->setStart(startAddress);
+ // The first segment has the startAddress set to the base address
+ // as we have added the file header and the program header
+ // dont align the first segment to the pagesize
+ // TODO: check in addition to this, that the first segment is a load
+ // segment, only load segments have the addresses aligned
+ segment->assignVirtualAddress(address, (si == _segments.begin()));
+ segment->setMemSize(address - startAddress);
+ startAddress = Chunk<target_endianness, is64Bits>::alignTo(address,
+ _options.pageSize());
+ }
+ _programHeader->resetProgramHeaders();
+ }
+ Section<target_endianness, is64Bits> *section;
+ // Fix the offsets of all the atoms within a section
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+ if (section && DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment(section))
+ section->assignOffset(section->fileOffset());
+ }
+ // Set the size of the merged Sections
+ for (auto msi = merged_sections_begin(); msi != merged_sections_end(); ++msi) {
+ int64_t sectionfileoffset = 0;
+ int64_t startFileOffset = 0;
+ int64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si = (*msi)->begin_sections(); si != (*msi)->end_sections(); ++si) {
+ if (isFirstSection) {
+ startFileOffset = (*si)->fileOffset();
+ isFirstSection = false;
}
+ sectionfileoffset = (*si)->fileOffset();
+ sectionsize = (*si)->filesize();
}
+ sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
+ (*msi)->setFileOffset(startFileOffset);
+ (*msi)->setSize(sectionsize);
+ }
+ // Set the virtual addr of the merged Sections
+ for (auto msi = merged_sections_begin(); msi != merged_sections_end(); ++msi) {
+ int64_t sectionstartaddr = 0;
+ int64_t startaddr = 0;
+ int64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si = (*msi)->begin_sections(); si != (*msi)->end_sections(); ++si) {
+ if (isFirstSection) {
+ startaddr = (*si)->startAddr();
+ isFirstSection = false;
+ }
+ sectionstartaddr = (*si)->startAddr();
+ sectionsize = (*si)->memsize();
+ }
+ sectionsize = (sectionstartaddr - startaddr) + sectionsize;
+ (*msi)->setMemSize(sectionsize);
+ (*msi)->setAddr(startaddr);
+ }
+ }
- Elf_Phdr *phdr = new(_headerAllocate.Allocate<Elf_Phdr>()) Elf_Phdr;
- phdr->p_type = ELF::PT_LOAD;
- phdr->p_offset = (*segBegin)->fileOffset();
- phdr->p_vaddr = (*segBegin)->address();
- phdr->p_paddr = phdr->p_vaddr;
- phdr->p_filesz = size;
- phdr->p_memsz = mSize;
- phdr->p_flags = _groupToPF[group];
- phdr->p_align = _options.pageSize();
- _programHeaders.push_back(phdr);
- this->_size += sizeof(Elf_Phdr);
+ void assignOffsetsForMiscSections() {
+ int64_t fileoffset = 0;
+ int64_t size = 0;
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ fileoffset = (*si)->fileOffset();
+ size = (*si)->filesize();
}
+ fileoffset = fileoffset + size;
+ Section<target_endianness, is64Bits> *section;
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+ if (section &&
+ DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment
+ (section))
+ continue;
+ fileoffset = Chunk<target_endianness, is64Bits>::alignTo(fileoffset,
+ (*si)->align2());
+ (*si)->setFileOffset(fileoffset);
+ (*si)->setStart(0);
+ fileoffset += (*si)->filesize();
+ }
}
-}
-template<support::endianness target_endianness, bool is64Bits>
-uint64_t ELFProgramHeaderChunk<target_endianness, is64Bits>::computeNumber() {
- return _programHeaders.size();
-}
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFProgramHeaderChunk<target_endianness, is64Bits>::info() {
- return "elf_program_header";
-}
+ void finalize() {
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ (*si)->finalize();
+ }
+ }
-template<support::endianness target_endianness, bool is64Bits>
-void ELFProgramHeaderChunk<target_endianness, is64Bits>
- ::write(uint8_t *chunkBuffer) {
- for (const auto si : _programHeaders) {
- ::memcpy(chunkBuffer, si, sizeof(*si));
- chunkBuffer += sizeof (*si);
+ bool findAtomAddrByName(const StringRef name, int64_t &addr) {
+ Section<target_endianness, is64Bits> *section;
+ for (auto ai = _sections.begin(); ai != _sections.end(); ++ai) {
+ if ((*ai)->kind() == Chunk<target_endianness, is64Bits>::Section) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ai);
+ if (section->findAtomAddrByName(name, addr))
+ return true;
+ }
+ }
+ return false;
}
-}
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFProgramHeaderChunk<target_endianness, is64Bits>
- ::segmentName() const {
- return "PT_NULL";
-}
+
+ merged_section_iter merged_sections_begin() {
+ return _mergedSections.begin();
+ }
+
+ merged_section_iter merged_sections_end() {
+ return _mergedSections.end();
+ }
+
+ chunk_iter sections_begin() {
+ return _sections.begin();
+ }
+ chunk_iter sections_end() {
+ return _sections.end();
+ }
+
+ chunk_iter segments_begin() {
+ return _segments.begin();
+ }
+
+ chunk_iter segments_end() {
+ return _segments.end();
+ }
+
+ ELFHeader<target_endianness, is64Bits> *elfHeader() {
+ return _elfHeader;
+ }
+
+ ELFProgramHeader<target_endianness, is64Bits> *elfProgramHeader() {
+ return _programHeader;
+ }
+
+private:
+ sectionMap_t _sectionMap;
+ mergedSectionMap_t _mergedSectionMap;
+ segmentMap_t _segmentMap;
+
+ std::vector<Chunk<target_endianness, is64Bits> *> _sections;
+ std::vector<Chunk<target_endianness, is64Bits> *> _segments;
+ std::vector<MergedSection<target_endianness, is64Bits> *> _mergedSections;
+ ELFHeader<target_endianness, is64Bits> *_elfHeader;
+ ELFProgramHeader<target_endianness, is64Bits> *_programHeader;
+ llvm::BumpPtrAllocator _allocator;
+ const WriterOptionsELF &_options;
+};
+
//===----------------------------------------------------------------------===//
-// ELFWriter Class
+// ELFExecutableWriter Class
//===----------------------------------------------------------------------===//
template<support::endianness target_endianness, bool is64Bits>
-class ELFWriter : public Writer {
+class ELFExecutableWriter : public ELFWriter {
public:
- LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
typedef object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
typedef object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
- typedef object::Elf_Phdr<target_endianness, is64Bits> Elf_Phdr;
- ELFWriter(const WriterOptionsELF &options);
+
+ ELFExecutableWriter(const WriterOptionsELF &options);
+
+private:
+ // build the sections that need to be created
+ void buildChunks(const lld::File &file);
virtual error_code writeFile(const lld::File &File, StringRef path);
- uint64_t addressOfAtom(const Atom *atom);
+ void buildAtomToAddressMap();
+ void buildSymbolTable ();
+ void buildSectionHeaderTable();
+ void assignSectionsWithNoSegments();
+ void addAbsoluteUndefinedSymbols(const lld::File &File);
- std::vector<Chunk<target_endianness, is64Bits>*> chunks() const {
- return _chunks; }
+ int64_t addressOfAtom(const Atom *atom) {
+ return _atomToAddressMap[atom];
+ }
KindHandler *kindHandler() { return _referenceKindHandler.get(); }
-
- std::vector<SectionChunk<target_endianness, is64Bits>*> sectionChunks() const {
- return _sectionChunks ;
- }
-
- ELFStringSectionChunk<target_endianness, is64Bits> *shstrtab() const {
- return _shstrtable;
- }
-
- ELFStringSectionChunk<target_endianness, is64Bits> *strtab() const {
- return _strtable;
- }
- ELFSymbolTableChunk<target_endianness, is64Bits> *symtab() const {
- return _symtable;
- }
-private:
- void build(const lld::File &file);
- void createChunks(const lld::File &file);
- void buildAtomToAddressMap();
- void assignFileOffsets();
+ void createDefaultSections();
+
const WriterOptionsELF &_options;
-/// \brief AtomToAddress: Is a mapping from an Atom to the address where
-/// it will live in the output file.
- typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
- typedef typename std::vector<Chunk<target_endianness, is64Bits>*>
- ::iterator chunkIterator;
- ELFProgramHeaderChunk<target_endianness, is64Bits> *_phdr;
- ELFHeaderChunk<target_endianness, is64Bits> *ehc;
- ELFStringSectionChunk<target_endianness, is64Bits> *_shstrtable ;
- ELFStringSectionChunk<target_endianness, is64Bits> *_strtable ;
- ELFSymbolTableChunk<target_endianness, is64Bits> *_symtable;
+ typedef llvm::DenseMap<const Atom*, int64_t> AtomToAddress;
std::unique_ptr<KindHandler> _referenceKindHandler;
- ELFSectionHeaderChunk<target_endianness, is64Bits> *_sectionHeaderChunk;
- AtomToAddress _atomToAddress;
- std::vector<Chunk<target_endianness, is64Bits>*> _chunks;
- const DefinedAtom *_entryAtom;
- std::vector<SectionChunk<target_endianness, is64Bits>*> _sectionChunks;
- std::vector<StockSectionChunk<target_endianness, is64Bits>*>
- _stockSectionChunks;
+ AtomToAddress _atomToAddressMap;
llvm::BumpPtrAllocator _chunkAllocate;
+ DefaultELFLayout<target_endianness, is64Bits> *_layout;
+ ELFHeader<target_endianness, is64Bits> *_elfHeader;
+ ELFProgramHeader<target_endianness, is64Bits> *_programHeader;
+ ELFSymbolTable<target_endianness, is64Bits> * _symtab;
+ ELFStringTable<target_endianness, is64Bits> *_strtab;
+ ELFStringTable<target_endianness, is64Bits> *_shstrtab;
+ ELFSectionHeader<target_endianness, is64Bits> *_shdrtab;
};
//===----------------------------------------------------------------------===//
-// ELFWriter
+// ELFExecutableWriter
//===----------------------------------------------------------------------===//
template<support::endianness target_endianness, bool is64Bits>
-ELFWriter<target_endianness, is64Bits>
- ::ELFWriter(const WriterOptionsELF &options)
+ELFExecutableWriter<target_endianness, is64Bits>
+ ::ELFExecutableWriter(const WriterOptionsELF &options)
: _options(options)
, _referenceKindHandler(KindHandler::makeHandler(_options.machine(),
target_endianness))
-{}
+{
+ _layout = new DefaultELFLayout<target_endianness, is64Bits>(options);
+}
template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>::build(const lld::File &file){
-// Create objects for each chunk.
- createChunks(file);
- assignFileOffsets();
- _phdr->createPHeaders();
- _sectionHeaderChunk->createHeaders();
- // Creating program headers changed its size. so we need to re-assign offsets
- assignFileOffsets();
- _sectionHeaderChunk->fixOffsets();
- _phdr->createPHeaders();
- buildAtomToAddressMap();
- _symtable->fixSymbolValue();
- ehc->e_shentsize(_sectionHeaderChunk->size());
- ehc->e_shnum(_sectionHeaderChunk->count());
- // We need to put the index of section string table in ELF header
- // first two chunks are not sections so we subtract 2 to start sections
- // and add 1 since we have a NULL header
- ehc->e_shstrndx(_shstrtable->ordinal() - 1);
- ehc->e_phnum(_phdr->computeNumber());
- ehc->e_phoff(_phdr->fileOffset());
- ehc->e_phentsize(sizeof(Elf_Phdr));
- for (auto i : _stockSectionChunks) {
- if(const DefinedAtom* da = findDefinedAtomByName(_options.entryPoint(), i)) {
- ehc->e_entry(this->addressOfAtom(da));
- return;
- }
+void ELFExecutableWriter<target_endianness, is64Bits>::buildChunks
+ (const lld::File &file){
+ for (const DefinedAtom *definedAtom : file.defined() ) {
+ _layout->addAtom(definedAtom);
}
}
template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>
- ::createChunks (const lld::File &file) {
- std::map<StringRef, StockSectionChunk<target_endianness, is64Bits>*>
- sectionMap;
-
-// Make header chunk
- ehc = new (_chunkAllocate.Allocate
- <ELFHeaderChunk<target_endianness, is64Bits>>())
- ELFHeaderChunk<target_endianness, is64Bits>(_options, file);
- _chunks.push_back(ehc);
-
- _phdr = new (_chunkAllocate.Allocate
- <ELFProgramHeaderChunk<target_endianness, is64Bits>>())
- ELFProgramHeaderChunk<target_endianness, is64Bits>(_options,
- *this);
- _chunks.push_back(_phdr);
-
-// We need to create hand crafted sections such as shstrtab strtab hash and
-// symtab to put relevant information in ELF structures and then process the
-// atoms.
-
- _shstrtable = new (_chunkAllocate.Allocate
- <ELFStringSectionChunk<target_endianness, is64Bits>>())
- ELFStringSectionChunk<target_endianness, is64Bits>
- (_options, *this, ".shstrtab");
- _shstrtable->setShStrtableOffset(_shstrtable->addString(".shstrtab"));
- _sectionChunks.push_back(_shstrtable);
-
- _strtable = new (_chunkAllocate.Allocate
- <ELFStringSectionChunk<target_endianness, is64Bits>>())
- ELFStringSectionChunk<target_endianness, is64Bits>
- (_options, *this, ".strtab");
- _strtable->setShStrtableOffset( _shstrtable->addString(".strtab"));
- _sectionChunks.push_back(_strtable);
-
- _symtable = new (_chunkAllocate.Allocate
- <ELFSymbolTableChunk<target_endianness, is64Bits>>())
- ELFSymbolTableChunk<target_endianness, is64Bits>
- (_options, *this, ".symtab");
- _symtable->setShStrtableOffset( _shstrtable->addString(".symtab"));
- _sectionChunks.push_back(_symtable);
-
-//TODO: implement .hash section
-
- DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
- << "Atoms in file" << file.path()<<":\n");
- for (const DefinedAtom *a : file.defined() ) {
- DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
- << a->name() << " type: " << a->contentType() <<"\n");
- StringRef sectionName = a->customSectionName();
- if (a->sectionChoice() ==
- DefinedAtom::SectionChoice::sectionBasedOnContent) {
- if (a->contentType() == DefinedAtom::typeZeroFill)
- sectionName = ".bss";
+void ELFExecutableWriter<target_endianness, is64Bits>::buildSymbolTable () {
+ Section<target_endianness, is64Bits> *section;
+ for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si) {
+ if ((*si)->kind() != Chunk<target_endianness, is64Bits>::Section)
+ continue;
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+ for (auto ai = section->atoms_begin(); ai != section->atoms_end(); ++ai) {
+ _symtab->addSymbol(ai->first, section->ordinal(), ai->second.second);
}
- auto pos = sectionMap.find(sectionName);
- DefinedAtom::ContentType type = a->contentType();
- if (type != DefinedAtom::typeUnknown){
- if (pos == sectionMap.end()) {
- StockSectionChunk<target_endianness, is64Bits>
- *chunk = new(_chunkAllocate.Allocate
- <StockSectionChunk<target_endianness, is64Bits>>
- ())StockSectionChunk<target_endianness, is64Bits>
- (sectionName, true, type, _options, *this);
-
- sectionMap[sectionName] = chunk;
- chunk->appendAtom(a);
- _sectionChunks.push_back(chunk);
- _stockSectionChunks.push_back(chunk);
-
- } else {
- pos->second->appendAtom(a);
- }
- }
}
+}
- for (auto chnk : _sectionChunks)
- _chunks.push_back(chnk);
-
- _sectionHeaderChunk = new (_chunkAllocate.Allocate<ELFSectionHeaderChunk
- <target_endianness, is64Bits>>())
- ELFSectionHeaderChunk
- <target_endianness, is64Bits>(_options, *this);
- _chunks.push_back(_sectionHeaderChunk);
- // We sort the chunks based on the group they belong to
- std::stable_sort(_chunks.begin(), _chunks.end(),
- chunkGroupSort<target_endianness, is64Bits>);
-
- // The CG_RW group also has to be arranged such that all
- // SHT_NOBITS type of sections (.*bss) are at end of this
- // "partition" of group.
- chunkIterator cI;
- std::pair<chunkIterator, chunkIterator> range;
- range = std::equal_range(_chunks.begin() + 2, _chunks.end() - 1, CG_RW,
- ChunkComparator<target_endianness, is64Bits>());
-
- cI = std::stable_partition(range.first, range.second,
- IsBss<target_endianness, is64Bits>);
-
- // We reassign all the ordinals since its needed when making headers and
- // populating symbol table.
- uint64_t i = 0;
- for (auto chnk : _chunks) {
- chnk->setOrdinal(i++);
- }
-
- // We sort the sections as per new ordinal set after group sorting.
- std::stable_sort(_sectionChunks.begin(), _sectionChunks.end(),([]
- (const SectionChunk<target_endianness, is64Bits> *A,
- const SectionChunk<target_endianness, is64Bits> *B) -> bool {
- return A->ordinal() < B->ordinal();}));
-
- // Populate symbol table with correct st_shndx member.
- for (auto chnk : _sectionChunks ) {
- Elf_Sym *sym = new (_chunkAllocate.Allocate<Elf_Sym>()) Elf_Sym;
- sym->st_name = 0;
- sym->st_value = 0;
- sym->st_size = 0;
- sym->st_other = ELF::STV_DEFAULT;
- // first two chunks are not sections hence we subtract 2 but there is a
- // NULL section in section table so add 1
- sym->st_shndx = chnk->ordinal() - 1 ;
- sym->setBindingAndType(ELF::STB_LOCAL, ELF::STT_SECTION);
- _symtable->addSymbol(sym);
- }
- for (const auto ssc : _stockSectionChunks){
- for (const auto da : ssc->atoms()) {
- _symtable->addSymbol(std::get<0>(da), ssc->ordinal() -1);
- }
- }
+template<support::endianness target_endianness, bool is64Bits>
+void ELFExecutableWriter<target_endianness, is64Bits>::
+ addAbsoluteUndefinedSymbols(const lld::File &file) {
for (const UndefinedAtom *a : file.undefined()) {
- _symtable->addSymbol(a, ELF::SHN_UNDEF);
+ _symtab->addSymbol(a, ELF::SHN_UNDEF);
}
for (const AbsoluteAtom *a : file.absolute()) {
- _symtable->addSymbol(a, ELF::SHN_ABS);
+ _symtab->addSymbol(a, ELF::SHN_ABS);
}
}
template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>
+void ELFExecutableWriter<target_endianness, is64Bits>
::buildAtomToAddressMap () {
-
-// _atomToAddress is a DenseMap that maps an atom its file address.
-// std::get<1>(ai) is the offset from the start of the section to the atom.
- for (auto chunk : _stockSectionChunks){
- for (auto &ai : chunk->atoms() ) {
- _atomToAddress[std::get<0>(ai)] = chunk->address() + std::get<1>(ai);
+ Section<target_endianness, is64Bits> *section;
+ for (auto si = _layout->sections_begin();
+ si != _layout->sections_end(); ++si) {
+ if ((*si)->kind() != Chunk<target_endianness, is64Bits>::Section)
+ continue;
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+ for (auto ai = section->atoms_begin(); ai != section->atoms_end(); ++ai) {
+ _atomToAddressMap[ai->first] = (ai)->second.second;
}
}
}
template<support::endianness target_endianness, bool is64Bits>
-void ELFWriter<target_endianness, is64Bits>::assignFileOffsets() {
- DEBUG_WITH_TYPE("WriterELF-layout", dbgs()
- << "assign file offsets:\n");
- uint64_t offset = 0;
- uint64_t address = _options.type() == ELF::ET_REL ? 0 :
- _options.baseAddress();
- uint16_t chunkGroup;
- auto chunkIt = _chunks.begin();
- // first (two in case of ET_EXEC or ET_DYN) chunks is (are) not section(s)
- (*chunkIt)->assignFileOffset(offset, address);
- chunkIt++;
- if (_options.type() == ELF::ET_EXEC ||
- _options.type() == ELF::ET_DYN) {
- (*chunkIt)->assignFileOffset(offset, address);
- chunkIt++;
+void ELFExecutableWriter<target_endianness, is64Bits>
+ ::buildSectionHeaderTable() {
+ for (auto msi = _layout->merged_sections_begin();
+ msi != _layout->merged_sections_end(); ++msi) {
+ if ((*msi)->kind() != Chunk<target_endianness, is64Bits>::Section)
+ continue;
+ if ((*msi)->hasSegment())
+ _shdrtab->appendSection(*msi);
}
- while (chunkIt != (_chunks.end() - 1) ) {
- (*chunkIt)->assignFileOffset(offset, address);
- if (_options.type() == ELF::ET_EXEC ||
- _options.type() == ELF::ET_DYN) {
- chunkGroup = (*chunkIt)->group();
- chunkIt++;
- // If the chunk group changes we start on new page
- if (chunkGroup != (*chunkIt)->group() && (*chunkIt)->group() != CG_NO_LOAD
- && (*chunkIt)->group() != CG_FILE_END)
- address = address + _options.pageSize();
- } else {
- chunkIt++;
- }
+}
+
+template<support::endianness target_endianness, bool is64Bits>
+void ELFExecutableWriter<target_endianness, is64Bits>
+ ::assignSectionsWithNoSegments() {
+ Section<target_endianness, is64Bits> *section;
+ for (auto msi = _layout->merged_sections_begin();
+ msi != _layout->merged_sections_end(); ++msi) {
+ if ((*msi)->kind() != Chunk<target_endianness, is64Bits>::Section)
+ continue;
+ if (!(*msi)->hasSegment())
+ _shdrtab->appendSection(*msi);
}
- (*chunkIt)->assignFileOffset(offset, address);
- ehc->e_shoff(_sectionHeaderChunk->fileOffset());
+ _layout->assignOffsetsForMiscSections();
+ for (auto si = _layout->sections_begin();
+ si != _layout->sections_end(); ++si) {
+ if ((*si)->kind() != Chunk<target_endianness, is64Bits>::Section)
+ continue;
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*si);
+ if (!DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment
+ (section))
+ _shdrtab->updateSection(section);
+ }
}
template<support::endianness target_endianness, bool is64Bits>
-error_code ELFWriter<target_endianness, is64Bits>
+error_code ELFExecutableWriter<target_endianness, is64Bits>
::writeFile(const lld::File &file, StringRef path) {
- build(file);
+ buildChunks(file);
+ // Create the default sections like the symbol table, string table, and the
+ // section string table
+ createDefaultSections();
- uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
+ // Set the Layout
+ _layout->assignSectionsToSegments();
+ _layout->assignFileOffset();
+ _layout->assignVirtualAddress();
+ // Build the Atom To Address map for applying relocations
+ buildAtomToAddressMap();
+
+ // Create symbol table and section string table
+ buildSymbolTable();
+
+ // add other symbols
+ addAbsoluteUndefinedSymbols(file);
+
+ // Finalize the layout by calling the finalize() functions
+ _layout->finalize();
+
+ // build Section Header table
+ buildSectionHeaderTable();
+
+ // assign Offsets and virtual addresses
+ // for sections with no segments
+ assignSectionsWithNoSegments();
+
+ uint64_t totalSize = _shdrtab->fileOffset() + _shdrtab->filesize();
+
OwningPtr<FileOutputBuffer> buffer;
error_code ec = FileOutputBuffer::create(path,
totalSize, buffer,
@@ -1417,28 +2134,80 @@
if (ec)
return ec;
- for (auto chunk : _chunks) {
- chunk->write(buffer->getBufferStart() + chunk->fileOffset());
- }
+ for (auto si = _layout->sections_begin(); si != _layout->sections_end(); ++si)
+ (*si)->write(this, buffer);
+
+ _elfHeader->e_ident(ELF::EI_CLASS, (_options.is64Bit() ? ELF::ELFCLASS64
+ : ELF::ELFCLASS32));
+ _elfHeader->e_ident(ELF::EI_DATA, (_options.endianness() == llvm::support::big)
+ ? ELF::ELFDATA2MSB : ELF::ELFDATA2LSB);
+ _elfHeader->e_ident(ELF::EI_VERSION, 1);
+ _elfHeader->e_ident(ELF::EI_OSABI, 0);
+ _elfHeader->e_type(_options.type());
+ _elfHeader->e_machine(_options.machine());
+ _elfHeader->e_version(1);
+ _elfHeader->e_entry(0ULL);
+ _elfHeader->e_phoff(_programHeader->fileOffset());
+ _elfHeader->e_shoff(_shdrtab->fileOffset());
+ _elfHeader->e_phentsize(_programHeader->entsize());
+ _elfHeader->e_phnum(_programHeader->numHeaders());
+ _elfHeader->e_shentsize(_shdrtab->entsize());
+ _elfHeader->e_shnum(_shdrtab->numHeaders());
+ _elfHeader->e_shstrndx(_shstrtab->ordinal());
+ int64_t startAddr = 0;
+ _layout->findAtomAddrByName("_start", startAddr);
+ _elfHeader->e_entry(startAddr);
+ _elfHeader->write(this, buffer);
+ _programHeader->write(this, buffer);
+
return buffer->commit();
+
+ return error_code::success();
}
template<support::endianness target_endianness, bool is64Bits>
-uint64_t ELFWriter<target_endianness, is64Bits>
- ::addressOfAtom(const Atom *atom) {
- return _atomToAddress[atom];
+void ELFExecutableWriter<target_endianness, is64Bits>
+ ::createDefaultSections() {
+ _elfHeader = new ELFHeader<target_endianness, is64Bits>();
+ _programHeader = new ELFProgramHeader<target_endianness, is64Bits>();
+ _layout->setELFHeader(_elfHeader);
+ _layout->setProgramHeader(_programHeader);
+
+ _symtab = new ELFSymbolTable<target_endianness, is64Bits>
+ (".symtab",
+ DefaultELFLayout<target_endianness, is64Bits>::ORDER_SYMBOL_TABLE);
+ _strtab = new ELFStringTable<target_endianness, is64Bits>
+ (".strtab",
+ DefaultELFLayout<target_endianness, is64Bits>::ORDER_STRING_TABLE);
+ _shstrtab = new ELFStringTable<target_endianness, is64Bits>
+ (".shstrtab",
+ DefaultELFLayout<target_endianness, is64Bits>::ORDER_SECTION_STRINGS);
+ _shdrtab = new ELFSectionHeader<target_endianness, is64Bits>
+ (DefaultELFLayout<target_endianness, is64Bits>::ORDER_SECTION_HEADERS);
+ _layout->addSection(_symtab);
+ _layout->addSection(_strtab);
+ _layout->addSection(_shstrtab);
+ _shdrtab->setStringSection(_shstrtab);
+ _symtab->setStringSection(_strtab);
+ _layout->addSection(_shdrtab);
}
+
} // namespace elf
Writer *createWriterELF(const WriterOptionsELF &options) {
+
+ // Set the default layout to be the static executable layout
+ // We would set the layout to a dynamic executable layout
+ // if we came across any shared libraries in the process
+
if (!options.is64Bit() && options.endianness() == llvm::support::little)
- return new lld::elf::ELFWriter<support::little, false>(options);
+ return new lld::elf::ELFExecutableWriter<support::little, false>(options);
else if (options.is64Bit() && options.endianness() == llvm::support::little)
- return new lld::elf::ELFWriter<support::little, true>(options);
+ return new lld::elf::ELFExecutableWriter<support::little, true>(options);
else if (!options.is64Bit() && options.endianness() == llvm::support::big)
- return new lld::elf::ELFWriter<support::big, false>(options);
+ return new lld::elf::ELFExecutableWriter<support::big, false>(options);
else if (options.is64Bit() && options.endianness() == llvm::support::big)
- return new lld::elf::ELFWriter<support::big, true>(options);
+ return new lld::elf::ELFExecutableWriter<support::big, true>(options);
llvm_unreachable("Invalid Options!");
}
Index: lib/ReaderWriter/ELF/HexagonReference.cpp
===================================================================
--- lib/ReaderWriter/ELF/HexagonReference.cpp (revision 169997)
+++ lib/ReaderWriter/ELF/HexagonReference.cpp (working copy)
@@ -67,7 +67,7 @@
/// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate
int relocLO16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
uint32_t result = (uint32_t)(S + A);
- result = ((result & 0x3fff) | ((result << 2) & 0x00c00000));
+ result = ((result & 0x3fff) | ((result << 8) & 0x00c00000));
*reinterpret_cast<llvm::support::ulittle32_t *>(location) = result |
(uint32_t)*reinterpret_cast<llvm::support::ulittle32_t *>(location);
return HexagonKindHandler::NoError;
@@ -76,7 +76,7 @@
/// \brief Word32_LO: 0x00c03fff : (S + A) >> 16 : Truncate
int relocHI16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
uint32_t result = (uint32_t)((S + A)>>16);
- result = ((result & 0x3fff) | ((result << 2) & 0x00c00000));
+ result = ((result & 0x3fff) | ((result << 8) & 0x00c00000));
*reinterpret_cast<llvm::support::ulittle32_t *>(location) = result |
(uint32_t)*reinterpret_cast<llvm::support::ulittle32_t *>(location);
return HexagonKindHandler::NoError;
Index: lib/ReaderWriter/ELF/ReaderELF.cpp
===================================================================
--- lib/ReaderWriter/ELF/ReaderELF.cpp (revision 169997)
+++ lib/ReaderWriter/ELF/ReaderELF.cpp (working copy)
@@ -22,6 +22,7 @@
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
@@ -30,7 +31,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Support/Path.h"
+#include "ELFAtoms.h"
#include <map>
@@ -40,415 +41,6 @@
using namespace lld;
namespace { // anonymous
-
-
-/// \brief Relocation References: Defined Atoms may contain
-/// references that will need to be patched before
-/// the executable is written.
-template <llvm::support::endianness target_endianness, bool is64Bits>
-class ELFReference final : public Reference {
-
- typedef llvm::object::Elf_Rel_Impl
- <target_endianness, is64Bits, false> Elf_Rel;
- typedef llvm::object::Elf_Rel_Impl
- <target_endianness, is64Bits, true> Elf_Rela;
-public:
-
- ELFReference(const Elf_Rela *rela, uint64_t offset, const Atom *target)
- : _target(target)
- , _targetSymbolIndex(rela->getSymbol())
- , _offsetInAtom(offset)
- , _addend(rela->r_addend)
- , _kind(rela->getType()) {}
-
- ELFReference(const Elf_Rel *rel, uint64_t offset, const Atom *target)
- : _target(target)
- , _targetSymbolIndex(rel->getSymbol())
- , _offsetInAtom(offset)
- , _addend(0)
- , _kind(rel->getType()) {}
-
-
- virtual uint64_t offsetInAtom() const {
- return _offsetInAtom;
- }
-
- virtual Kind kind() const {
- return _kind;
- }
-
- virtual void setKind(Kind kind) {
- _kind = kind;
- }
-
- virtual const Atom *target() const {
- return _target;
- }
-
-/// \brief targetSymbolIndex: This is the symbol table index that contains
-/// the target reference.
- uint64_t targetSymbolIndex() const {
- return _targetSymbolIndex;
- }
-
- virtual Addend addend() const {
- return _addend;
- }
-
- virtual void setAddend(Addend A) {
- _addend = A;
- }
-
- virtual void setTarget(const Atom *newAtom) {
- _target = newAtom;
- }
-private:
- const Atom *_target;
- uint64_t _targetSymbolIndex;
- uint64_t _offsetInAtom;
- Addend _addend;
- Kind _kind;
-};
-
-
-/// \brief ELFAbsoluteAtom: These atoms store symbols that are fixed to a
-/// particular address. This atom has no content its address will be used by
-/// the writer to fixup references that point to it.
-template<llvm::support::endianness target_endianness, bool is64Bits>
-class ELFAbsoluteAtom final : public AbsoluteAtom {
-
- typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
-
-public:
- ELFAbsoluteAtom(const File &file,
- llvm::StringRef name,
- const Elf_Sym *symbol,
- uint64_t value)
- : _owningFile(file)
- , _name(name)
- , _symbol(symbol)
- , _value(value)
- {}
-
- virtual const class File &file() const {
- return _owningFile;
- }
-
- virtual Scope scope() const {
- if (_symbol->st_other == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- if (_symbol->getBinding() == llvm::ELF::STB_LOCAL)
- return scopeTranslationUnit;
- else
- return scopeGlobal;
- }
-
- virtual llvm::StringRef name() const {
- return _name;
- }
-
- virtual uint64_t value() const {
- return _value;
- }
-
-private:
- const File &_owningFile;
- llvm::StringRef _name;
- const Elf_Sym *_symbol;
- uint64_t _value;
-};
-
-
-/// \brief ELFUndefinedAtom: These atoms store undefined symbols and are
-/// place holders that will be replaced by defined atoms later in the
-/// linking process.
-template<llvm::support::endianness target_endianness, bool is64Bits>
-class ELFUndefinedAtom final: public UndefinedAtom {
-
- typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
-
-public:
- ELFUndefinedAtom(const File &file,
- llvm::StringRef name,
- const Elf_Sym *symbol)
- : _owningFile(file)
- , _name(name)
- , _symbol(symbol)
- {}
-
- virtual const class File &file() const {
- return _owningFile;
- }
-
- virtual llvm::StringRef name() const {
- return _name;
- }
-
- // FIXME What distinguishes a symbol in ELF that can help
- // decide if the symbol is undefined only during build and not
- // runtime? This will make us choose canBeNullAtBuildtime and
- // canBeNullAtRuntime
- //
- virtual CanBeNull canBeNull() const {
-
- if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
- return CanBeNull::canBeNullAtBuildtime;
- else
- return CanBeNull::canBeNullNever;
- }
-
-private:
- const File &_owningFile;
- llvm::StringRef _name;
- const Elf_Sym *_symbol;
-};
-
-
-/// \brief ELFDefinedAtom: This atom stores defined symbols and will contain
-/// either data or code.
-template<llvm::support::endianness target_endianness, bool is64Bits>
-class ELFDefinedAtom final: public DefinedAtom {
-
- typedef llvm::object::Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym;
- typedef llvm::object::Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;
-
-public:
- ELFDefinedAtom(const File &file,
- llvm::StringRef symbolName,
- llvm::StringRef sectionName,
- const Elf_Sym *symbol,
- const Elf_Shdr *section,
- llvm::ArrayRef<uint8_t> contentData,
- unsigned int referenceStart,
- unsigned int referenceEnd,
- std::vector<ELFReference
- <target_endianness, is64Bits> *> &referenceList)
-
- : _owningFile(file)
- , _symbolName(symbolName)
- , _sectionName(sectionName)
- , _symbol(symbol)
- , _section(section)
- , _contentData(contentData)
- , _referenceStartIndex(referenceStart)
- , _referenceEndIndex(referenceEnd)
- , _referenceList(referenceList) {
- static uint64_t orderNumber = 0;
- _ordinal = ++orderNumber;
- }
-
- virtual const class File &file() const {
- return _owningFile;
- }
-
- virtual llvm::StringRef name() const {
- return _symbolName;
- }
-
- virtual uint64_t ordinal() const {
- return _ordinal;
- }
-
- virtual uint64_t size() const {
-
- // Common symbols are not allocated in object files,
- // so use st_size to tell how many bytes are required.
- if ((_symbol->getType() == llvm::ELF::STT_COMMON)
- || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
- return (uint64_t)_symbol->st_size;
-
- return _contentData.size();
-
- }
-
- virtual Scope scope() const {
- if (_symbol->st_other == llvm::ELF::STV_HIDDEN)
- return scopeLinkageUnit;
- else if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
- return scopeGlobal;
- else
- return scopeTranslationUnit;
- }
-
- // FIXME Need to revisit this in future.
-
- virtual Interposable interposable() const {
- return interposeNo;
- }
-
- // FIXME What ways can we determine this in ELF?
-
- virtual Merge merge() const {
-
- if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
- return mergeAsWeak;
-
- if ((_symbol->getType() == llvm::ELF::STT_COMMON)
- || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
- return mergeAsTentative;
-
- return mergeNo;
- }
-
- virtual ContentType contentType() const {
-
- ContentType ret = typeUnknown;
-
- switch (_section->sh_type) {
- case llvm::ELF::SHT_PROGBITS:
- case llvm::ELF::SHT_DYNAMIC:
- switch (_section->sh_flags) {
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR
- | llvm::ELF::SHF_WRITE):
- ret = typeCode;
- break;
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR):
- ret = typeCode;
- break;
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE):
- ret = typeData;
- break;
- case llvm::ELF::SHF_ALLOC:
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE):
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE |
- llvm::ELF::SHF_STRINGS):
- ret = typeConstant;
- break;
- }
- break;
- case llvm::ELF::SHT_NOBITS:
- ret = typeZeroFill;
- break;
- case llvm::ELF::SHT_NULL:
- if ((_symbol->getType() == llvm::ELF::STT_COMMON)
- || _symbol->st_shndx == llvm::ELF::SHN_COMMON)
- ret = typeZeroFill;
- break;
- }
-
- return ret;
- }
-
- virtual Alignment alignment() const {
-
- // Unallocated common symbols specify their alignment
- // constraints in st_value.
- if ((_symbol->getType() == llvm::ELF::STT_COMMON)
- || _symbol->st_shndx == llvm::ELF::SHN_COMMON) {
- return Alignment(llvm::Log2_64(_symbol->st_value));
- }
- return Alignment(llvm::Log2_64(_section->sh_addralign));
- }
-
- // Do we have a choice for ELF? All symbols
- // live in explicit sections.
- virtual SectionChoice sectionChoice() const {
- if (_symbol->st_shndx > llvm::ELF::SHN_LORESERVE)
- return sectionBasedOnContent;
-
- return sectionCustomRequired;
- }
-
- virtual llvm::StringRef customSectionName() const {
- return _sectionName;
- }
-
- // It isn't clear that __attribute__((used)) is transmitted to
- // the ELF object file.
- virtual DeadStripKind deadStrip() const {
- return deadStripNormal;
- }
-
- virtual ContentPermissions permissions() const {
-
- switch (_section->sh_type) {
- // permRW_L is for sections modified by the runtime
- // loader.
- case llvm::ELF::SHT_REL:
- case llvm::ELF::SHT_RELA:
- return permRW_L;
-
- case llvm::ELF::SHT_DYNAMIC:
- case llvm::ELF::SHT_PROGBITS:
- switch (_section->sh_flags) {
-
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR):
- return permR_X;
-
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE):
- return permRW_;
-
- case llvm::ELF::SHF_ALLOC:
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE):
- case (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_MERGE
- | llvm::ELF::SHF_STRINGS):
- return permR__;
- }
- default:
- return perm___;
- }
- }
-
- // Many non ARM architectures use ELF file format
- // This not really a place to put a architecture
- // specific method in an atom. A better approach is
- // needed.
- //
- virtual bool isThumb() const {
- return false;
- }
-
- // FIXME Not Sure if ELF supports alias atoms. Find out more.
- virtual bool isAlias() const {
- return false;
- }
-
- virtual llvm::ArrayRef<uint8_t> rawContent() const {
- return _contentData;
- }
-
- DefinedAtom::reference_iterator begin() const {
- uintptr_t index = _referenceStartIndex;
- const void *it = reinterpret_cast<const void*>(index);
- return reference_iterator(*this, it);
- }
-
- DefinedAtom::reference_iterator end() const {
- uintptr_t index = _referenceEndIndex;
- const void *it = reinterpret_cast<const void*>(index);
- return reference_iterator(*this, it);
- }
-
- const Reference *derefIterator(const void *It) const {
- uintptr_t index = reinterpret_cast<uintptr_t>(It);
- assert(index >= _referenceStartIndex);
- assert(index < _referenceEndIndex);
- return ((_referenceList)[index]);
- }
-
- void incrementIterator(const void*& It) const {
- uintptr_t index = reinterpret_cast<uintptr_t>(It);
- ++index;
- It = reinterpret_cast<const void*>(index);
- }
-
-private:
-
- const File &_owningFile;
- llvm::StringRef _symbolName;
- llvm::StringRef _sectionName;
- const Elf_Sym *_symbol;
- const Elf_Shdr *_section;
- // _contentData will hold the bits that make up the atom.
- llvm::ArrayRef<uint8_t> _contentData;
-
- uint64_t _ordinal;
- unsigned int _referenceStartIndex;
- unsigned int _referenceEndIndex;
- std::vector<ELFReference<target_endianness, is64Bits> *> &_referenceList;
-};
-
-
// FileELF will read a binary, find out based on the symbol table contents
// what kind of symbol it is and create corresponding atoms for it
@@ -644,7 +236,6 @@
symbolData = llvm::ArrayRef<uint8_t>((uint8_t *)symbolContents.data()
+ (*si)->st_value, contentSize);
-
unsigned int referenceStart = _references.size();
// Only relocations that are inside the domain of the atom are
@@ -683,7 +274,7 @@
<ELFDefinedAtom<target_endianness, is64Bits> > ())
ELFDefinedAtom<target_endianness, is64Bits>
(*this, symbolName, sectionName,
- *si, i.first, symbolData,
+ *si, i.first, symbolData,
referenceStart, _references.size(), _references);
_definedAtoms._atoms.push_back(newAtom);
Index: lib/Core/SymbolTable.cpp
===================================================================
--- lib/Core/SymbolTable.cpp (revision 169997)
+++ lib/Core/SymbolTable.cpp (working copy)
@@ -73,7 +73,7 @@
},
{
// first is absolute
- NCR_Error, NCR_Error, NCR_First, NCR_First
+ NCR_Error, NCR_First, NCR_First, NCR_First
},
{
// first is undef
More information about the llvm-commits
mailing list