Newer
Older
//===- lib/ReaderWriter/ELF/HeaderChunks.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 "SegmentChunks.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"
/// \brief An Header represents the Elf[32/64]_Ehdr structure at the
/// start of an ELF executable file.
namespace lld {
namespace elf {
template<class ELFT>
class Header : public Chunk<ELFT> {
public:
typedef llvm::object::Elf_Ehdr_Impl<ELFT> Elf_Ehdr;
Header(const ELFTargetInfo &);
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_Header;
void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
void finalize() { }
private:
Elf_Ehdr _eh;
};
Header<ELFT>::Header(const ELFTargetInfo &ti)
: Chunk<ELFT>("elfhdr", Chunk<ELFT>::K_Header, ti) {
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 Header<ELFT>::write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
uint8_t *chunkBuffer = buffer.getBufferStart();
uint8_t *atomContent = chunkBuffer + this->fileOffset();
memcpy(atomContent, &_eh, fileSize());
}
/// \brief An ProgramHeader represents the Elf[32/64]_Phdr structure at the
/// start of an ELF executable file.
template<class ELFT>
class ProgramHeader : 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;
};
ProgramHeader(const ELFTargetInfo &ti)
: Chunk<ELFT>("elfphdr", Chunk<ELFT>::K_ProgramHeader, ti) {
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_ProgramHeader;
void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer);
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/// \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::pair<Elf_Phdr *, bool> allocateProgramHeader() {
Elf_Phdr *phdr;
bool ret = false;
if (_phi == _ph.end()) {
phdr = new (_allocator) Elf_Phdr;
_ph.push_back(phdr);
_phi = _ph.end();
ret = true;
} else {
phdr = (*_phi);
++_phi;
}
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
return std::make_pair(phdr, ret);
}
std::vector<Elf_Phdr *> _ph;
PhIterT _phi;
llvm::BumpPtrAllocator _allocator;
};
template <class ELFT>
bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
bool allocatedNew = false;
for (auto slice : segment->slices()) {
// If we have a TLS segment, emit a LOAD first.
if (segment->segmentType() == llvm::ELF::PT_TLS) {
auto phdr = allocateProgramHeader();
if (phdr.second)
allocatedNew = true;
phdr.first->p_type = llvm::ELF::PT_LOAD;
phdr.first->p_offset = slice->fileOffset();
phdr.first->p_vaddr = slice->virtualAddr();
phdr.first->p_paddr = slice->virtualAddr();
phdr.first->p_filesz = slice->fileSize();
phdr.first->p_memsz = slice->memSize();
phdr.first->p_flags = segment->flags();
phdr.first->p_align = slice->align2();
}
auto phdr = allocateProgramHeader();
if (phdr.second)
allocatedNew = true;
phdr.first->p_type = segment->segmentType();
phdr.first->p_offset = slice->fileOffset();
phdr.first->p_vaddr = slice->virtualAddr();
phdr.first->p_paddr = slice->virtualAddr();
phdr.first->p_filesz = slice->fileSize();
phdr.first->p_memsz = slice->memSize();
phdr.first->p_flags = segment->flags();
phdr.first->p_align = (phdr.first->p_type == llvm::ELF::PT_LOAD) ?
segment->pageSize() : slice->align2();
}
this->_fsize = fileSize();
this->_msize = this->_fsize;
template <class ELFT>
void ProgramHeader<ELFT>::write(ELFWriter *writer,
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 SectionHeader represents the Elf[32/64]_Shdr structure
/// at the end of the file
template<class ELFT>
class SectionHeader : public Chunk<ELFT> {
public:
typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
SectionHeader(const ELFTargetInfo &, 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_SectionHeader;
void setStringSection(StringTable<ELFT> *s) {
_stringSection = s;
}
void write(ELFWriter *writer, 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:
StringTable<ELFT> *_stringSection;
std::vector<Elf_Shdr*> _sectionInfo;
llvm::BumpPtrAllocator _sectionAllocate;
};
SectionHeader<ELFT>::SectionHeader(const ELFTargetInfo &ti, int32_t order)
: Chunk<ELFT>("shdr", Chunk<ELFT>::K_SectionHeader, ti) {
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
SectionHeader<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
SectionHeader<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 SectionHeader<ELFT>::write(ELFWriter *writer,
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);
}
} // end namespace elf
} // end namespace lld