no functionality changes(split WriterELF into multiple files)

llvm-svn: 173082
This commit is contained in:
Shankar Easwaran
2013-01-21 20:09:55 +00:00
parent bdb259d223
commit 6d9921fc53
8 changed files with 2252 additions and 1882 deletions

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

File diff suppressed because it is too large Load Diff