[llvm-commits] [lld] r173082 - in /lld/trunk/lib/ReaderWriter/ELF: DefaultELFLayout.h ELFChunk.h ELFHeaderChunks.h ELFLayout.h ELFSectionChunks.h ELFSegmentChunks.h ELFWriter.h WriterELF.cpp
Shankar Easwaran
shankare at codeaurora.org
Mon Jan 21 12:09:55 PST 2013
Author: shankare
Date: Mon Jan 21 14:09:55 2013
New Revision: 173082
URL: http://llvm.org/viewvc/llvm-project?rev=173082&view=rev
Log:
no functionality changes(split WriterELF into multiple files)
Added:
lld/trunk/lib/ReaderWriter/ELF/DefaultELFLayout.h
lld/trunk/lib/ReaderWriter/ELF/ELFChunk.h
lld/trunk/lib/ReaderWriter/ELF/ELFHeaderChunks.h
lld/trunk/lib/ReaderWriter/ELF/ELFLayout.h
lld/trunk/lib/ReaderWriter/ELF/ELFSectionChunks.h
lld/trunk/lib/ReaderWriter/ELF/ELFSegmentChunks.h
lld/trunk/lib/ReaderWriter/ELF/ELFWriter.h
Modified:
lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp
Added: lld/trunk/lib/ReaderWriter/ELF/DefaultELFLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultELFLayout.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DefaultELFLayout.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/DefaultELFLayout.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,629 @@
+//===- lib/ReaderWriter/ELF/DefaultELFLayout.h ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_DEFAULT_ELF_LAYOUT_H_
+#define LLD_READER_WRITER_DEFAULT_ELF_LAYOUT_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 "ELFChunk.h"
+#include "ELFHeaderChunks.h"
+#include "ELFLayout.h"
+#include "ELFSectionChunks.h"
+#include "ELFSegmentChunks.h"
+
+#include <map>
+#include <unordered_map>
+#include <tuple>
+
+/// \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
+
+namespace lld {
+namespace elf {
+
+template<class ELFT>
+class DefaultELFLayout : public ELFLayout {
+public:
+
+ // 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
+ // Change the enumerations so that Target can override and stick
+ // a section anywhere it wants to
+ enum DefaultSectionOrder {
+ ORDER_NOT_DEFINED = 0,
+ ORDER_INTERP = 10,
+ ORDER_NOTE = 20,
+ ORDER_HASH = 30,
+ ORDER_DYNAMIC_SYMBOLS = 40,
+ ORDER_DYNAMIC_STRINGS = 50,
+ ORDER_INIT = 60,
+ ORDER_TEXT = 70,
+ ORDER_PLT = 80,
+ ORDER_FINI = 90,
+ ORDER_RODATA = 100,
+ ORDER_EH_FRAME = 110,
+ ORDER_EH_FRAMEHDR = 120,
+ ORDER_CTORS = 130,
+ ORDER_DTORS = 140,
+ ORDER_INIT_ARRAY = 150,
+ ORDER_FINI_ARRAY = 160,
+ ORDER_DYNAMIC = 170,
+ ORDER_GOT = 180,
+ ORDER_GOT_PLT = 190,
+ ORDER_DATA = 200,
+ ORDER_BSS = 210,
+ ORDER_OTHER = 220,
+ ORDER_SECTION_STRINGS = 230,
+ ORDER_SYMBOL_TABLE = 240,
+ ORDER_STRING_TABLE = 250,
+ ORDER_SECTION_HEADERS = 260
+ };
+
+public:
+
+ // 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<ELFT> *>::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<ELFT> *> MergedSectionMapT;
+ typedef typename std::vector<MergedSections<ELFT> *>::iterator
+ MergedSectionIter;
+
+ // 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);
+ }
+ };
+
+ // 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);
+ }
+ };
+
+ typedef std::unordered_map<Key, Section<ELFT>*, HashKey> SectionMapT;
+ typedef std::unordered_map<SegmentKey,
+ Segment<ELFT>*,
+ SegmentHashKey> SegmentMapT;
+
+ /// \brief All absolute atoms are created in the ELF Layout by using
+ /// an AbsoluteAtomPair. Contains a pair of AbsoluteAtom and the
+ /// value which is the address of the absolute atom
+ class AbsoluteAtomPair {
+ public:
+ AbsoluteAtomPair(const AbsoluteAtom *a, int64_t value)
+ : _absoluteAtom(a)
+ , _value(value) { }
+
+ const AbsoluteAtom *absoluteAtom() { return _absoluteAtom; }
+ int64_t value() const { return _value; }
+ void setValue(int64_t val) { _value = val; }
+
+ private:
+ const AbsoluteAtom *_absoluteAtom;
+ int64_t _value;
+ };
+
+ /// \brief find a absolute atom pair given a absolute atom name
+ struct FindByName {
+ const std::string _name;
+ FindByName(StringRef name) : _name(name) {}
+ bool operator()(AbsoluteAtomPair& j) {
+ return j.absoluteAtom()->name() == _name;
+ }
+ };
+
+ typedef typename std::vector<AbsoluteAtomPair>::iterator AbsoluteAtomIterT;
+
+ DefaultELFLayout(const WriterOptionsELF &options) : _options(options) {}
+
+ /// \brief Return the section order for a input section
+ virtual SectionOrder getSectionOrder
+ (const StringRef name,
+ int32_t contentType,
+ int32_t contentPermissions);
+
+ /// \brief This maps the input sections to the output section names
+ StringRef getSectionName(const StringRef name,
+ const int32_t contentType);
+
+ /// \brief Gets the segment for a output section
+ virtual ELFLayout::SegmentType getSegmentType(Section<ELFT> *section) const;
+
+ /// \brief Returns true/false depending on whether the section has a Output
+ // segment or not
+ static bool hasOutputSegment(Section<ELFT> *section);
+
+ // Adds an atom to the section
+ virtual error_code addAtom(const Atom *atom);
+
+ /// \brief Find an output Section given a section name.
+ MergedSections<ELFT> *findOutputSection(StringRef name) {
+ auto iter = _mergedSectionMap.find(name);
+ if (iter == _mergedSectionMap.end())
+ return nullptr;
+ return iter->second;
+ }
+
+ /// \brief find a absolute atom given a name
+ AbsoluteAtomIterT findAbsoluteAtom(const StringRef name) {
+ return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
+ FindByName(name));
+ }
+
+ // Merge sections with the same name into a MergedSections
+ void mergeSimiliarSections();
+
+ void assignSectionsToSegments();
+
+ void assignVirtualAddress();
+
+ void assignOffsetsForMiscSections();
+
+ void assignFileOffsets();
+
+ /// Inline functions
+ inline range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
+
+ inline void addSection(Chunk<ELFT> *c) {
+ _sections.push_back(c);
+ }
+
+ inline void finalize() {
+ for (auto &si : _sections)
+ si->finalize();
+ }
+
+ inline bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
+ for (auto sec : _sections)
+ if (auto section = dyn_cast<Section<ELFT>>(sec))
+ if (section->findAtomAddrByName(name, addr))
+ return true;
+ return false;
+ }
+
+ inline void setELFHeader(ELFHeader<ELFT> *e) {
+ _elfHeader = e;
+ }
+
+ inline void setProgramHeader(ELFProgramHeader<ELFT> *p) {
+ _programHeader = p;
+ }
+
+ inline range<MergedSectionIter> mergedSections() { return _mergedSections; }
+
+ inline range<ChunkIter> sections() { return _sections; }
+
+ inline range<ChunkIter> segments() { return _segments; }
+
+ inline ELFHeader<ELFT> *elfHeader() {
+ return _elfHeader;
+ }
+
+ inline ELFProgramHeader<ELFT> *elfProgramHeader() {
+ return _programHeader;
+ }
+
+private:
+ SectionMapT _sectionMap;
+ MergedSectionMapT _mergedSectionMap;
+ SegmentMapT _segmentMap;
+ std::vector<Chunk<ELFT> *> _sections;
+ std::vector<Segment<ELFT> *> _segments;
+ std::vector<MergedSections<ELFT> *> _mergedSections;
+ ELFHeader<ELFT> *_elfHeader;
+ ELFProgramHeader<ELFT> *_programHeader;
+ std::vector<AbsoluteAtomPair> _absoluteAtoms;
+ llvm::BumpPtrAllocator _allocator;
+ const WriterOptionsELF _options;
+};
+
+template<class ELFT>
+ELFLayout::SectionOrder
+DefaultELFLayout<ELFT>::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);
+
+ case DefinedAtom::typeConstant:
+ return ORDER_RODATA;
+
+ case DefinedAtom::typeData:
+ return llvm::StringSwitch<Reference::Kind>(name)
+ .StartsWith(".init_array", ORDER_INIT_ARRAY)
+ .Default(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;
+ }
+}
+
+/// \brief This maps the input sections to the output section names
+template<class ELFT>
+StringRef
+DefaultELFLayout<ELFT>::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;
+}
+
+/// \brief Gets the segment for a output section
+template<class ELFT>
+ELFLayout::SegmentType
+DefaultELFLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
+ switch(section->order()) {
+ case ORDER_INTERP:
+ return llvm::ELF::PT_INTERP;
+
+ 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;
+
+ case ORDER_NOTE:
+ return llvm::ELF::PT_NOTE;
+
+ case ORDER_DYNAMIC:
+ return llvm::ELF::PT_DYNAMIC;
+
+ case ORDER_CTORS:
+ case ORDER_DTORS:
+ case ORDER_GOT:
+ return llvm::ELF::PT_GNU_RELRO;
+
+ case ORDER_GOT_PLT:
+ case ORDER_DATA:
+ case ORDER_BSS:
+ case ORDER_INIT_ARRAY:
+ case ORDER_FINI_ARRAY:
+ return llvm::ELF::PT_LOAD;
+
+ default:
+ return llvm::ELF::PT_NULL;
+ }
+}
+
+template<class ELFT>
+bool
+DefaultELFLayout<ELFT>::hasOutputSegment(Section<ELFT> *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_INIT_ARRAY:
+ case ORDER_FINI_ARRAY:
+ case ORDER_BSS:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+template<class ELFT>
+error_code
+DefaultELFLayout<ELFT>::addAtom(const Atom *atom) {
+ if (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<ELFT> *>currentSection(key, nullptr);
+ std::pair<typename SectionMapT::iterator, bool>
+ sectionInsert(_sectionMap.insert(currentSection));
+ Section<ELFT> *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<ELFT>>()) Section<ELFT>(
+ sectionName, contentType, permissions, section_order);
+ sectionInsert.first->second = section;
+ section->setOrder(section_order);
+ _sections.push_back(section);
+ }
+ section->appendAtom(atom);
+ }
+ // Absolute atoms are not part of any section, they are global for the whole
+ // link
+ else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
+ _absoluteAtoms.push_back(AbsoluteAtomPair(absoluteAtom,
+ absoluteAtom->value()));
+ }
+ else
+ llvm_unreachable("Only absolute / defined atoms can be added here");
+ return error_code::success();
+}
+
+/// Merge sections with the same name into a MergedSections
+template<class ELFT>
+void
+DefaultELFLayout<ELFT>::mergeSimiliarSections() {
+ MergedSections<ELFT> *mergedSection;
+
+ for (auto &si : _sections) {
+ const std::pair<StringRef, MergedSections<ELFT> *>
+ 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<ELFT>>())
+ MergedSections<ELFT>(si->name());
+ _mergedSections.push_back(mergedSection);
+ mergedSectionInsert.first->second = mergedSection;
+ }
+ mergedSection->appendSection(si);
+ }
+}
+
+template<class ELFT>
+void
+DefaultELFLayout<ELFT>::assignSectionsToSegments() {
+ // sort the sections by their order as defined by the layout
+ std::stable_sort(_sections.begin(), _sections.end(),
+ [](Chunk<ELFT> *A, Chunk<ELFT> *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->sections()) {
+ ai->setOrdinal(ordinal);
+ }
+ ++ordinal;
+ }
+ for (auto msi : _mergedSections) {
+ for (auto ai : msi->sections()) {
+ if (auto section = dyn_cast<Section<ELFT>>(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<ELFT> *>
+ currentSegment(key, nullptr);
+ std::pair<typename SegmentMapT::iterator, bool>
+ segmentInsert(_segmentMap.insert(currentSegment));
+ Segment<ELFT> *segment;
+ if (!segmentInsert.second) {
+ segment = segmentInsert.first->second;
+ } else {
+ segment = new (_allocator.Allocate<Segment<ELFT>>()) Segment<ELFT>(
+ segmentName, getSegmentType(section), _options);
+ segmentInsert.first->second = segment;
+ _segments.push_back(segment);
+ }
+ segment->append(section);
+ }
+ }
+ }
+}
+
+template<class ELFT>
+void
+DefaultELFLayout<ELFT>::assignFileOffsets() {
+ std::sort(_segments.begin(), _segments.end(),
+ Segment<ELFT>::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<class ELFT>
+void
+DefaultELFLayout<ELFT>::assignVirtualAddress() {
+ if (_segments.empty())
+ return;
+
+ uint64_t virtualAddress = _options.baseAddress();
+
+ // HACK: This is a super dirty hack. The elf header and program header are
+ // not part of a section, but we need them to be loaded at the base address
+ // so that AT_PHDR is set correctly by the loader and so they are accessible
+ // at runtime. To do this we simply prepend them to the first Segment and
+ // let the layout logic take care of it.
+ _segments[0]->prepend(_programHeader);
+ _segments[0]->prepend(_elfHeader);
+
+ bool newSegmentHeaderAdded = true;
+ while (true) {
+ for (auto si : _segments) {
+ newSegmentHeaderAdded = _programHeader->addSegment(si);
+ }
+ if (!newSegmentHeaderAdded)
+ break;
+ uint64_t fileoffset = 0;
+ 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)->setMemSize(address - virtualAddress);
+ virtualAddress = llvm::RoundUpToAlignment(address,
+ _options.pageSize());
+ }
+ _programHeader->resetProgramHeaders();
+ }
+ Section<ELFT> *section;
+ // Fix the offsets of all the atoms within a section
+ for (auto &si : _sections) {
+ section = dyn_cast<Section<ELFT>>(si);
+ if (section && DefaultELFLayout<ELFT>::hasOutputSegment(section))
+ section->assignOffsets(section->fileOffset());
+ }
+ // Set the size of the merged Sections
+ for (auto msi : _mergedSections) {
+ uint64_t sectionfileoffset = 0;
+ uint64_t startFileOffset = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si : msi->sections()) {
+ 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 : _mergedSections) {
+ uint64_t sectionstartaddr = 0;
+ uint64_t startaddr = 0;
+ uint64_t sectionsize = 0;
+ bool isFirstSection = true;
+ for (auto si : msi->sections()) {
+ if (isFirstSection) {
+ startaddr = si->virtualAddr();
+ isFirstSection = false;
+ }
+ sectionstartaddr = si->virtualAddr();
+ sectionsize = si->memSize();
+ }
+ sectionsize = (sectionstartaddr - startaddr) + sectionsize;
+ msi->setMemSize(sectionsize);
+ msi->setAddr(startaddr);
+ }
+}
+
+template<class ELFT>
+void
+DefaultELFLayout<ELFT>::assignOffsetsForMiscSections() {
+ uint64_t fileoffset = 0;
+ uint64_t size = 0;
+ for (auto si : _segments) {
+ fileoffset = si->fileOffset();
+ size = si->fileSize();
+ }
+ fileoffset = fileoffset + size;
+ Section<ELFT> *section;
+ for (auto si : _sections) {
+ section = dyn_cast<Section<ELFT>>(si);
+ if (section && DefaultELFLayout<ELFT>::hasOutputSegment(section))
+ continue;
+ fileoffset = llvm::RoundUpToAlignment(fileoffset, si->align2());
+ si->setFileOffset(fileoffset);
+ si->setVAddr(0);
+ fileoffset += si->fileSize();
+ }
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_DEFAULT_ELF_LAYOUT_H_
Added: lld/trunk/lib/ReaderWriter/ELF/ELFChunk.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFChunk.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFChunk.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFChunk.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,99 @@
+//===- lib/ReaderWriter/ELF/ELFChunks.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_CHUNKS_H_
+#define LLD_READER_WRITER_ELF_CHUNKS_H_
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+namespace lld {
+namespace elf {
+
+class ELFWriter;
+
+/// \brief A chunk is a contiguous region of space
+template<class ELFT>
+class Chunk {
+public:
+
+ /// \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(llvm::StringRef name, Kind kind)
+ : _name(name)
+ , _kind(kind)
+ , _fsize(0)
+ , _msize(0)
+ , _align2(0)
+ , _order(0)
+ , _ordinal(1)
+ , _start(0)
+ , _fileoffset(0) {}
+ virtual ~Chunk() {}
+ // Does the chunk occupy disk space
+ virtual bool occupiesNoDiskSpace() const {
+ return false;
+ }
+ // The name of the chunk
+ llvm::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;}
+ // 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,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer) = 0;
+ // Finalize the chunk before writing
+ virtual void finalize() = 0;
+
+protected:
+ llvm::StringRef _name;
+ Kind _kind;
+ uint64_t _fsize;
+ uint64_t _msize;
+ uint64_t _align2;
+ uint32_t _order;
+ uint64_t _ordinal;
+ uint64_t _start;
+ uint64_t _fileoffset;
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_CHUNKS_H_
Added: lld/trunk/lib/ReaderWriter/ELF/ELFHeaderChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFHeaderChunks.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFHeaderChunks.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFHeaderChunks.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,316 @@
+//===- lib/ReaderWriter/ELF/ELFHeaderChunks.h -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_HEADER_CHUNKS_H_
+#define LLD_READER_WRITER_ELF_HEADER_CHUNKS_H_
+
+#include "llvm/Object/ELF.h"
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+#include "ELFSegmentChunks.h"
+
+/// \brief An ELFHeader represents the Elf[32/64]_Ehdr structure at the
+/// start of an ELF executable file.
+namespace lld {
+namespace elf {
+
+template<class ELFT>
+class ELFHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
+
+ ELFHeader();
+
+ 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<ELFT> *c) {
+ return c->Kind() == Chunk<ELFT>::K_ELFHeader;
+ }
+
+ void write(ELFWriter *writer, llvm::OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ void finalize() { }
+
+private:
+ Elf_Ehdr _eh;
+};
+
+template<class ELFT>
+ELFHeader<ELFT>::ELFHeader()
+: Chunk<ELFT>("elfhdr", Chunk<ELFT>::K_ELFHeader) {
+ this->_align2 = ELFT::Is64Bits ? 8 : 4;
+ this->_fsize = sizeof(Elf_Ehdr);
+ this->_msize = sizeof(Elf_Ehdr);
+ memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT);
+ e_ident(llvm::ELF::EI_MAG0, 0x7f);
+ e_ident(llvm::ELF::EI_MAG1, 'E');
+ e_ident(llvm::ELF::EI_MAG2, 'L');
+ e_ident(llvm::ELF::EI_MAG3, 'F');
+ e_ehsize(sizeof(Elf_Ehdr));
+ e_flags(2);
+}
+
+template<class ELFT>
+void
+ELFHeader<ELFT>::write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer) {
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ uint8_t *atomContent = chunkBuffer + this->fileOffset();
+ memcpy(atomContent, &_eh, fileSize());
+}
+
+/// \brief An ELFProgramHeader represents the Elf[32/64]_Phdr structure at the
+/// start of an ELF executable file.
+template<class ELFT>
+class ELFProgramHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Phdr_Impl<ELFT> Elf_Phdr;
+ typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
+
+ /// \brief Find a program header entry, given the type of entry that
+ /// we are looking for
+ class FindPhdr {
+ public:
+ FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
+ : _type(type)
+ , _flags(flags)
+ , _flagsClear(flagsClear)
+ {}
+
+ bool operator()(const Elf_Phdr *j) const {
+ return ((j->p_type == _type) &&
+ ((j->p_flags & _flags) == _flags) &&
+ (!(j->p_flags & _flagsClear)));
+ }
+ private:
+ uint64_t _type;
+ uint64_t _flags;
+ uint64_t _flagsClear;
+ };
+
+ ELFProgramHeader()
+ : Chunk<ELFT>("elfphdr", Chunk<ELFT>::K_ELFProgramHeader) {
+ this->_align2 = ELFT::Is64Bits ? 8 : 4;
+ resetProgramHeaders();
+ }
+
+ bool addSegment(Segment<ELFT> *segment);
+
+ void resetProgramHeaders() {
+ _phi = _ph.begin();
+ }
+
+ uint64_t fileSize() {
+ return sizeof(Elf_Phdr) * _ph.size();
+ }
+
+ static inline bool classof(const Chunk<ELFT> *c) {
+ return c->Kind() == Chunk<ELFT>::K_ELFProgramHeader;
+ }
+
+ void write(ELFWriter *writer, llvm::OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ /// \brief find a program header entry in the list of program headers
+ PhIterT findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
+ return std::find_if(_ph.begin(), _ph.end(),
+ FindPhdr(type, flags, flagClear));
+ }
+
+ PhIterT begin() {
+ return _ph.begin();
+ }
+
+ PhIterT end() {
+ return _ph.end();
+ }
+
+ void finalize() { }
+
+ int64_t entsize() {
+ return sizeof(Elf_Phdr);
+ }
+
+ int64_t numHeaders() {
+ return _ph.size();
+ }
+
+private:
+ std::vector<Elf_Phdr *> _ph;
+ PhIterT _phi;
+ llvm::BumpPtrAllocator _allocator;
+};
+
+template<class ELFT>
+bool
+ELFProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
+ Elf_Phdr *phdr = nullptr;
+ bool ret = false;
+
+ for (auto slice : segment->slices()) {
+ 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 = slice->fileOffset();
+ phdr->p_vaddr = slice->virtualAddr();
+ phdr->p_paddr = slice->virtualAddr();
+ phdr->p_filesz = slice->fileSize();
+ phdr->p_memsz = slice->memSize();
+ phdr->p_flags = segment->flags();
+ phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
+ segment->pageSize() : slice->align2();
+ }
+ this->_fsize = fileSize();
+ this->_msize = this->_fsize;
+
+ return ret;
+}
+
+template<class ELFT>
+void
+ELFProgramHeader<ELFT>::write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer) {
+ 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);
+ }
+}
+
+/// \brief An ELFSectionHeader represents the Elf[32/64]_Shdr structure
+/// at the end of the file
+template<class ELFT>
+class ELFSectionHeader : public Chunk<ELFT> {
+public:
+ typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+ ELFSectionHeader(int32_t order);
+
+ void appendSection(MergedSections<ELFT> *section);
+
+ void updateSection(Section<ELFT> *section);
+
+ static inline bool classof(const Chunk<ELFT> *c) {
+ return c->getChunkKind() == Chunk<ELFT>::K_ELFSectionHeader;
+ }
+
+ void setStringSection(ELFStringTable<ELFT> *s) {
+ _stringSection = s;
+ }
+
+ void write(ELFWriter *writer, llvm::OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ void finalize() { }
+
+ inline uint16_t fileSize() {
+ return sizeof(Elf_Shdr) * _sectionInfo.size();
+ }
+
+ inline int64_t entsize() {
+ return sizeof(Elf_Shdr);
+ }
+
+ inline int64_t numHeaders() {
+ return _sectionInfo.size();
+ }
+
+private:
+ ELFStringTable<ELFT> *_stringSection;
+ std::vector<Elf_Shdr*> _sectionInfo;
+ llvm::BumpPtrAllocator _sectionAllocate;
+};
+
+template<class ELFT>
+ELFSectionHeader<ELFT>::ELFSectionHeader(int32_t order)
+ : Chunk<ELFT>("shdr", Chunk<ELFT>::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<class ELFT>
+void
+ELFSectionHeader<ELFT>::appendSection(MergedSections<ELFT> *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);
+}
+
+template<class ELFT>
+void
+ELFSectionHeader<ELFT>::updateSection(Section<ELFT> *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();
+}
+
+template<class ELFT>
+void
+ELFSectionHeader<ELFT>::write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::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);
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_HEADER_CHUNKS_H_
Added: lld/trunk/lib/ReaderWriter/ELF/ELFLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLayout.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLayout.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLayout.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,74 @@
+//===- lib/ReaderWriter/ELF/ELFLayout.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_LAYOUT_H_
+#define LLD_READER_WRITER_ELF_LAYOUT_H_
+
+#include "lld/Core/DefinedAtom.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/Object/ELF.h"
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+
+namespace lld {
+namespace elf {
+/// \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 llvm::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 llvm::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() {}
+
+ virtual ~ELFLayout() { }
+};
+
+struct AtomLayout {
+ AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr)
+ : _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {}
+
+ AtomLayout()
+ : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {}
+
+ const Atom *_atom;
+ uint64_t _fileOffset;
+ uint64_t _virtualAddr;
+};
+} // lld
+} // elf
+
+#endif // LLD_READER_WRITER_ELF_LAYOUT_H_
Added: lld/trunk/lib/ReaderWriter/ELF/ELFSectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFSectionChunks.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFSectionChunks.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFSectionChunks.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,706 @@
+//===- lib/ReaderWriter/ELF/ELFSectionChunks.h -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_SECTION_CHUNKS_H_
+#define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H_
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/range.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/Object/ELF.h"
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+#include "ELFChunk.h"
+#include "ELFLayout.h"
+#include "ELFWriter.h"
+
+namespace lld {
+namespace elf {
+
+/// \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<class ELFT>
+class Section : public Chunk<ELFT> {
+public:
+ // The Kind of section that the object represents
+ enum SectionKind {
+ K_Default,
+ K_Target, // The section is handed over to the target
+ K_SymbolTable,
+ K_StringTable,
+ };
+ // Create a section object, the section is set to the default type if the
+ // caller doesnot set it
+ Section(const llvm::StringRef sectionName,
+ const int32_t contentType,
+ const int32_t contentPermissions,
+ const int32_t order,
+ const SectionKind kind = K_Default);
+
+ /// return the section kind
+ inline SectionKind sectionKind() const {
+ return _sectionKind;
+ }
+
+ /// Align the offset to the required modulus defined by the atom alignment
+ uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
+
+ // \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);
+
+ /// \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
+ inline void assignVirtualAddress(uint64_t &addr) {
+ for (auto &ai : _atoms) {
+ ai._virtualAddr = addr + ai._fileOffset;
+ }
+ 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
+ inline void assignOffsets(uint64_t offset) {
+ for (auto &ai : _atoms) {
+ ai._fileOffset = offset + ai._fileOffset;
+ }
+ }
+
+ /// \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
+ inline bool findAtomAddrByName(const llvm::StringRef name, uint64_t &addr) {
+ for (auto ai : _atoms) {
+ if (ai._atom->name() == name) {
+ addr = ai._virtualAddr;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// \brief Does the Atom occupy any disk space
+ inline 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
+ inline 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();
+
+ /// \brief Return the section type, the returned value is recorded in the
+ /// sh_type field of the Section Header
+ int type();
+
+ /// \brief convert the segment type to a String for diagnostics
+ /// and printing purposes
+ llvm::StringRef segmentKindToStr() const;
+
+ /// \brief Return the raw flags, we need this to sort segments
+ inline int64_t atomflags() const {
+ return _contentPermissions;
+ }
+
+ /// \brief Returns the section link field, the returned value is
+ /// recorded in the sh_link field of the Section Header
+ inline int link() const {
+ return _link;
+ }
+
+ inline 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
+ inline int entsize() const {
+ return _entSize;
+ }
+
+ /// \brief Returns the shinfo field, the returned value is
+ /// recorded in the sh_info field of the Section Header
+ inline int shinfo() const {
+ return _shInfo;
+ }
+
+ /// \brief Records the segmentType, that this section belongs to
+ inline void setSegment(const ELFLayout::SegmentType segmentType) {
+ _segmentType = segmentType;
+ }
+
+ /// \brief for LLVM style RTTI information
+ static inline bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::K_ELFSection;
+ }
+
+ /// \brief Finalize the section contents before writing
+ inline void finalize() { }
+
+ /// \brief Write the section and the atom contents to the buffer
+ void write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ /// Atom Iterators
+ typedef typename std::vector<AtomLayout>::iterator atom_iter;
+
+ range<atom_iter> atoms() { return _atoms; }
+
+protected:
+ int32_t _contentType;
+ int32_t _contentPermissions;
+ SectionKind _sectionKind;
+ std::vector<AtomLayout> _atoms;
+ ELFLayout::SegmentType _segmentType;
+ int64_t _entSize;
+ int64_t _shInfo;
+ int64_t _link;
+};
+
+// Create a section object, the section is set to the default type if the
+// caller doesnot set it
+template<class ELFT>
+Section<ELFT>::Section(const StringRef sectionName,
+ const int32_t contentType,
+ const int32_t contentPermissions,
+ const int32_t order,
+ const SectionKind kind)
+ : Chunk<ELFT>(sectionName, Chunk<ELFT>::K_ELFSection)
+ , _contentType(contentType)
+ , _contentPermissions(contentPermissions)
+ , _sectionKind(kind)
+ , _entSize(0)
+ , _shInfo(0)
+ , _link(0) {
+ this->setOrder(order);
+}
+
+/// Align the offset to the required modulus defined by the atom alignment
+template<class ELFT>
+uint64_t
+Section<ELFT>::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 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
+template<class ELFT>
+void
+Section<ELFT>::appendAtom(const Atom *atom) {
+ Atom::Definition atomType = atom->definition();
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
+
+ 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:
+ case DefinedAtom::typeConstant:
+ _atoms.push_back(AtomLayout(atom, fOffset, 0));
+ this->_fsize = fOffset + definedAtom->size();
+ this->_msize = mOffset + definedAtom->size();
+ break;
+ case DefinedAtom::typeZeroFill:
+ _atoms.push_back(AtomLayout(atom, 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 Get the section flags, defined by the permissions of the section
+template<class ELFT>
+int64_t
+Section<ELFT>::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 section type, the returned value is recorded in the
+/// sh_type field of the Section Header
+
+template<class ELFT>
+int
+Section<ELFT>::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 convert the segment type to a String for diagnostics
+/// and printing purposes
+template<class ELFT>
+StringRef
+Section<ELFT>::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 Write the section and the atom contents to the buffer
+template<class ELFT>
+void
+Section<ELFT>::write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer) {
+ uint8_t *chunkBuffer = buffer->getBufferStart();
+ for (auto &ai : _atoms) {
+ const DefinedAtom *definedAtom = cast<DefinedAtom>(ai._atom);
+ if (definedAtom->contentType() == DefinedAtom::typeZeroFill)
+ continue;
+ // Copy raw content of atom to file buffer.
+ llvm::ArrayRef<uint8_t> content = definedAtom->rawContent();
+ uint64_t contentSize = content.size();
+ if (contentSize == 0)
+ continue;
+ uint8_t *atomContent = chunkBuffer + ai._fileOffset;
+ std::copy_n(content.data(), contentSize, atomContent);
+ for (const auto ref : *definedAtom) {
+ uint32_t offset = ref->offsetInAtom();
+ uint64_t targetAddress = 0;
+ assert(ref->target() != nullptr && "Found the target to be NULL");
+ targetAddress = writer->addressOfAtom(ref->target());
+ uint64_t fixupAddress = writer->addressOfAtom(ai._atom) + offset;
+ // apply the relocation
+ writer->kindHandler()->applyFixup(ref->kind(),
+ ref->addend(),
+ &atomContent[offset],
+ fixupAddress,
+ targetAddress);
+ }
+ }
+}
+
+/// \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<class ELFT>
+class MergedSections {
+public:
+ // Iterators
+ typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
+
+ MergedSections(llvm::StringRef name);
+
+ // Appends a section into the list of sections that are part of this Merged
+ // Section
+ void appendSection(Chunk<ELFT> *c);
+
+ // Set the MergedSections is associated with a segment
+ inline void setHasSegment() { _hasSegment = true; }
+
+ /// Sets the ordinal
+ inline void setOrdinal(uint64_t ordinal) {
+ _ordinal = ordinal;
+ }
+
+ /// Sets the Memory size
+ inline void setMemSize(uint64_t memsz) {
+ _memSize = memsz;
+ }
+
+ /// Sets the size fo the merged Section
+ inline void setSize(uint64_t fsiz) {
+ _size = fsiz;
+ }
+
+ // The offset of the first section contained in the merged section is
+ // contained here
+ inline void setFileOffset(uint64_t foffset) {
+ _fileOffset = foffset;
+ }
+
+ // Sets the starting address of the section
+ inline void setAddr(uint64_t addr) {
+ _virtualAddr = addr;
+ }
+
+ inline range<ChunkIter> sections() { return _sections; }
+
+ // The below functions returns the properties of the MergeSection
+ inline bool hasSegment() const { return _hasSegment; }
+
+ inline llvm::StringRef name() const { return _name; }
+
+ inline int64_t shinfo() const { return _shInfo; }
+
+ inline uint64_t align2() const { return _align2; }
+
+ inline int64_t link() const { return _link; }
+
+ inline int64_t type() const { return _type; }
+
+ inline uint64_t virtualAddr() const { return _virtualAddr; }
+
+ inline int64_t ordinal() const { return _ordinal; }
+
+ inline int64_t kind() const { return _kind; }
+
+ inline uint64_t fileSize() const { return _size; }
+
+ inline int64_t entsize() const { return _entSize; }
+
+ inline uint64_t fileOffset() const { return _fileOffset; }
+
+ inline int64_t flags() const { return _flags; }
+
+ inline uint64_t memSize() { return _memSize; }
+
+private:
+ llvm::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<ELFT> *> _sections;
+};
+
+/// MergedSections
+template<class ELFT>
+MergedSections<ELFT>::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) { }
+
+
+template<class ELFT>
+void
+MergedSections<ELFT>::appendSection(Chunk<ELFT> *c) {
+ if (c->align2() > _align2)
+ _align2 = c->align2();
+ if (const auto section = dyn_cast<Section<ELFT>>(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);
+}
+
+/// \brief The class represents the ELF String Table
+template<class ELFT>
+class ELFStringTable : public Section<ELFT> {
+public:
+ ELFStringTable(const char *str, int32_t order);
+
+ static inline bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Section<ELFT>::K_StringTable;
+ }
+
+ uint64_t addString(const llvm::StringRef symname);
+
+ void write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ inline void finalize() { }
+
+private:
+ std::vector<llvm::StringRef> _strings;
+};
+
+template<class ELFT>
+ELFStringTable<ELFT>::ELFStringTable(const char *str,
+ int32_t order)
+ : Section<ELFT>(
+ str,
+ llvm::ELF::SHT_STRTAB,
+ DefinedAtom::perm___,
+ order,
+ Section<ELFT>::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);
+}
+
+template<class ELFT>
+uint64_t
+ELFStringTable<ELFT>::addString(const StringRef symname) {
+ _strings.push_back(symname);
+ uint64_t offset = this->_fsize;
+ this->_fsize += symname.size() + 1;
+ return offset;
+}
+
+template<class ELFT>
+void
+ELFStringTable<ELFT>::write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::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;
+ }
+}
+
+/// \brief The ELFSymbolTable class represents the symbol table in a ELF file
+template<class ELFT>
+class ELFSymbolTable : public Section<ELFT> {
+public:
+ typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+
+ ELFSymbolTable(const char *str, int32_t order);
+
+ void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0);
+
+ void finalize();
+
+ void write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ static inline bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Section<ELFT>::K_SymbolTable;
+ }
+
+ inline void setStringSection(ELFStringTable<ELFT> *s) {
+ _stringSection = s;
+ }
+
+private:
+ ELFStringTable<ELFT> *_stringSection;
+ std::vector<Elf_Sym*> _symbolTable;
+ llvm::BumpPtrAllocator _symbolAllocate;
+ int64_t _link;
+};
+
+/// ELF Symbol Table
+template<class ELFT>
+ELFSymbolTable<ELFT>::ELFSymbolTable(const char *str,
+ int32_t order)
+ : Section<ELFT>(
+ str,
+ llvm::ELF::SHT_SYMTAB,
+ 0,
+ order,
+ Section<ELFT>::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 *);
+}
+
+template<class ELFT>
+void
+ELFSymbolTable<ELFT>::addSymbol(const Atom *atom,
+ int32_t sectionIndex,
+ uint64_t addr) {
+ 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 = llvm::ELF::STV_DEFAULT;
+ if (const DefinedAtom *da = 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 = llvm::ELF::STT_FUNC;
+ break;
+ case DefinedAtom::typeData:
+ case DefinedAtom::typeConstant:
+ symbol->st_value = addr;
+ type = llvm::ELF::STT_OBJECT;
+ break;
+ case DefinedAtom::typeZeroFill:
+ type = llvm::ELF::STT_OBJECT;
+ symbol->st_value = addr;
+ break;
+ default:
+ type = llvm::ELF::STT_NOTYPE;
+ }
+ if (da->scope() == DefinedAtom::scopeTranslationUnit)
+ binding = llvm::ELF::STB_LOCAL;
+ else
+ binding = llvm::ELF::STB_GLOBAL;
+ } else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom)){
+ type = llvm::ELF::STT_OBJECT;
+ symbol->st_shndx = llvm::ELF::SHN_ABS;
+ switch (aa->scope()) {
+ case AbsoluteAtom::scopeLinkageUnit:
+ symbol->st_other = llvm::ELF::STV_HIDDEN;
+ binding = llvm::ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeTranslationUnit:
+ binding = llvm::ELF::STB_LOCAL;
+ break;
+ case AbsoluteAtom::scopeGlobal:
+ binding = llvm::ELF::STB_GLOBAL;
+ break;
+ }
+ symbol->st_value = addr;
+ } else {
+ symbol->st_value = 0;
+ type = llvm::ELF::STT_NOTYPE;
+ binding = llvm::ELF::STB_WEAK;
+ }
+ symbol->setBindingAndType(binding, type);
+ _symbolTable.push_back(symbol);
+ this->_fsize += sizeof(Elf_Sym);
+}
+
+template<class ELFT>
+void
+ELFSymbolTable<ELFT>::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() != llvm::ELF::STB_LOCAL)
+ break;
+ shInfo++;
+ }
+ this->_shInfo = shInfo;
+ this->setLink(_stringSection->ordinal());
+}
+
+template<class ELFT>
+void
+ELFSymbolTable<ELFT>::write(ELFWriter *writer,
+ llvm::OwningPtr<llvm::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);
+ }
+}
+
+} // elf
+} // lld
+
+#endif //LLD_READER_WRITER_ELF_SECTION_CHUNKS_H_
Added: lld/trunk/lib/ReaderWriter/ELF/ELFSegmentChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFSegmentChunks.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFSegmentChunks.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFSegmentChunks.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,383 @@
+//===- lib/ReaderWriter/ELF/ELFSegmentChunks.h -----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H_
+#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H_
+
+#include "lld/Core/range.h"
+#include "lld/ReaderWriter/WriterELF.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/Object/ELF.h"
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+
+#include "ELFChunk.h"
+#include "ELFLayout.h"
+#include "ELFSectionChunks.h"
+#include "ELFWriter.h"
+
+/// \brief A segment can be divided into segment slices
+/// depending on how the segments can be split
+namespace lld {
+namespace elf {
+
+template<class ELFT>
+class SegmentSlice {
+public:
+ typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
+
+ SegmentSlice() { }
+
+ /// Set the segment slice so that it begins at the offset specified
+ /// by file offset 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;
+ }
+
+ // Set the segment slice start and end iterators. This is used to walk through
+ // the sections that are part of the Segment slice
+ inline void setSections(range<SectionIter> sections) {
+ _sections = sections;
+ }
+
+ // Return the fileOffset of the slice
+ inline uint64_t fileOffset() const { return _offset; }
+
+ // Return the size of the slice
+ inline uint64_t fileSize() const { return _size; }
+
+ // Return the start of the slice
+ inline int32_t startSection() const { return _startSection; }
+
+ // Return the start address of the slice
+ inline uint64_t virtualAddr() const { return _addr; }
+
+ // Return the memory size of the slice
+ inline uint64_t memSize() const { return _memSize; }
+
+ // Return the alignment of the slice
+ inline uint64_t align2() const { return _align2; }
+
+ inline void setSize(uint64_t sz) { _size = sz; }
+
+ inline void setMemSize(uint64_t memsz) { _memSize = memsz; }
+
+ inline void setVAddr(uint64_t addr) { _addr = addr; }
+
+ inline void setAlign(uint64_t align) { _align2 = align; }
+
+ static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b) {
+ return a->startSection() < b->startSection();
+ }
+
+ inline range<SectionIter> sections() {
+ return _sections;
+ }
+
+private:
+ int32_t _startSection;
+ int32_t _endSection;
+ range<SectionIter> _sections;
+ uint64_t _addr;
+ uint64_t _offset;
+ uint64_t _size;
+ uint64_t _align2;
+ uint64_t _memSize;
+};
+
+/// \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<class ELFT>
+class Segment : public Chunk<ELFT> {
+public:
+ typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
+ typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
+
+ Segment(const StringRef name,
+ const ELFLayout::SegmentType type,
+ const WriterOptionsELF &options);
+
+ /// append a section to a segment
+ void append(Section<ELFT> *section);
+
+ /// 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<ELFT> *sega, Segment<ELFT> *segb);
+
+ /// \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);
+
+ /// \brief Assign virtual addresses to the slices
+ void assignVirtualAddress(uint64_t &addr);
+
+ // Write the Segment
+ void write(ELFWriter *writer, OwningPtr<llvm::FileOutputBuffer> &buffer);
+
+ int64_t flags() const;
+
+ /// Prepend a generic chunk to the segment.
+ void prepend(Chunk<ELFT> *c) {
+ _sections.insert(_sections.begin(), c);
+ }
+
+ // Finalize the segment, before we want to write to the output file
+ inline void finalize() { }
+
+ // For LLVM RTTI
+ static inline bool classof(const Chunk<ELFT> *c) {
+ return c->kind() == Chunk<ELFT>::K_ELFSegment;
+ }
+
+ // Getters
+ inline int32_t sectionCount() const {
+ return _sections.size();
+ }
+
+ inline ELFLayout::SegmentType segmentType() { return _segmentType; }
+
+ inline int pageSize() const { return _options.pageSize(); }
+
+ inline int64_t atomflags() const { return _atomflags; }
+
+ inline int64_t numSlices() const {
+ return _segmentSlices.size();
+ }
+
+ inline range<SliceIter> slices() { return _segmentSlices; }
+
+ // These two accessors are still needed for a call to std::stable_sort.
+ // Consider adding wrappers for two iterator algorithms.
+ inline SliceIter slices_begin() {
+ return _segmentSlices.begin();
+ }
+
+ inline SliceIter slices_end() {
+ return _segmentSlices.end();
+ }
+
+protected:
+ /// \brief Section or some other chunk type.
+ std::vector<Chunk<ELFT> *> _sections;
+ std::vector<SegmentSlice<ELFT> *> _segmentSlices;
+ ELFLayout::SegmentType _segmentType;
+ int64_t _flags;
+ int64_t _atomflags;
+ const WriterOptionsELF _options;
+ llvm::BumpPtrAllocator _segmentAllocate;
+};
+
+template<class ELFT>
+Segment<ELFT>::Segment(const StringRef name,
+ const ELFLayout::SegmentType type,
+ const WriterOptionsELF &options)
+ : Chunk<ELFT>(name, Chunk<ELFT>::K_ELFSegment)
+ , _segmentType(type)
+ , _flags(0)
+ , _atomflags(0)
+ , _options(options) {
+ this->_align2 = 0;
+ this->_fsize = 0;
+}
+
+template<class ELFT>
+void
+Segment<ELFT>::append(Section<ELFT> *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();
+}
+
+template<class ELFT>
+bool
+Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
+ if (sega->atomflags() < segb->atomflags())
+ return false;
+ return true;
+}
+
+template<class ELFT>
+void
+Segment<ELFT>::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<ELFT> *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 s : slices()) {
+ if (s->startSection() == startSection) {
+ slice = s;
+ break;
+ }
+ }
+ if (!slice) {
+ slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
+ SegmentSlice<ELFT>();
+ _segmentSlices.push_back(slice);
+ }
+ slice->set(curSliceFileOffset, startSection, currSection);
+ slice->setSections(make_range(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<ELFT> *slice = nullptr;
+ for (auto s : slices()) {
+ // TODO: add std::find
+ if (s->startSection() == startSection) {
+ slice = s;
+ break;
+ }
+ }
+ if (!slice) {
+ slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
+ SegmentSlice<ELFT>();
+ _segmentSlices.push_back(slice);
+ }
+ slice->set(curSliceFileOffset, startSection, currSection);
+ slice->setSections(make_range(startSectionIter, _sections.end()));
+ slice->setSize(curSliceSize);
+ slice->setAlign(sliceAlign);
+ this->_fsize = curSliceFileOffset - startOffset + curSliceSize;
+ std::stable_sort(slices_begin(), slices_end(),
+ SegmentSlice<ELFT>::compare_slices);
+}
+
+/// \brief Assign virtual addresses to the slices
+template<class ELFT>
+void
+Segment<ELFT>::assignVirtualAddress(uint64_t &addr) {
+ for (auto slice : slices()) {
+ // Align to a page
+ addr = llvm::RoundUpToAlignment(addr, _options.pageSize());
+ // Align to the slice alignment
+ addr = llvm::RoundUpToAlignment(addr, slice->align2());
+
+ bool virtualAddressSet = false;
+ for (auto section : slice->sections()) {
+ // Align the section address
+ addr = llvm::RoundUpToAlignment(addr, section->align2());
+ if (!virtualAddressSet) {
+ slice->setVAddr(addr);
+ virtualAddressSet = true;
+ }
+ section->setVAddr(addr);
+ if (auto s = dyn_cast<Section<ELFT>>(section))
+ s->assignVirtualAddress(addr);
+ else
+ addr += section->memSize();
+ section->setMemSize(addr - section->virtualAddr());
+ }
+ slice->setMemSize(addr - slice->virtualAddr());
+ }
+}
+
+// Write the Segment
+template<class ELFT>
+void
+Segment<ELFT>::write(ELFWriter *writer, OwningPtr<llvm::FileOutputBuffer> &buffer) {
+ for (auto slice : slices())
+ for (auto section : slice->sections())
+ section->write(writer, buffer);
+}
+
+template<class ELFT>
+int64_t
+Segment<ELFT>::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;
+}
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H_
Added: lld/trunk/lib/ReaderWriter/ELF/ELFWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFWriter.h?rev=173082&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFWriter.h (added)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFWriter.h Mon Jan 21 14:09:55 2013
@@ -0,0 +1,44 @@
+//===- lib/ReaderWriter/ELF/ELFWriter.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_WRITER_H_
+#define LLD_READER_WRITER_ELF_WRITER_H_
+
+#include "lld/Core/File.h"
+#include "lld/Core/InputFiles.h"
+#include "lld/ReaderWriter/WriterELF.h"
+#include "ReferenceKinds.h"
+
+namespace lld {
+namespace elf {
+/// \brief The ELFWriter class is a base class for the linker to write
+/// various kinds of ELF files.
+class ELFWriter : public Writer {
+public:
+ ELFWriter() { }
+
+public:
+ /// \brief builds the chunks that needs to be written to the output
+ /// ELF file
+ virtual void buildChunks(const lld::File &file) = 0;
+
+ /// \brief Writes the chunks into the output file specified by path
+ virtual error_code writeFile(const lld::File &File, StringRef path) = 0;
+
+ /// \brief Get the virtual address of \p atom after layout.
+ virtual uint64_t addressOfAtom(const Atom *atom) = 0;
+
+ /// \brief Return the processing function to apply Relocations
+ virtual KindHandler *kindHandler() = 0;
+};
+
+} // elf
+} // lld
+
+#endif // LLD_READER_WRITER_ELF_WRITER_H_
Modified: lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp?rev=173082&r1=173081&r2=173082&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/WriterELF.cpp Mon Jan 21 14:09:55 2013
@@ -7,41 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "lld/ReaderWriter/WriterELF.h"
-#include "ReferenceKinds.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/InputFiles.h"
-#include "lld/Core/range.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"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
+#include "DefaultELFLayout.h"
#include "ExecutableAtoms.h"
-#include <map>
-#include <unordered_map>
-#include <tuple>
-#include <vector>
-
using namespace llvm;
using namespace llvm::object;
namespace lld {
@@ -49,1855 +17,6 @@
template<class ELFT>
class ELFExecutableWriter;
-/// \brief The ELFWriter class is a base class for the linker to write
-/// various kinds of ELF files.
-class ELFWriter : public Writer {
-public:
- ELFWriter() { }
-
-public:
- /// \brief builds the chunks that needs to be written to the output
- /// ELF file
- virtual void buildChunks(const lld::File &file) = 0;
-
- /// \brief Writes the chunks into the output file specified by path
- virtual error_code writeFile(const lld::File &File, StringRef path) = 0;
-
- /// \brief Get the virtual address of \p atom after layout.
- 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<class ELFT>
-class Chunk {
-public:
-
- /// \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() {}
- // 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;}
- // 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:
- StringRef _name;
- Kind _kind;
- uint64_t _fsize;
- uint64_t _msize;
- uint64_t _align2;
- uint32_t _order;
- uint64_t _ordinal;
- uint64_t _start;
- uint64_t _fileoffset;
-};
-
-/// \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() { }
-
- 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;
-};
-
-struct AtomLayout {
- AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr)
- : _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {}
-
- AtomLayout()
- : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {}
-
- const Atom *_atom;
- uint64_t _fileOffset;
- uint64_t _virtualAddr;
-};
-
-/// \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<class ELFT>
-class Section : public Chunk<ELFT> {
-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<ELFT>(sectionName, Chunk<ELFT>::K_ELFSection)
- , _contentType(contentType)
- , _contentPermissions(contentPermissions)
- , _sectionKind(kind)
- , _entSize(0)
- , _shInfo(0)
- , _link(0) {
- this->setOrder(order);
- }
-
- /// return the section kind
- SectionKind sectionKind() const {
- return _sectionKind;
- }
-
- /// 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 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 = cast<DefinedAtom>(atom);
-
- 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:
- case DefinedAtom::typeConstant:
- _atoms.push_back(AtomLayout(atom, fOffset, 0));
- this->_fsize = fOffset + definedAtom->size();
- this->_msize = mOffset + definedAtom->size();
- break;
- case DefinedAtom::typeZeroFill:
- _atoms.push_back(AtomLayout(atom, 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._virtualAddr = addr + ai._fileOffset;
- }
- 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._fileOffset = offset + ai._fileOffset;
- }
- }
-
- /// \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._atom->name() == name) {
- addr = ai._virtualAddr;
- 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<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::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 = cast<DefinedAtom>(ai._atom);
- if (definedAtom->contentType() == DefinedAtom::typeZeroFill)
- continue;
- // 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._fileOffset;
- std::copy_n(content.data(), contentSize, atomContent);
- for (const auto ref : *definedAtom) {
- uint32_t offset = ref->offsetInAtom();
- uint64_t targetAddress = 0;
- assert(ref->target() != nullptr && "Found the target to be NULL");
- targetAddress = writer->addressOfAtom(ref->target());
- uint64_t fixupAddress = writer->addressOfAtom(ai._atom) + offset;
- // apply the relocation
- writer->kindHandler()->applyFixup(ref->kind(),
- ref->addend(),
- &atomContent[offset],
- fixupAddress,
- targetAddress);
- }
- }
- }
-
- /// Atom Iterators
- typedef typename std::vector<AtomLayout>::iterator atom_iter;
-
- range<atom_iter> atoms() { return _atoms; }
-
-protected:
- int32_t _contentType;
- int32_t _contentPermissions;
- SectionKind _sectionKind;
- std::vector<AtomLayout> _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<class ELFT>
-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; }
-
- /// Sets the ordinal
- void setOrdinal(uint64_t ordinal) {
- _ordinal = ordinal;
- }
-
- /// 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<ELFT> *c) {
- if (c->align2() > _align2)
- _align2 = c->align2();
- if (const auto section = dyn_cast<Section<ELFT>>(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<ELFT> *>::iterator ChunkIter;
-
- range<ChunkIter> sections() { return _sections; }
-
- // 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:
- 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<ELFT> *> _sections;
-};
-
-/// \brief A segment can be divided into segment slices
-/// depending on how the segments can be split
-template<class ELFT>
-class SegmentSlice {
-public:
- typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
-
- SegmentSlice() { }
-
- /// Set the segment slice so that it begins at the offset specified
- /// by file offset 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;
- }
-
- // 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(range<SectionIter> sections) {
- _sections = sections;
- }
-
- // 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<ELFT> *a, SegmentSlice<ELFT> *b) {
- return a->startSection() < b->startSection();
- }
-
- range<SectionIter> sections() {
- return _sections;
- }
-
-private:
- int32_t _startSection;
- int32_t _endSection;
- range<SectionIter> _sections;
- uint64_t _addr;
- uint64_t _offset;
- uint64_t _size;
- uint64_t _align2;
- uint64_t _memSize;
-};
-
-/// \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<class ELFT>
-class Segment : public Chunk<ELFT> {
-public:
- typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
- typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
-
- Segment(const StringRef name,
- const ELFLayout::SegmentType type,
- const WriterOptionsELF &options)
- : Chunk<ELFT>(name, Chunk<ELFT>::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<ELFT> *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();
- }
-
- /// Prepend a generic chunk to the segment.
- void prepend(Chunk<ELFT> *c) {
- _sections.insert(_sections.begin(), c);
- }
-
- /// 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<ELFT> *sega, Segment<ELFT> *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<ELFT> *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 s : slices()) {
- if (s->startSection() == startSection) {
- slice = s;
- break;
- }
- }
- if (!slice) {
- slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
- SegmentSlice<ELFT>();
- _segmentSlices.push_back(slice);
- }
- slice->set(curSliceFileOffset, startSection, currSection);
- slice->setSections(make_range(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<ELFT> *slice = nullptr;
- for (auto s : slices()) {
- // TODO: add std::find
- if (s->startSection() == startSection) {
- slice = s;
- break;
- }
- }
- if (!slice) {
- slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
- SegmentSlice<ELFT>();
- _segmentSlices.push_back(slice);
- }
- slice->set(curSliceFileOffset, startSection, currSection);
- slice->setSections(make_range(startSectionIter, _sections.end()));
- slice->setSize(curSliceSize);
- slice->setAlign(sliceAlign);
- this->_fsize = curSliceFileOffset - startOffset + curSliceSize;
- std::stable_sort(slices_begin(), slices_end(),
- SegmentSlice<ELFT>::compare_slices);
- }
-
- /// \brief Assign virtual addresses to the slices
- void assignVirtualAddress(uint64_t &addr) {
- for (auto slice : slices()) {
- // Align to a page
- addr = llvm::RoundUpToAlignment(addr, _options.pageSize());
- // Align to the slice alignment
- addr = llvm::RoundUpToAlignment(addr, slice->align2());
-
- bool virtualAddressSet = false;
- for (auto section : slice->sections()) {
- // Align the section address
- addr = llvm::RoundUpToAlignment(addr, section->align2());
- if (!virtualAddressSet) {
- slice->setVAddr(addr);
- virtualAddressSet = true;
- }
- section->setVAddr(addr);
- if (auto s = dyn_cast<Section<ELFT>>(section))
- s->assignVirtualAddress(addr);
- else
- addr += section->memSize();
- section->setMemSize(addr - section->virtualAddr());
- }
- slice->setMemSize(addr - slice->virtualAddr());
- }
- }
-
- range<SliceIter> slices() { return _segmentSlices; }
-
- // These two accessors are still needed for a call to std::stable_sort.
- // Consider adding wrappers for two iterator algorithms.
- SliceIter slices_begin() {
- return _segmentSlices.begin();
- }
-
- SliceIter slices_end() {
- return _segmentSlices.end();
- }
-
- // Write the Segment
- void write(ELFWriter *writer, OwningPtr<FileOutputBuffer> &buffer) {
- for (auto slice : slices())
- for (auto section : slice->sections())
- section->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<ELFT> *c) {
- return c->kind() == Chunk<ELFT>::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:
- /// \brief Section or some other chunk type.
- std::vector<Chunk<ELFT> *> _sections;
- std::vector<SegmentSlice<ELFT> *> _segmentSlices;
- ELFLayout::SegmentType _segmentType;
- int64_t _flags;
- int64_t _atomflags;
- const WriterOptionsELF _options;
- llvm::BumpPtrAllocator _segmentAllocate;
-};
-
-/// \brief The class represents the ELF String Table
-template<class ELFT>
-class ELFStringTable : public Section<ELFT> {
-public:
- ELFStringTable(const char *str, int32_t order)
- : Section<ELFT>(
- str,
- llvm::ELF::SHT_STRTAB,
- DefinedAtom::perm___,
- order,
- Section<ELFT>::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(const Chunk<ELFT> *c) {
- return c->kind() == Section<ELFT>::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> _strings;
-};
-
-/// \brief The ELFSymbolTable class represents the symbol table in a ELF file
-template<class ELFT>
-class ELFSymbolTable : public Section<ELFT> {
-public:
- typedef object::Elf_Sym_Impl<ELFT> Elf_Sym;
-
- ELFSymbolTable(const char *str, int32_t order)
- : Section<ELFT>(
- str,
- llvm::ELF::SHT_SYMTAB,
- 0,
- order,
- Section<ELFT>::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(const Chunk<ELFT> *c) {
- return c->kind() == Section<ELFT>::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 = 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:
- case DefinedAtom::typeConstant:
- symbol->st_value = addr;
- type = ELF::STT_OBJECT;
- break;
- case DefinedAtom::typeZeroFill:
- type = ELF::STT_OBJECT;
- 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 = 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 = addr;
- } 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<ELFT> *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<ELFT> *_stringSection;
- std::vector<Elf_Sym*> _symbolTable;
- llvm::BumpPtrAllocator _symbolAllocate;
- int64_t _link;
-};
-
-/// \brief An ELFHeader represents the Elf[32/64]_Ehdr structure at the
-/// start of an ELF executable file.
-template<class ELFT>
-class ELFHeader : public Chunk<ELFT> {
-public:
- typedef Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
-
- ELFHeader()
- : Chunk<ELFT>("elfhdr", Chunk<ELFT>::K_ELFHeader) {
- this->_align2 = ELFT::Is64Bits ? 8 : 4;
- this->_fsize = sizeof(Elf_Ehdr);
- this->_msize = sizeof(Elf_Ehdr);
- 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<ELFT> *c) {
- return c->Kind() == Chunk<ELFT>::K_ELFHeader;
- }
-
- void write(ELFWriter *writer,
- OwningPtr<FileOutputBuffer> &buffer) {
- uint8_t *chunkBuffer = buffer->getBufferStart();
- uint8_t *atomContent = chunkBuffer + this->fileOffset();
- memcpy(atomContent, &_eh, fileSize());
- }
-
- void finalize() { }
-
-private:
- Elf_Ehdr _eh;
-};
-
-/// \brief An ELFProgramHeader represents the Elf[32/64]_Phdr structure at the
-/// start of an ELF executable file.
-template<class ELFT>
-class ELFProgramHeader : public Chunk<ELFT> {
-public:
- typedef Elf_Phdr_Impl<ELFT> Elf_Phdr;
- typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
-
- /// \brief Find a program header entry, given the type of entry that
- /// we are looking for
- class FindPhdr {
- public:
- FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
- : _type(type)
- , _flags(flags)
- , _flagsClear(flagsClear)
- {}
-
- bool operator()(const Elf_Phdr *j) const {
- return ((j->p_type == _type) &&
- ((j->p_flags & _flags) == _flags) &&
- (!(j->p_flags & _flagsClear)));
- }
- private:
- uint64_t _type;
- uint64_t _flags;
- uint64_t _flagsClear;
- };
-
- ELFProgramHeader()
- : Chunk<ELFT>("elfphdr", Chunk<ELFT>::K_ELFProgramHeader) {
- this->_align2 = ELFT::Is64Bits ? 8 : 4;
- resetProgramHeaders();
- }
-
- bool addSegment(Segment<ELFT> *segment) {
- Elf_Phdr *phdr = nullptr;
- bool ret = false;
-
- for (auto slice : segment->slices()) {
- 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 = slice->fileOffset();
- phdr->p_vaddr = slice->virtualAddr();
- phdr->p_paddr = slice->virtualAddr();
- phdr->p_filesz = slice->fileSize();
- phdr->p_memsz = slice->memSize();
- phdr->p_flags = segment->flags();
- phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
- segment->pageSize() : slice->align2();
- }
-
- this->_fsize = fileSize();
- this->_msize = this->_fsize;
-
- return ret;
- }
-
- void resetProgramHeaders() {
- _phi = _ph.begin();
- }
-
- uint64_t fileSize() {
- return sizeof(Elf_Phdr) * _ph.size();
- }
-
- static inline bool classof(const Chunk<ELFT> *c) {
- return c->Kind() == Chunk<ELFT>::K_ELFProgramHeader;
- }
-
- void write(ELFWriter *writer,
- OwningPtr<FileOutputBuffer> &buffer) {
- 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);
- }
- }
-
- /// \brief find a program header entry in the list of program headers
- PhIterT findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
- return std::find_if(_ph.begin(), _ph.end(),
- FindPhdr(type, flags, flagClear));
- }
-
- PhIterT begin() {
- return _ph.begin();
- }
-
- PhIterT end() {
- return _ph.end();
- }
-
- void finalize() { }
-
- int64_t entsize() {
- return sizeof(Elf_Phdr);
- }
-
- int64_t numHeaders() {
- return _ph.size();
- }
-
-private:
- std::vector<Elf_Phdr *> _ph;
- PhIterT _phi;
- llvm::BumpPtrAllocator _allocator;
-};
-
-/// \brief An ELFSectionHeader represents the Elf[32/64]_Shdr structure
-/// at the end of the file
-template<class ELFT>
-class ELFSectionHeader : public Chunk<ELFT> {
-public:
- typedef Elf_Shdr_Impl<ELFT> Elf_Shdr;
-
- ELFSectionHeader(int32_t order)
- : Chunk<ELFT>("shdr", Chunk<ELFT>::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);
- }
-
- uint16_t fileSize() {
- return sizeof(Elf_Shdr) * _sectionInfo.size();
- }
-
- void appendSection(MergedSections<ELFT> *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);
- }
-
- void updateSection(Section<ELFT> *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();
- }
-
- static inline bool classof(const Chunk<ELFT> *c) {
- return c->getChunkKind() == Chunk<ELFT>::K_ELFSectionHeader;
- }
-
- void setStringSection(ELFStringTable<ELFT> *s) {
- _stringSection = s;
- }
-
- 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);
- }
-
- void finalize() { }
-
- int64_t entsize() {
- return sizeof(Elf_Shdr);
- }
-
- int64_t numHeaders() {
- return _sectionInfo.size();
- }
-
-private:
- ELFStringTable<ELFT> *_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<class ELFT>
-class DefaultELFLayout : public ELFLayout {
-public:
-
- // 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_INIT_ARRAY,
- ORDER_FINI_ARRAY,
- 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
- };
-
-public:
-
- // 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<ELFT> *>::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<ELFT> *> MergedSectionMapT;
- typedef typename std::vector<MergedSections<ELFT> *>::iterator
- MergedSectionIter;
-
- // 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);
- }
- };
-
- // 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);
- }
- };
-
- typedef std::unordered_map<Key, Section<ELFT>*, HashKey> SectionMapT;
- typedef std::unordered_map<SegmentKey,
- Segment<ELFT>*,
- SegmentHashKey> SegmentMapT;
-
- /// \brief All absolute atoms are created in the ELF Layout by using
- /// an AbsoluteAtomPair. Contains a pair of AbsoluteAtom and the
- /// value which is the address of the absolute atom
- class AbsoluteAtomPair {
- public:
- AbsoluteAtomPair(const AbsoluteAtom *a, int64_t value)
- : _absoluteAtom(a)
- , _value(value) { }
-
- const AbsoluteAtom *absoluteAtom() { return _absoluteAtom; }
- int64_t value() const { return _value; }
- void setValue(int64_t val) { _value = val; }
-
- private:
- const AbsoluteAtom *_absoluteAtom;
- int64_t _value;
- };
-
- /// \brief find a absolute atom pair given a absolute atom name
- struct FindByName {
- const std::string _name;
- FindByName(StringRef name) : _name(name) {}
- bool operator()(AbsoluteAtomPair& j) {
- return j.absoluteAtom()->name() == _name;
- }
- };
-
- typedef typename std::vector<AbsoluteAtomPair>::iterator AbsoluteAtomIterT;
-
- DefaultELFLayout(const WriterOptionsELF &options):_options(options) { }
-
- /// \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);
-
- case DefinedAtom::typeConstant:
- return ORDER_RODATA;
-
- case DefinedAtom::typeData:
- return llvm::StringSwitch<Reference::Kind>(name)
- .StartsWith(".init_array", ORDER_INIT_ARRAY)
- .Default(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;
- }
- }
-
- /// \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;
- }
-
- /// \brief Gets the segment for a output section
- virtual ELFLayout::SegmentType getSegmentType(Section<ELFT> *section) const {
- switch(section->order()) {
- case ORDER_INTERP:
- return llvm::ELF::PT_INTERP;
-
- 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;
-
- case ORDER_NOTE:
- return llvm::ELF::PT_NOTE;
-
- case ORDER_DYNAMIC:
- return llvm::ELF::PT_DYNAMIC;
-
- case ORDER_CTORS:
- case ORDER_DTORS:
- case ORDER_GOT:
- return llvm::ELF::PT_GNU_RELRO;
-
- case ORDER_GOT_PLT:
- case ORDER_DATA:
- case ORDER_BSS:
- case ORDER_INIT_ARRAY:
- case ORDER_FINI_ARRAY:
- 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<ELFT> *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_INIT_ARRAY:
- case ORDER_FINI_ARRAY:
- case ORDER_BSS:
- return true;
-
- default:
- return false;
- }
- }
-
- // Adds an atom to the section
- virtual error_code addAtom(const Atom *atom) {
- if (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<ELFT> *>currentSection(key, nullptr);
- std::pair<typename SectionMapT::iterator, bool>
- sectionInsert(_sectionMap.insert(currentSection));
- Section<ELFT> *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<ELFT>>()) Section<ELFT>(
- sectionName, contentType, permissions, section_order);
- sectionInsert.first->second = section;
- section->setOrder(section_order);
- _sections.push_back(section);
- }
- section->appendAtom(atom);
- }
- // Absolute atoms are not part of any section, they are global for the whole
- // link
- else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
- _absoluteAtoms.push_back(AbsoluteAtomPair(absoluteAtom,
- absoluteAtom->value()));
- }
- else
- llvm_unreachable("Only absolute / defined atoms can be added here");
- return error_code::success();
- }
-
- /// \brief Find an output Section given a section name.
- MergedSections<ELFT> *findOutputSection(StringRef name) {
- auto iter = _mergedSectionMap.find(name);
- if (iter == _mergedSectionMap.end())
- return nullptr;
- return iter->second;
- }
-
- /// \brief find a absolute atom given a name
- AbsoluteAtomIterT findAbsoluteAtom(const StringRef name) {
- return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
- FindByName(name));
- }
-
- range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
-
- // Merge sections with the same name into a MergedSections
- void mergeSimiliarSections() {
- MergedSections<ELFT> *mergedSection;
-
- for (auto &si : _sections) {
- const std::pair<StringRef, MergedSections<ELFT> *>
- 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<ELFT>>())
- MergedSections<ELFT>(si->name());
- _mergedSections.push_back(mergedSection);
- mergedSectionInsert.first->second = mergedSection;
- }
- mergedSection->appendSection(si);
- }
- }
-
- void assignSectionsToSegments() {
- // sort the sections by their order as defined by the layout
- std::stable_sort(_sections.begin(), _sections.end(),
- [](Chunk<ELFT> *A, Chunk<ELFT> *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->sections()) {
- ai->setOrdinal(ordinal);
- }
- ++ordinal;
- }
- for (auto msi : _mergedSections) {
- for (auto ai : msi->sections()) {
- if (auto section = dyn_cast<Section<ELFT>>(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<ELFT> *>
- currentSegment(key, nullptr);
- std::pair<typename SegmentMapT::iterator, bool>
- segmentInsert(_segmentMap.insert(currentSegment));
- Segment<ELFT> *segment;
- if (!segmentInsert.second) {
- segment = segmentInsert.first->second;
- } else {
- segment = new (_allocator.Allocate<Segment<ELFT>>()) Segment<ELFT>(
- segmentName, getSegmentType(section), _options);
- segmentInsert.first->second = segment;
- _segments.push_back(segment);
- }
- segment->append(section);
- }
- }
- }
- }
-
- void addSection(Chunk<ELFT> *c) {
- _sections.push_back(c);
- }
-
- void assignFileOffsets() {
- std::sort(_segments.begin(), _segments.end(),
- Segment<ELFT>::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();
- }
- }
-
- void setELFHeader(ELFHeader<ELFT> *e) {
- _elfHeader = e;
- }
-
- void setProgramHeader(ELFProgramHeader<ELFT> *p) {
- _programHeader = p;
- }
-
- void assignVirtualAddress() {
- if (_segments.empty())
- return;
-
- uint64_t virtualAddress = _options.baseAddress();
-
- // HACK: This is a super dirty hack. The elf header and program header are
- // not part of a section, but we need them to be loaded at the base address
- // so that AT_PHDR is set correctly by the loader and so they are accessible
- // at runtime. To do this we simply prepend them to the first Segment and
- // let the layout logic take care of it.
- _segments[0]->prepend(_programHeader);
- _segments[0]->prepend(_elfHeader);
-
- bool newSegmentHeaderAdded = true;
- while (true) {
- for (auto si : _segments) {
- newSegmentHeaderAdded = _programHeader->addSegment(si);
- }
- if (!newSegmentHeaderAdded)
- break;
- uint64_t fileoffset = 0;
- 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)->setMemSize(address - virtualAddress);
- virtualAddress = llvm::RoundUpToAlignment(address, _options.pageSize());
- }
- _programHeader->resetProgramHeaders();
- }
- Section<ELFT> *section;
- // Fix the offsets of all the atoms within a section
- for (auto &si : _sections) {
- section = dyn_cast<Section<ELFT>>(si);
- if (section && DefaultELFLayout<ELFT>::hasOutputSegment(section))
- section->assignOffsets(section->fileOffset());
- }
- // Set the size of the merged Sections
- for (auto msi : _mergedSections) {
- uint64_t sectionfileoffset = 0;
- uint64_t startFileOffset = 0;
- uint64_t sectionsize = 0;
- bool isFirstSection = true;
- for (auto si : msi->sections()) {
- 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 : _mergedSections) {
- uint64_t sectionstartaddr = 0;
- uint64_t startaddr = 0;
- uint64_t sectionsize = 0;
- bool isFirstSection = true;
- for (auto si : msi->sections()) {
- if (isFirstSection) {
- startaddr = si->virtualAddr();
- isFirstSection = false;
- }
- sectionstartaddr = si->virtualAddr();
- sectionsize = si->memSize();
- }
- sectionsize = (sectionstartaddr - startaddr) + sectionsize;
- msi->setMemSize(sectionsize);
- msi->setAddr(startaddr);
- }
- }
-
- void assignOffsetsForMiscSections() {
- uint64_t fileoffset = 0;
- uint64_t size = 0;
- for (auto si : _segments) {
- fileoffset = si->fileOffset();
- size = si->fileSize();
- }
- fileoffset = fileoffset + size;
- Section<ELFT> *section;
- for (auto si : _sections) {
- section = dyn_cast<Section<ELFT>>(si);
- if (section && DefaultELFLayout<ELFT>::hasOutputSegment(section))
- continue;
- fileoffset = llvm::RoundUpToAlignment(fileoffset, si->align2());
- si->setFileOffset(fileoffset);
- si->setVAddr(0);
- fileoffset += si->fileSize();
- }
- }
-
- void finalize() {
- for (auto &si : _sections)
- si->finalize();
- }
-
- bool findAtomAddrByName(const StringRef name, uint64_t &addr) {
- for (auto sec : _sections)
- if (auto section = dyn_cast<Section<ELFT>>(sec))
- if (section->findAtomAddrByName(name, addr))
- return true;
- return false;
- }
-
- range<MergedSectionIter> mergedSections() { return _mergedSections; }
-
- range<ChunkIter> sections() { return _sections; }
-
- range<ChunkIter> segments() { return _segments; }
-
- ELFHeader<ELFT> *elfHeader() {
- return _elfHeader;
- }
-
- ELFProgramHeader<ELFT> *elfProgramHeader() {
- return _programHeader;
- }
-
-private:
- SectionMapT _sectionMap;
- MergedSectionMapT _mergedSectionMap;
- SegmentMapT _segmentMap;
- std::vector<Chunk<ELFT> *> _sections;
- std::vector<Segment<ELFT> *> _segments;
- std::vector<MergedSections<ELFT> *> _mergedSections;
- ELFHeader<ELFT> *_elfHeader;
- ELFProgramHeader<ELFT> *_programHeader;
- std::vector<AbsoluteAtomPair> _absoluteAtoms;
- llvm::BumpPtrAllocator _allocator;
- const WriterOptionsELF &_options;
-};
-
//===----------------------------------------------------------------------===//
// ELFExecutableWriter Class
//===----------------------------------------------------------------------===//
More information about the llvm-commits
mailing list