[llvm-commits] [PATCH] [lld] patch for ELF Writer to get it to 'Hello world'
Shankar Easwaran
shankare at codeaurora.org
Wed Dec 26 15:40:20 PST 2012
Attached is the diff with the changes to the header sort order and the
lambda function.
Thanks
Shankar Easwaran
On 12/21/2012 11:28 PM, Shankar Easwaran wrote:
> Attached is the diff with the changes.
>
> Thanks
>
> Shankar Easwaran
>
> On 12/21/2012 11:11 PM, Shankar Easwaran wrote:
>> Done the changes as specified by your review comments.
>>
>> OK to commit ?
>>
>> Thanks
>>
>> Shankar Easwaran
>>
>> On 12/21/2012 9:54 PM, Michael Spencer wrote:
>>> On Fri, Dec 21, 2012 at 2:23 PM, Shankar Easwaran
>>> <shankare at codeaurora.org> wrote:
>>>> Hi Michael,
>>>>
>>>> Attached is the new diff after the review with the test case changes.
>>>>
>>>> You would need to apply the other changes that were in the previous
>>>> patches
>>>> to build.
>>>>
>>>> a) ELFAtoms.h
>>>> b) ReaderELF changes
>>>> c) HexagonRelocation changes
>>>>
>>>> OK to commit ?
>>>>
>>>> Thanks
>>>>
>>>> Shankar Easwaran
>>>>
>>>>
>>>> On 12/21/2012 11:11 AM, Michael Spencer wrote:
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:80-86
>>>>> @@ +79,9 @@
>>>>> + /// \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),
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> This either needs to be an enum class, or the members need to
>>>>>>> follow the
>>>>>>> naming convention. Currently this breaks MSVC because it doesn't
>>>>>>> do two
>>>>>>> phase name lookup and therefore sees Section and Segment in the
>>>>>>> derived
>>>>>>> class (Chunk) instead of the templates Section and Segment.
>>>>>> Changed the names to add ELF in the front
>>>>>
>>>>> http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly
>>>>>
>>>>>
>>>>> They should start with K_
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:121-123
>>>>> @@ +120,5 @@
>>>>> + 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; }
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> What is the difference between these two function? Is one the
>>>>>>> virtual
>>>>>>> address?
>>>>>> yes.
>>>>> Then the names could be improved and a \brief added.
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:549
>>>>> @@ -235,1 +548,3 @@
>>>>> + void setOrdinal(int64_t ordinal) {
>>>>> + ordinal = ordinal;
>>>>> }
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> _ordinal = ordinal;
>>>>>> Nice catch.
>>>>> Clang -Wall caught it for me :P
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:1008
>>>>> @@ +1007,3 @@
>>>>> + static inline bool classof(const Chunk<target_endianness,
>>>>> is64Bits> *c)
>>>>> {
>>>>> + return c->kind() == Section<target_endianness,
>>>>> is64Bits>::StringTable;
>>>>> + }
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> This is broken. Chunk already has a Kind with the same value.
>>>>>> Chunk doesnot have such a type called StringTable.
>>>>> Not named StringTable. But StringTable shares the same underlying
>>>>> value as
>>>>> Chunk::Segment
>>>>>
>>>>> ================
>>>>> Comment at: lib/ReaderWriter/ELF/WriterELF.cpp:1491-1502
>>>>> @@ -826,1 +1490,14 @@
>>>>> + 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;
>>>>> ----------------
>>>>> Shankar Kalpathi Easwaran wrote:
>>>>>> Michael Spencer wrote:
>>>>>>> llvm::StringSwitch in llvm/ADT/StringSwitch.h
>>>>>> How do you do startswith with StringSwitch ?
>>>>> .StartsWith("") instead of .Case("").
>>>>>
>>>>>
>>>>> https://github.com/Bigcheese/llvm/blob/master/lib/Object/COFFObjectFile.cpp#L214
>>>>>
>>>>>
>>>>>
>>>>> http://llvm-reviews.chandlerc.com/D222
>>>>> _______________________________________________
>>>>> llvm-commits mailing list
>>>>> llvm-commits at cs.uiuc.edu
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>>>>
>>>>>
>>>>
>>>> --
>>>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>>>> hosted by
>>>> the Linux Foundation
>>>>
>>>> Index: WriterELF.cpp
>>>> ===================================================================
>>>> --- WriterELF.cpp (revision 170923)
>>>> +++ WriterELF.cpp (working copy)
>>>> @@ -11,20 +11,20 @@
>>>> #include "ReferenceKinds.h"
>>>>
>>>> #include "lld/Core/DefinedAtom.h"
>>>> +#include "llvm/Object/ELF.h"
>>> This needs to be sorted. It should come right before the Support
>>> headers.
>>>
>>>> #include "lld/Core/File.h"
>>>> #include "lld/Core/InputFiles.h"
>>>> #include "lld/Core/Reference.h"
>>>> #include "lld/Core/SharedLibraryAtom.h"
>>>> -
>>>> #include "llvm/ADT/ArrayRef.h"
>>>> #include "llvm/ADT/DenseMap.h"
>>>> +#include "llvm/ADT/Hashing.h"
>>>> #include "llvm/ADT/OwningPtr.h"
>>>> #include "llvm/ADT/SmallVector.h"
>>>> +#include "llvm/ADT/StringExtras.h"
>>>> #include "llvm/ADT/StringMap.h"
>>>> #include "llvm/ADT/StringRef.h"
>>>> -
>>>> -#include "llvm/Object/ELF.h"
>>>> -
>>>> +#include "llvm/ADT/StringSwitch.h"
>>>> #include "llvm/Support/Allocator.h"
>>>> #include "llvm/Support/Debug.h"
>>>> #include "llvm/Support/ELF.h"
>>>> @@ -34,1382 +34,2020 @@
>>>> #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:
>>> This shouldn't be indented.
>>>
>>>> + 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 {
>>>> + K_ELFHeader, // ELF Header
>>>> + K_ELFProgramHeader, // Program Header
>>>> + K_ELFSegment, // Segment
>>>> + K_ELFSection, // Section
>>>> + K_ELFSectionHeader // 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() const {
>>>> + 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;
>>>> +
>>>> + // 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 setVAddr(int64_t start) { _start = start; }
>>>> + int64_t virtualAddr() 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;
>>>> +
>>>> 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;
>>> These should all be unsigned.
>>>
>>>> };
>>>>
>>>> -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;
>>> Unsigned.
>>>
>>>> +
>>>> +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 assignFileOffsets() = 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 {
>>>> + K_Default = 0x100,
>>>> + K_SymbolTable,
>>>> + K_StringTable,
>>>> + };
>>> I see now that this isn't the using the same kind field as Chunk is.
>>> So no need for the 0x100. Although it does hide Chunk::Kind, so it
>>> needs a different name.
>>>
>>>> + // 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 = K_Default)
>>>> + : Chunk<target_endianness, is64Bits>
>>>> + (sectionName, Chunk<target_endianness, is64Bits>::K_ELFSection)
>>>> + , _contentType(contentType)
>>>> + , _contentPermissions(contentPermissions)
>>>> + , _sectionKind(kind)
>>>> + , _entSize(0)
>>>> + , _shInfo(0)
>>>> + , _link(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;
>>>> + /// Align the offset to the required modulus defined by the atom
>>>> alignment
>>>> + uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment
>>>> &atomAlign) {
>>>> + uint64_t requiredModulus = atomAlign.modulus;
>>>> + int64_t align2 = 1 << atomAlign.powerOf2;
>>> Unsigned. Won't warn if you do 1u <<.
>>>
>>>> + uint64_t currentModulus = (offset % align2);
>>>> + uint64_t retOffset = offset;
>>>> + if (currentModulus != requiredModulus) {
>>>> + if (requiredModulus > currentModulus)
>>>> + retOffset += requiredModulus - currentModulus;
>>>> + else
>>>> + retOffset += align2 + requiredModulus - currentModulus;
>>>> + }
>>>> + return retOffset;
>>>> + }
>>>>
>>>> +
>>>> + 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) {
>>>> + return A->getBinding() < B->getBinding();
>>>> + });
>>> This needs to be reformatted.
>>>
>>>> + uint16_t shInfo = 0;
>>>> + for (auto i : _symbolTable) {
>>>> + if (i->getBinding() != ELF::STB_LOCAL)
>>>> + break;
>>>> + shInfo++;
>>>> + }
>>>> + this->_shInfo = shInfo;
>>>> + this->setLink(_stringSection->ordinal());
>>>> + }
>>>> +
>>>> + // HashKey for the Segment
>>>> + class SegmentHashKey {
>>>> + public:
>>>> + int64_t operator() (const SegmentKey &k) const {
>>>> + // k.first = SegmentName
>>>> + // k.second = SegmentFlags
>>>> + return llvm::hash_combine(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>
>>>> SectionMapT;
>>>> + typedef std::unordered_map<SegmentKey,
>>>> + Segment<target_endianness, is64Bits>*,
>>>> + SegmentHashKey> SegmentMapT;
>>>>
>>> - Michael Spencer
>>>
>>
>>
>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation
-------------- next part --------------
Index: WriterELF.cpp
===================================================================
--- WriterELF.cpp (revision 170980)
+++ WriterELF.cpp (working copy)
@@ -15,16 +15,16 @@
#include "lld/Core/InputFiles.h"
#include "lld/Core/Reference.h"
#include "lld/Core/SharedLibraryAtom.h"
-
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/ELF.h"
-
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
@@ -34,1382 +34,2022 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include "AtomsELF.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 uint64_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 {
+ K_ELFHeader, // ELF Header
+ K_ELFProgramHeader, // Program Header
+ K_ELFSegment, // Segment
+ K_ELFSection, // Section
+ K_ELFSectionHeader // 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);
+ // Does the chunk occupy disk space
+ virtual bool occupiesNoDiskSpace() const {
+ return false;
+ }
+ // The name of the chunk
+ StringRef name() const { return _name; }
+ // Kind of chunk
+ Kind kind() const { return _kind; }
+ uint64_t fileSize() const { return _fsize; }
+ uint64_t align2() const { return _align2; }
+ void appendAtom() const;
+
+ // The ordinal value of the chunk
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;
+ void setOrdinal(uint64_t newVal) { _ordinal = newVal;}
+ // The order in which the chunk would appear in the output file
+ uint64_t order() const { return _order; }
+ void setOrder(uint32_t order) { _order = order; }
+ // Output file offset of the chunk
+ uint64_t fileOffset() const { return _fileoffset; }
+ void setFileOffset(uint64_t offset) { _fileoffset = offset; }
+ // Output start address of the chunk
+ void setVAddr(uint64_t start) { _start = start; }
+ uint64_t virtualAddr() const { return _start; }
+ // Does the chunk occupy memory during execution ?
+ uint64_t memSize() const { return _msize; }
+ void setMemSize(uint64_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;
+
protected:
- Chunk();
- Chunk(Kind K): _cKind(K) { this->init();}
- uint64_t _size;
- uint64_t _address;
- uint64_t _fileOffset;
+ StringRef _name;
+ Kind _kind;
+ uint64_t _fsize;
+ uint64_t _msize;
uint64_t _align2;
+ uint32_t _order;
uint64_t _ordinal;
- uint16_t _group;
- bool _isLoadable;
+ uint64_t _start;
+ uint64_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 uint32_t SectionOrder;
+ typedef uint32_t SegmentType;
+ typedef uint32_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, uint64_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 assignFileOffsets() = 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 SectionKind {
+ K_Default,
+ K_SymbolTable,
+ K_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 SectionKind kind = K_Default)
+ : Chunk<target_endianness, is64Bits>
+ (sectionName, Chunk<target_endianness, is64Bits>::K_ELFSection)
+ , _contentType(contentType)
+ , _contentPermissions(contentPermissions)
+ , _sectionKind(kind)
+ , _entSize(0)
+ , _shInfo(0)
+ , _link(0) {
+ this->setOrder(order);
}
- bool operator()(Chunk<target_endianness, is64Bits> *A, uint16_t B) {
- return A->group() < B;
+
+ /// return the section kind
+ SectionKind 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;
+ /// Align the offset to the required modulus defined by the atom alignment
+ uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign) {
+ uint64_t requiredModulus = atomAlign.modulus;
+ uint64_t align2 = 1u << atomAlign.powerOf2;
+ uint64_t currentModulus = (offset % align2);
+ uint64_t retOffset = offset;
+ if (currentModulus != requiredModulus) {
+ if (requiredModulus > currentModulus)
+ retOffset += requiredModulus - currentModulus;
+ else
+ retOffset += align2 + requiredModulus - currentModulus;
+ }
+ return retOffset;
+ }
-/// \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);
+ // \brief Append an atom to a Section. The atom gets pushed into a vector
+ // 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();
+ uint64_t align2 = 1u << atomAlign.powerOf2;
+ // 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 fOffset = alignOffset(this->fileSize(), atomAlign);
+ uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
+ 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:
+ llvm_unreachable("Expecting only definedAtoms being passed here");
+ break;
+ }
+ // Set the section alignment to the largest alignment
+ // std::max doesnot support uint64_t
+ 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(uint64_t &addr) {
+ for (auto &ai : _atoms) {
+ 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 assignOffsets(uint64_t offset) {
+ for (auto &ai : _atoms) {
+ ai.second.first = offset + ai.second.first;
+ }
+ }
+
+ /// \brief Find the Atom address given a name, this is needed to to properly
+ /// apply relocation. The section class calls this to find the atom address
+ /// to fix the relocation
+ bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
+ for (auto ai : _atoms) {
+ if (ai.first->name() == name) {
+ addr = ai.second.second;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// \brief Does the Atom occupy any disk space
+ bool occupiesNoDiskSpace() const {
+ return _contentType == DefinedAtom::typeZeroFill;
+ }
+
+ /// \brief The permission of the section is the most permissive permission
+ /// of all atoms that the section contains
+ void setContentPermissions(int32_t perm) {
+ _contentPermissions = std::max(perm, _contentPermissions);
+ }
+
+ /// \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(const Chunk<target_endianness, is64Bits> *c) {
- return c->getChunkKind() == Chunk<target_endianness, is64Bits>::Kind
- ::Section;
+ return c->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection;
}
+
+ /// \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) {
+ 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());
+ else
+ assert(0 && "Found the target to be NULL");
+ 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<uint64_t, uint64_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;
+ SectionKind _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<uint64_t, uint64_t>>> _atoms;
+ ELFLayout::SegmentType _segmentType;
+ int64_t _entSize;
+ int64_t _shInfo;
+ int64_t _link;
+};
+/// \brief A MergedSections 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 MergedSections {
+public:
+ MergedSections(StringRef name)
+ : _name(name)
+ ,_hasSegment(false)
+ ,_ordinal(0)
+ ,_flags(0)
+ ,_size(0)
+ ,_memSize(0)
+ ,_fileOffset(0)
+ ,_virtualAddr(0)
+ ,_shInfo(0)
+ ,_entSize(0)
+ ,_link(0)
+ ,_align2(0)
+ ,_kind(0)
+ ,_type(0) { }
+
+ // Set the MergedSections 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(uint64_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(uint64_t memsz) {
+ _memSize = memsz;
+ }
+
+ /// Sets the size fo the merged Section
+ void setSize(uint64_t fsiz) {
+ _size = fsiz;
+ }
+
+ // The offset of the first section contained in the merged section is contained here
+ void setFileOffset(uint64_t foffset) {
+ _fileOffset = foffset;
+ }
+
+ // Sets the starting address of the section
+ void setAddr(uint64_t addr) {
+ _virtualAddr = addr;
+ }
+
+ // Appends a section into the list of sections that are part of this Merged
+ // Section
+ void appendSection(Chunk<target_endianness, is64Bits> *c) {
+ if (c->align2() > _align2)
+ _align2 = c->align2();
+ if (c->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection) {
+ Section<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
+ ChunkIter;
+
+ ChunkIter begin_sections() { return _sections.begin(); }
+
+ ChunkIter 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; }
+
+ uint64_t align2() const { return _align2; }
+
+ int64_t link() const { return _link; }
+
+ int64_t type() const { return _type; }
+
+ uint64_t virtualAddr() const { return _virtualAddr; }
+
+ int64_t ordinal() const { return _ordinal; }
+
+ int64_t kind() const { return _kind; }
+
+ uint64_t fileSize() const { return _size; }
+
+ int64_t entsize() const { return _entSize; }
+
+ uint64_t fileOffset() const { return _fileOffset; }
+
+ int64_t flags() const { return _flags; }
+
+ uint64_t memSize() { return _memSize; }
+
private:
- std::vector<AtomInfo> _atoms;
+ StringRef _name;
+ bool _hasSegment;
+ uint64_t _ordinal;
+ int64_t _flags;
+ uint64_t _size;
+ uint64_t _memSize;
+ uint64_t _fileOffset;
+ uint64_t _virtualAddr;
+ int64_t _shInfo;
+ int64_t _entSize;
+ int64_t _link;
+ uint64_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<Section<target_endianness, is64Bits> *>::iterator
+ sectionIter;
- 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(uint64_t fileoffset, int32_t s, int e) {
+ _startSection = s;
+ _endSection = e+1;
+ _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 setSections(sectionIter start, sectionIter end) {
+ _startSectionIter = start;
+ _endSectionIter = end;
}
+
+ // Return the fileOffset of the slice
+ uint64_t fileOffset() const { return _offset; }
+
+ // Return the size of the slice
+ uint64_t fileSize() const { return _size; }
+
+ // Return the start of the slice
+ int32_t startSection() const { return _startSection; }
+
+ // Return the start address of the slice
+ uint64_t virtualAddr() const { return _addr; }
+
+ // Return the memory size of the slice
+ uint64_t memSize() const { return _memSize; }
+
+ // Return the alignment of the slice
+ uint64_t align2() const { return _align2; }
+
+ void setSize(uint64_t sz) { _size = sz; }
+
+ void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+ void setVAddr(uint64_t addr) { _addr = addr; }
+
+ void setAlign(uint64_t align) { _align2 = align; }
+
+ static bool compare_slices(SegmentSlice<target_endianness, is64Bits> *a,
+ SegmentSlice<target_endianness, is64Bits> *b) {
+ return (a->startSection() < b->startSection());
+ }
+
+ // Functions to run through the slice
+ sectionIter sections_begin() { return _startSectionIter; }
+
+ sectionIter sections_end() { return _endSectionIter; }
+
private:
- Elf_Ehdr _eh;
+ int32_t _startSection;
+ int32_t _endSection;
+ sectionIter _startSectionIter;
+ sectionIter _endSectionIter;
+ uint64_t _addr;
+ uint64_t _offset;
+ uint64_t _size;
+ uint64_t _align2;
+ uint64_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<Section<target_endianness, is64Bits> *>::iterator SectionIter;
+
+ Segment(const StringRef name,
+ const ELFLayout::SegmentType type,
+ const WriterOptionsELF &options)
+ : Chunk<target_endianness, is64Bits>(name
+ , Chunk<target_endianness, is64Bits>::K_ELFSegment)
+ , _segmentType(type)
+ , _flags(0)
+ , _atomflags(0)
+ , _options(options) {
+ this->_align2 = 0;
+ this->_fsize = 0;
}
+
+ /// append a section to a segment
+ void append(Section<target_endianness, is64Bits> *section) {
+ _sections.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 compareSegments(Segment<target_endianness, is64Bits> *sega,
+ Segment<target_endianness, is64Bits> *segb)
+ {
+
+ 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.
+ /// The algorithm starts off by assigning the startOffset thats passed in as
+ /// parameter to the first section in the segment, if the difference between
+ /// the newly computed offset is greater than a page, then we create a segment
+ /// slice, as it would be a waste of virtual memory just to be filled with
+ /// zeroes
+ void assignOffsets(uint64_t startOffset) {
+ int startSection = 0;
+ int currSection = 0;
+ SectionIter startSectionIter, endSectionIter;
+ // slice align is set to the max alignment of the chunks that are
+ // contained in the slice
+ uint64_t sliceAlign = 0;
+ // Current slice size
+ uint64_t curSliceSize = 0;
+ // Current Slice File Offset
+ uint64_t curSliceFileOffset = 0;
+
+ startSectionIter = _sections.begin();
+ endSectionIter = _sections.end();
+ startSection = 0;
+ bool isFirstSection = true;
+ for (auto si = _sections.begin(); si != _sections.end(); ++si) {
+ if (isFirstSection) {
+ // align the startOffset to the section alignment
+ uint64_t newOffset = llvm::RoundUpToAlignment(startOffset, (*si)->align2());
+ curSliceFileOffset = newOffset;
+ sliceAlign = (*si)->align2();
+ this->setFileOffset(startOffset);
+ (*si)->setFileOffset(newOffset);
+ curSliceSize = (*si)->fileSize();
+ isFirstSection = false;
+ } else {
+ uint64_t curOffset = curSliceFileOffset + curSliceSize;
+ uint64_t newOffset = llvm::RoundUpToAlignment(curOffset, (*si)->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()) {
+ // TODO: use std::find here
+ for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+ if ((*sei)->startSection() == startSection) {
+ slice = *sei;
+ break;
+ }
+ }
+ if (!slice) {
+ slice = new (_segmentAllocate.Allocate
+ <SegmentSlice<target_endianness, is64Bits>>())
+ SegmentSlice<target_endianness, is64Bits>();
+ _segmentSlices.push_back(slice);
+ }
+ slice->set(curSliceFileOffset, startSection, currSection);
+ slice->setSections(startSectionIter, endSectionIter);
+ slice->setSize(curSliceSize);
+ slice->setAlign(sliceAlign);
+ uint64_t newPageOffset = llvm::RoundUpToAlignment(curOffset, _options.pageSize());
+ newOffset = llvm::RoundUpToAlignment(newPageOffset, (*si)->align2());
+ curSliceFileOffset = newOffset;
+ startSectionIter = endSectionIter;
+ startSection = currSection;
+ (*si)->setFileOffset(curSliceFileOffset);
+ curSliceSize = newOffset - curSliceFileOffset + (*si)->fileSize();
+ sliceAlign = (*si)->align2();
+ }
+ else {
+ if (sliceAlign < (*si)->align2())
+ sliceAlign = (*si)->align2();
+ (*si)->setFileOffset(newOffset);
+ curSliceSize = newOffset - curSliceFileOffset + (*si)->fileSize();
+ }
+ }
+ currSection++;
+ endSectionIter = si;
+ }
+ SegmentSlice<target_endianness, is64Bits> *slice = nullptr;
+ for (auto sei = slices_begin(); sei != slices_end(); ++sei) {
+ // TODO: add std::find
+ if ((*sei)->startSection() == startSection) {
+ slice = *sei;
+ break;
+ }
+ }
+ if (!slice) {
+ slice = new (_segmentAllocate.Allocate
+ <SegmentSlice<target_endianness, is64Bits>>())
+ SegmentSlice<target_endianness, is64Bits>();
+ _segmentSlices.push_back(slice);
+ }
+ slice->set(curSliceFileOffset, startSection, currSection);
+ slice->setSections(startSectionIter, _sections.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(uint64_t &addr, bool isFirstSegment) {
+ for (auto sei = slices_begin(), see = slices_end(); sei != see; ++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)->setVAddr(this->virtualAddr());
+ else {
+ // Align to a page
+ addr = llvm::RoundUpToAlignment(addr, _options.pageSize());
+ // Align to the slice alignment
+ addr = llvm::RoundUpToAlignment(addr, (*sei)->align2());
+ }
+ bool virtualAddressSet = false;
+ for (auto si = (*sei)->sections_begin(), se = (*sei)->sections_end();
+ si != se; ++si) {
+ // Align the section address
+ addr = llvm::RoundUpToAlignment(addr, (*si)->align2());
+ if (!isFirstSegment && !virtualAddressSet) {
+ (*sei)->setVAddr(addr);
+ virtualAddressSet = true;
+ }
+ (*si)->setVAddr(addr);
+ (*si)->assignVirtualAddress(addr);
+ (*si)->setMemSize(addr - (*si)->virtualAddr());
+ }
+ (*sei)->setMemSize(addr - (*sei)->virtualAddr());
+ }
+ }
+
+ 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(), see = slices_end(); sei != see; ++sei) {
+ for (auto si = (*sei)->sections_begin(), se = (*sei)->sections_end();
+ si != se; ++si) {
+ (*si)->write(writer, buffer);
+ }
+ }
+ }
+
+ // Finalize the segment, before we want to write to the output file
+ void finalize() { }
+
+ // For LLVM RTTI
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>::K_ELFSegment;
}
+ // Getters
+ int32_t sectionCount() const {
+ return _sections.size();
+ }
+
+ ELFLayout::SegmentType segmentType() { return _segmentType; }
+
+ int pageSize() 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<Section<target_endianness, is64Bits> *> _sections;
+ std::vector<SegmentSlice<target_endianness, is64Bits> *> _segmentSlices;
+ ELFLayout::SegmentType _segmentType;
+ int64_t _flags;
+ int64_t _atomflags;
+ const WriterOptionsELF _options;
+ llvm::BumpPtrAllocator _segmentAllocate;
};
-/// \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>::K_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 Chunk<target_endianness, is64Bits> *c) {
+ return c->kind() == Section<target_endianness, is64Bits>::K_StringTable;
+ }
+
+ uint64_t addString(const StringRef symname) {
+ _strings.push_back(symname);
+ uint64_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) {
+ 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>::K_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 Chunk<target_endianness, is64Bits> *c) {
+ return c->kind() == Section<target_endianness, is64Bits>::K_SymbolTable;
+ }
+
+ void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0) {
+ Elf_Sym *symbol = new(_symbolAllocate.Allocate<Elf_Sym>()) Elf_Sym;
+ unsigned char binding = 0, type = 0;
+ symbol->st_name = _stringSection->addString(atom->name());
+ symbol->st_size = 0;
+ symbol->st_shndx = sectionIndex;
+ symbol->st_value = 0;
+ symbol->st_other = ELF::STV_DEFAULT;
+ if (const DefinedAtom *da = llvm::dyn_cast<const DefinedAtom>(atom)){
+ symbol->st_size = da->size();
+ lld::DefinedAtom::ContentType ct;
+ switch (ct = da->contentType()){
+ case DefinedAtom::typeCode:
+ symbol->st_value = addr;
+ type = ELF::STT_FUNC;
+ break;
+ case DefinedAtom::typeData:
+ symbol->st_value = addr;
+ type = ELF::STT_OBJECT;
+ break;
+ case DefinedAtom::typeZeroFill:
+ type = ELF::STT_COMMON;
+ symbol->st_value = addr;
+ break;
+ default:
+ type = ELF::STT_NOTYPE;
+ }
+ if (da->scope() == DefinedAtom::scopeTranslationUnit)
+ binding = ELF::STB_LOCAL;
+ else
+ binding = ELF::STB_GLOBAL;
+ } else if (const AbsoluteAtom *aa = llvm::dyn_cast<const AbsoluteAtom>(atom)){
+ type = ELF::STT_OBJECT;
+ symbol->st_shndx = ELF::SHN_ABS;
+ switch (aa->scope()) {
+ case AbsoluteAtom::scopeLinkageUnit:
+ symbol->st_other = ELF::STV_HIDDEN;
+ binding = ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeTranslationUnit:
+ binding = ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeGlobal:
+ binding = ELF::STB_GLOBAL;
+ break;
+ }
+ symbol->st_value = aa->value();
+ }
+ else {
+ symbol->st_value = 0;
+ type = ELF::STT_NOTYPE;
+ binding = ELF::STB_WEAK;
+ }
+ symbol->setBindingAndType(binding, type);
+ _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) {
+ 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) {
+ 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>::K_ELFHeader) {
+ memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
+ 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; }
+ uint64_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>::K_ELFHeader;
}
-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>::K_ELFProgramHeader) { }
-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(), see = segment->slices_end();
+ sei != see; ++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)->virtualAddr();
+ phdr->p_paddr = (*sei)->virtualAddr();
+ 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->pageSize() : (*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 setVAddr(uint64_t addr) {
+ this->_start = llvm::RoundUpToAlignment(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);
-}
+ uint64_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>::K_ELFProgramHeader;
}
- 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) {
+ 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>::K_ELFSectionHeader)
+ {
+ 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(MergedSections<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->virtualAddr();
+ 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->virtualAddr();
+ 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>::K_ELFSectionHeader;
+ }
- 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) {
+ 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
+ ChunkIter;
+ // 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, MergedSections<target_endianness, is64Bits> *>
+ MergedSectionMapT;
+ typedef typename std::vector
+ <MergedSections<target_endianness, is64Bits> *>::iterator MergedSectionIter;
-/// \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::hash_combine(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::hash_combine(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> SectionMapT;
+ typedef std::unordered_map<SegmentKey,
+ Segment<target_endianness, is64Bits>*,
+ SegmentHashKey> SegmentMapT;
-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:
+ return llvm::StringSwitch<Reference::Kind>(name)
+ .StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
+ .StartsWith(".eh_frame", ORDER_EH_FRAME)
+ .StartsWith(".init", ORDER_INIT)
+ .StartsWith(".fini", ORDER_FINI)
+ .StartsWith(".hash", ORDER_HASH)
+ .Default(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,
+ const int32_t contentType) {
+ if (contentType == DefinedAtom::typeZeroFill)
+ return ".bss";
+ 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(),
+ definedAtom->contentType());
+ 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 SectionMapT::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 MergedSections
+ void mergeSimiliarSections() {
+ MergedSections<target_endianness, is64Bits> *mergedSection;
+
+ for (auto &si : _sections) {
+ const std::pair<StringRef, MergedSections<target_endianness, is64Bits> *>
+ currentMergedSections(si->name(),
+ nullptr);
+ std::pair<typename MergedSectionMapT::iterator, bool>
+ mergedSectionInsert
+ (_mergedSectionMap.insert(currentMergedSections));
+ if (!mergedSectionInsert.second) {
+ mergedSection = mergedSectionInsert.first->second;
+ }
+ else {
+ mergedSection = new (_allocator.Allocate
+ <MergedSections<target_endianness, is64Bits>>())
+ MergedSections<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) {
+ return A->order() < B->order();
+ });
+ // Merge all sections
+ mergeSimiliarSections();
+ // Set the ordinal after sorting the sections
+ int ordinal = 1;
+ for (auto &msi : _mergedSections) {
+ (*msi).setOrdinal(ordinal);
+ for (auto ai = (*msi).begin_sections(), ae = (*msi).end_sections();
+ ai != ae; ++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(), mse = merged_sections_end();
+ msi != mse; ++msi) {
+ for (auto ai = (*msi)->begin_sections(), ae = (*msi)->end_sections();
+ ai != ae; ++ai) {
+ if ((*ai)->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection) {
+ 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 SegmentMapT::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";
-}
+ void assignFileOffsets() {
+ std::sort(_segments.begin(),
+ _segments.end(),
+ Segment<target_endianness, is64Bits>::compareSegments);
+ int ordinal = 0;
+ // Compute the number of segments that might be needed, so that the
+ // size of the program header can be computed
+ uint64_t offset = 0;
+ for (auto si : _segments) {
+ si->setOrdinal(++ordinal);
+ si->assignOffsets(offset);
+ offset += si->fileSize();
+ }
+ }
-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 setELFHeader(ELFHeader<target_endianness, is64Bits> *e) {
+ _elfHeader = e;
}
-}
-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 setProgramHeader(ELFProgramHeader<target_endianness, is64Bits> *p) {
+ _programHeader = p;
+ }
-template<support::endianness target_endianness, bool is64Bits>
-const char *ELFSectionHeaderChunk<target_endianness, is64Bits>::info() {
- return "elf_section_header";
-}
+ void assignVirtualAddress() {
+ int32_t numSlices = 0;
+ uint64_t virtualAddress = _options.baseAddress();
-//===----------------------------------------------------------------------===//
-// 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;
+ // Add the ELF Header
+ if (_elfHeader) {
+ _elfHeader->setFileOffset(0);
+ _elfHeader->setVAddr(virtualAddress);
+ }
+ // Add the program header
+ if (_programHeader) {
+ _programHeader->setVAddr(uint64_t(virtualAddress + _elfHeader->fileSize()));
+ _programHeader->setFileOffset(_elfHeader->fileSize());
+ }
+ bool newSegmentHeaderAdded = true;
+ while (true) {
+ for (auto si : _segments) {
+ newSegmentHeaderAdded = _programHeader->addSegment(si);
+ numSlices += si->numSlices();
+ }
+ if (!newSegmentHeaderAdded)
+ break;
+ uint64_t fileoffset = _elfHeader->fileSize() + _programHeader->fileSize();
+ uint64_t address = virtualAddress;
+ // Fix the offsets after adding the program header
+ for (auto &si : _segments) {
+ // Align the segment to a page boundary
+ fileoffset = llvm::RoundUpToAlignment(fileoffset, _options.pageSize());
+ si->assignOffsets(fileoffset);
+ fileoffset = si->fileOffset() + si->fileSize();
+ }
+ // start assigning virtual addresses
+ for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+ (*si)->setVAddr(virtualAddress);
+ // The first segment has the virtualAddress set to the base address as
+ // we have added the file header and the program header dont align the
+ // first segment to the pagesize
+ (*si)->assignVirtualAddress(address, (si == _segments.begin()));
+ (*si)->setMemSize(address - virtualAddress);
+ virtualAddress = llvm::RoundUpToAlignment(address, _options.pageSize());
+ }
+ _programHeader->resetProgramHeaders();
+ }
+ Section<target_endianness, is64Bits> *section;
+ // Fix the offsets of all the atoms within a section
+ for (auto &si : _sections) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(si);
+ if (section &&
+ DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment(section))
+ section->assignOffsets(section->fileOffset());
+ }
+ // Set the size of the merged Sections
+ for (auto msi = merged_sections_begin(), mse = merged_sections_end();
+ msi != mse; ++msi) {
+ uint64_t sectionfileoffset = 0;
+ uint64_t startFileOffset = 0;
+ uint64_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(), mse = merged_sections_end();
+ msi != mse; ++msi) {
+ uint64_t sectionstartaddr = 0;
+ uint64_t startaddr = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si = (*msi)->begin_sections(), se = (*msi)->end_sections();
+ si != se; ++si) {
+ if (isFirstSection) {
+ startaddr = (*si)->virtualAddr();
+ isFirstSection = false;
+ }
+ sectionstartaddr = (*si)->virtualAddr();
+ sectionsize = (*si)->memSize();
+ }
+ sectionsize = (sectionstartaddr - startaddr) + sectionsize;
+ (*msi)->setMemSize(sectionsize);
+ (*msi)->setAddr(startaddr);
+ }
}
-template<support::endianness target_endianness, bool is64Bits>
-void ELFProgramHeaderChunk<target_endianness, is64Bits>::createPHeaders() {
+ void assignOffsetsForMiscSections() {
+ uint64_t fileoffset = 0;
+ uint64_t size = 0;
+ for (auto si : _segments) {
+ fileoffset = si->fileOffset();
+ size = si->fileSize();
+ }
+ fileoffset = fileoffset + size;
+ Section<target_endianness, is64Bits> *section;
+ for (auto si : _sections) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(si);
+ if (section &&
+ DefaultELFLayout<target_endianness, is64Bits>::hasOutputSegment
+ (section))
+ continue;
+ fileoffset = llvm::RoundUpToAlignment(fileoffset, si->align2());
+ si->setFileOffset(fileoffset);
+ si->setVAddr(0);
+ fileoffset += si->fileSize();
+ }
+ }
- //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 finalize() {
+ for (auto &si : _sections) {
+ si->finalize();
+ }
+ }
- 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();
- }
+ bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
+ Section<target_endianness, is64Bits> *section;
+ for (auto ai = _sections.begin(); ai != _sections.end(); ++ai) {
+ if ((*ai)->kind() == Chunk<target_endianness, is64Bits>::K_ELFSection) {
+ section = llvm::dyn_cast<Section<target_endianness, is64Bits>>(*ai);
+ if (section->findAtomAddrByName(name, addr))
+ return true;
}
-
- 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);
}
+ return false;
}
-}
-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";
-}
+ MergedSectionIter merged_sections_begin() {
+ return _mergedSections.begin();
+ }
-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);
+ MergedSectionIter merged_sections_end() {
+ return _mergedSections.end();
}
-}
-template<support::endianness target_endianness, bool is64Bits>
-StringRef ELFProgramHeaderChunk<target_endianness, is64Bits>
- ::segmentName() const {
- return "PT_NULL";
-}
+
+ ChunkIter sections_begin() {
+ return _sections.begin();
+ }
+ ChunkIter sections_end() {
+ return _sections.end();
+ }
+
+ ChunkIter segments_begin() {
+ return _segments.begin();
+ }
+
+ ChunkIter segments_end() {
+ return _segments.end();
+ }
+
+ ELFHeader<target_endianness, is64Bits> *elfHeader() {
+ return _elfHeader;
+ }
+
+ ELFProgramHeader<target_endianness, is64Bits> *elfProgramHeader() {
+ return _programHeader;
+ }
+
+private:
+ SectionMapT _sectionMap;
+ MergedSectionMapT _mergedSectionMap;
+ SegmentMapT _segmentMap;
+
+ std::vector<Chunk<target_endianness, is64Bits> *> _sections;
+ std::vector<Segment<target_endianness, is64Bits> *> _segments;
+ std::vector<MergedSections<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; }
+ uint64_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;
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>::K_ELFSection)
+ 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>::K_ELFSection)
+ 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>::K_ELFSection)
+ 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>::K_ELFSection)
+ 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>::K_ELFSection)
+ 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->assignFileOffsets();
+ _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 +2057,78 @@
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());
+ uint64_t virtualAddr = 0;
+ _layout->findAtomAddrByName("_start", virtualAddr);
+ _elfHeader->e_entry(virtualAddr);
+ _elfHeader->write(this, buffer);
+ _programHeader->write(this, buffer);
+
return buffer->commit();
}
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!");
}
More information about the llvm-commits
mailing list