613 lines
20 KiB
C++
613 lines
20 KiB
C++
//===- lib/ReaderWriter/ELF/SectionChunks.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 "Chunk.h"
|
|
#include "TargetHandler.h"
|
|
#include "Writer.h"
|
|
#include "lld/Core/DefinedAtom.h"
|
|
#include "lld/Core/range.h"
|
|
#include "lld/ReaderWriter/AtomLayout.h"
|
|
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Object/ELF.h"
|
|
#include "llvm/Support/Allocator.h"
|
|
#include "llvm/Support/ELF.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
namespace lld {
|
|
namespace elf {
|
|
template <class> class OutputSection;
|
|
using namespace llvm::ELF;
|
|
template <class ELFT> class Segment;
|
|
template <class ELFT> class TargetLayout;
|
|
|
|
/// \brief An ELF section.
|
|
template <class ELFT> class Section : public Chunk<ELFT> {
|
|
public:
|
|
Section(const ELFLinkingContext &ctx, StringRef sectionName,
|
|
StringRef chunkName,
|
|
typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection);
|
|
|
|
/// \brief Modify the section contents before assigning virtual addresses
|
|
// or assigning file offsets
|
|
|
|
/// \brief Finalize the section contents before writing
|
|
|
|
/// \brief Does this section have an output segment.
|
|
virtual bool hasOutputSegment() const { return false; }
|
|
|
|
/// Return if the section is a loadable section that occupies memory
|
|
virtual bool isLoadableSection() const { return false; }
|
|
|
|
/// \brief Assign file offsets starting at offset.
|
|
virtual void assignFileOffsets(uint64_t offset) {}
|
|
|
|
/// \brief Assign virtual addresses starting at addr.
|
|
virtual void assignVirtualAddress(uint64_t addr) {}
|
|
|
|
uint64_t getFlags() const { return _flags; }
|
|
uint64_t getEntSize() const { return _entSize; }
|
|
uint32_t getType() const { return _type; }
|
|
uint32_t getLink() const { return _link; }
|
|
uint32_t getInfo() const { return _info; }
|
|
|
|
typename TargetLayout<ELFT>::SegmentType getSegmentType() const {
|
|
return _segmentType;
|
|
}
|
|
|
|
/// \brief Return the type of content that the section contains
|
|
int getContentType() const override;
|
|
|
|
/// \brief convert the segment type to a String for diagnostics and printing
|
|
/// purposes
|
|
virtual StringRef segmentKindToStr() const;
|
|
|
|
/// \brief Records the segmentType, that this section belongs to
|
|
void
|
|
setSegmentType(const typename TargetLayout<ELFT>::SegmentType segmentType) {
|
|
this->_segmentType = segmentType;
|
|
}
|
|
|
|
virtual const AtomLayout *findAtomLayoutByName(StringRef) const {
|
|
return nullptr;
|
|
}
|
|
|
|
void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) {
|
|
_outputSection = os;
|
|
_isFirstSectionInOutputSection = isFirst;
|
|
}
|
|
|
|
static bool classof(const Chunk<ELFT> *c) {
|
|
return c->kind() == Chunk<ELFT>::Kind::ELFSection ||
|
|
c->kind() == Chunk<ELFT>::Kind::AtomSection;
|
|
}
|
|
|
|
uint64_t alignment() const override {
|
|
return _isFirstSectionInOutputSection ? _outputSection->alignment()
|
|
: this->_alignment;
|
|
}
|
|
|
|
virtual StringRef inputSectionName() const { return _inputSectionName; }
|
|
|
|
virtual StringRef outputSectionName() const { return _outputSectionName; }
|
|
|
|
virtual void setOutputSectionName(StringRef outputSectionName) {
|
|
_outputSectionName = outputSectionName;
|
|
}
|
|
|
|
void setArchiveNameOrPath(StringRef name) { _archivePath = name; }
|
|
|
|
void setMemberNameOrPath(StringRef name) { _memberPath = name; }
|
|
|
|
StringRef archivePath() { return _archivePath; }
|
|
|
|
StringRef memberPath() { return _memberPath; }
|
|
|
|
protected:
|
|
/// \brief OutputSection this Section is a member of, or nullptr.
|
|
OutputSection<ELFT> *_outputSection = nullptr;
|
|
/// \brief ELF SHF_* flags.
|
|
uint64_t _flags = 0;
|
|
/// \brief The size of each entity.
|
|
uint64_t _entSize = 0;
|
|
/// \brief ELF SHT_* type.
|
|
uint32_t _type = 0;
|
|
/// \brief sh_link field.
|
|
uint32_t _link = 0;
|
|
/// \brief the sh_info field.
|
|
uint32_t _info = 0;
|
|
/// \brief Is this the first section in the output section.
|
|
bool _isFirstSectionInOutputSection = false;
|
|
/// \brief the output ELF segment type of this section.
|
|
typename TargetLayout<ELFT>::SegmentType _segmentType = SHT_NULL;
|
|
/// \brief Input section name.
|
|
StringRef _inputSectionName;
|
|
/// \brief Output section name.
|
|
StringRef _outputSectionName;
|
|
StringRef _archivePath;
|
|
StringRef _memberPath;
|
|
};
|
|
|
|
/// \brief A section containing atoms.
|
|
template <class ELFT> class AtomSection : public Section<ELFT> {
|
|
public:
|
|
AtomSection(const ELFLinkingContext &ctx, StringRef sectionName,
|
|
int32_t contentType, int32_t permissions, int32_t order);
|
|
|
|
/// Align the offset to the required modulus defined by the atom alignment
|
|
uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign);
|
|
|
|
/// Return if the section is a loadable section that occupies memory
|
|
bool isLoadableSection() const override { return _isLoadedInMemory; }
|
|
|
|
// \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
|
|
virtual const AtomLayout *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
|
|
virtual void assignVirtualAddress(uint64_t addr) override;
|
|
|
|
/// \brief Set the file offset of each Atom in the section. This routine
|
|
/// gets called after the linker fixes up the section offset
|
|
void assignFileOffsets(uint64_t offset) override;
|
|
|
|
/// \brief Find the Atom address given a name, this is needed to properly
|
|
/// apply relocation. The section class calls this to find the atom address
|
|
/// to fix the relocation
|
|
const AtomLayout *findAtomLayoutByName(StringRef name) const override;
|
|
|
|
/// \brief Return the raw flags, we need this to sort segments
|
|
int64_t atomflags() const { return _contentPermissions; }
|
|
|
|
/// Atom Iterators
|
|
typedef typename std::vector<AtomLayout *>::iterator atom_iter;
|
|
|
|
range<atom_iter> atoms() { return _atoms; }
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
static bool classof(const Chunk<ELFT> *c) {
|
|
return c->kind() == Chunk<ELFT>::Kind::AtomSection;
|
|
}
|
|
|
|
protected:
|
|
llvm::BumpPtrAllocator _alloc;
|
|
int32_t _contentType;
|
|
int32_t _contentPermissions;
|
|
bool _isLoadedInMemory = true;
|
|
std::vector<AtomLayout *> _atoms;
|
|
mutable std::mutex _outputMutex;
|
|
|
|
void printError(const std::string &errorStr, const AtomLayout &atom,
|
|
const Reference &ref) const;
|
|
};
|
|
|
|
/// \brief A OutputSection represents a set of sections grouped by the same
|
|
/// name. The output file that gets written by the linker has sections grouped
|
|
/// by similar names
|
|
template <class ELFT> class OutputSection {
|
|
public:
|
|
// Iterators
|
|
typedef typename std::vector<Section<ELFT> *>::iterator SectionIter;
|
|
|
|
OutputSection(StringRef name) : _name(name) {}
|
|
|
|
// Appends a section into the list of sections that are part of this Output
|
|
// Section
|
|
void appendSection(Section<ELFT> *c);
|
|
|
|
// Set the OutputSection 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 output Section.
|
|
void setSize(uint64_t fsiz) { _size = fsiz; }
|
|
|
|
// The offset of the first section contained in the output 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; }
|
|
|
|
// Is the section loadable?
|
|
bool isLoadableSection() const { return _isLoadableSection; }
|
|
|
|
// Set section Loadable
|
|
void setLoadableSection(bool isLoadable) {
|
|
_isLoadableSection = isLoadable;
|
|
}
|
|
|
|
void setLink(uint64_t link) { _link = link; }
|
|
void setInfo(uint64_t info) { _shInfo = info; }
|
|
void setFlag(uint64_t flags) { _flags = flags; }
|
|
void setType(int64_t type) { _type = type; }
|
|
range<SectionIter> sections() { return _sections; }
|
|
|
|
// The below functions returns the properties of the OutputSection.
|
|
bool hasSegment() const { return _hasSegment; }
|
|
StringRef name() const { return _name; }
|
|
int64_t shinfo() const { return _shInfo; }
|
|
uint64_t alignment() const { return _alignment; }
|
|
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; }
|
|
uint64_t flags() const { return _flags; }
|
|
uint64_t memSize() { return _memSize; }
|
|
|
|
private:
|
|
StringRef _name;
|
|
bool _hasSegment = false;
|
|
uint64_t _ordinal = 0;
|
|
uint64_t _flags = 0;
|
|
uint64_t _size = 0;
|
|
uint64_t _memSize = 0;
|
|
uint64_t _fileOffset = 0;
|
|
uint64_t _virtualAddr = 0;
|
|
int64_t _shInfo = 0;
|
|
int64_t _entSize = 0;
|
|
int64_t _link = 0;
|
|
uint64_t _alignment = 1;
|
|
int64_t _kind = 0;
|
|
int64_t _type = 0;
|
|
bool _isLoadableSection = false;
|
|
std::vector<Section<ELFT> *> _sections;
|
|
};
|
|
|
|
/// \brief The class represents the ELF String Table
|
|
template <class ELFT> class StringTable : public Section<ELFT> {
|
|
public:
|
|
StringTable(const ELFLinkingContext &, const char *str, int32_t order,
|
|
bool dynamic = false);
|
|
|
|
uint64_t addString(StringRef symname);
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); }
|
|
|
|
private:
|
|
std::vector<StringRef> _strings;
|
|
|
|
struct StringRefMappingInfo {
|
|
static StringRef getEmptyKey() { return StringRef(); }
|
|
static StringRef getTombstoneKey() { return StringRef(" ", 1); }
|
|
static unsigned getHashValue(StringRef const val) {
|
|
return llvm::HashString(val);
|
|
}
|
|
static bool isEqual(StringRef const lhs, StringRef const rhs) {
|
|
return lhs.equals(rhs);
|
|
}
|
|
};
|
|
typedef typename llvm::DenseMap<StringRef, uint64_t, StringRefMappingInfo>
|
|
StringMapT;
|
|
typedef typename StringMapT::iterator StringMapTIter;
|
|
StringMapT _stringMap;
|
|
};
|
|
|
|
/// \brief The SymbolTable class represents the symbol table in a ELF file
|
|
template <class ELFT> class SymbolTable : public Section<ELFT> {
|
|
typedef
|
|
typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr Elf_Addr;
|
|
|
|
public:
|
|
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
|
|
|
|
SymbolTable(const ELFLinkingContext &ctx, const char *str, int32_t order);
|
|
|
|
/// \brief set the number of entries that would exist in the symbol
|
|
/// table for the current link
|
|
void setNumEntries(int64_t numEntries) const {
|
|
if (_stringSection)
|
|
_stringSection->setNumEntries(numEntries);
|
|
}
|
|
|
|
/// \brief return number of entries
|
|
std::size_t size() const { return _symbolTable.size(); }
|
|
|
|
void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0,
|
|
const AtomLayout *layout = nullptr);
|
|
|
|
/// \brief Get the symbol table index for an Atom. If it's not in the symbol
|
|
/// table, return STN_UNDEF.
|
|
uint32_t getSymbolTableIndex(const Atom *a) const {
|
|
for (size_t i = 0, e = _symbolTable.size(); i < e; ++i)
|
|
if (_symbolTable[i]._atom == a)
|
|
return i;
|
|
return STN_UNDEF;
|
|
}
|
|
|
|
void finalize() override { finalize(true); }
|
|
|
|
virtual void sortSymbols() {
|
|
std::stable_sort(_symbolTable.begin(), _symbolTable.end(),
|
|
[](const SymbolEntry &A, const SymbolEntry &B) {
|
|
return A._symbol.getBinding() < B._symbol.getBinding();
|
|
});
|
|
}
|
|
|
|
virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa,
|
|
int64_t addr);
|
|
|
|
virtual void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
|
|
int64_t addr);
|
|
|
|
virtual void addUndefinedAtom(Elf_Sym &sym, const UndefinedAtom *ua);
|
|
|
|
virtual void addSharedLibAtom(Elf_Sym &sym, const SharedLibraryAtom *sla);
|
|
|
|
virtual void finalize(bool sort);
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
void setStringSection(StringTable<ELFT> *s) { _stringSection = s; }
|
|
|
|
StringTable<ELFT> *getStringTable() const { return _stringSection; }
|
|
|
|
protected:
|
|
struct SymbolEntry {
|
|
SymbolEntry(const Atom *a, const Elf_Sym &sym, const AtomLayout *layout)
|
|
: _atom(a), _atomLayout(layout), _symbol(sym) {}
|
|
|
|
const Atom *_atom;
|
|
const AtomLayout *_atomLayout;
|
|
Elf_Sym _symbol;
|
|
};
|
|
|
|
llvm::BumpPtrAllocator _symbolAllocate;
|
|
StringTable<ELFT> *_stringSection;
|
|
std::vector<SymbolEntry> _symbolTable;
|
|
};
|
|
|
|
template <class ELFT> class HashSection;
|
|
|
|
template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> {
|
|
public:
|
|
DynamicSymbolTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout,
|
|
const char *str, int32_t order);
|
|
|
|
// Set the dynamic hash table for symbols to be added into
|
|
void setHashTable(HashSection<ELFT> *hashTable) { _hashTable = hashTable; }
|
|
|
|
// Add all the dynamic symbos to the hash table
|
|
void addSymbolsToHashTable();
|
|
|
|
void finalize() override;
|
|
|
|
protected:
|
|
HashSection<ELFT> *_hashTable = nullptr;
|
|
TargetLayout<ELFT> &_layout;
|
|
};
|
|
|
|
template <class ELFT> class RelocationTable : public Section<ELFT> {
|
|
public:
|
|
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
|
|
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
|
|
|
|
RelocationTable(const ELFLinkingContext &ctx, StringRef str, int32_t order);
|
|
|
|
/// \returns the index of the relocation added.
|
|
uint32_t addRelocation(const DefinedAtom &da, const Reference &r);
|
|
|
|
bool getRelocationIndex(const Reference &r, uint32_t &res);
|
|
|
|
void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) {
|
|
_symbolTable = symbolTable;
|
|
}
|
|
|
|
/// \brief Check if any relocation modifies a read-only section.
|
|
bool canModifyReadonlySection() const;
|
|
|
|
void finalize() override;
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
protected:
|
|
const DynamicSymbolTable<ELFT> *_symbolTable = nullptr;
|
|
|
|
virtual void writeRela(ELFWriter *writer, Elf_Rela &r,
|
|
const DefinedAtom &atom, const Reference &ref);
|
|
virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
|
|
const Reference &ref);
|
|
uint32_t getSymbolIndex(const Atom *a);
|
|
|
|
private:
|
|
std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs;
|
|
};
|
|
|
|
template <class ELFT> class HashSection;
|
|
|
|
template <class ELFT> class DynamicTable : public Section<ELFT> {
|
|
public:
|
|
typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn;
|
|
typedef std::vector<Elf_Dyn> EntriesT;
|
|
|
|
DynamicTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout,
|
|
StringRef str, int32_t order);
|
|
|
|
range<typename EntriesT::iterator> entries() { return _entries; }
|
|
|
|
/// \returns the index of the entry.
|
|
std::size_t addEntry(int64_t tag, uint64_t val);
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
virtual void createDefaultEntries();
|
|
void doPreFlight() override;
|
|
|
|
/// \brief Dynamic table tag for .got.plt section referencing.
|
|
/// Usually but not always targets use DT_PLTGOT for that.
|
|
virtual int64_t getGotPltTag() { return DT_PLTGOT; }
|
|
|
|
void finalize() override;
|
|
|
|
void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) {
|
|
_dynamicSymbolTable = dynsym;
|
|
}
|
|
|
|
const DynamicSymbolTable<ELFT> *getSymbolTable() const {
|
|
return _dynamicSymbolTable;
|
|
}
|
|
|
|
void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; }
|
|
|
|
virtual void updateDynamicTable();
|
|
|
|
protected:
|
|
EntriesT _entries;
|
|
|
|
/// \brief Return a virtual address (maybe adjusted) for the atom layout
|
|
/// Some targets like microMIPS and ARM Thumb use the last bit
|
|
/// of a symbol's value to mark 'compressed' code. This function allows
|
|
/// to adjust a virtal address before using it in the dynamic table tag.
|
|
virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const {
|
|
return al->_virtualAddr;
|
|
}
|
|
|
|
private:
|
|
std::size_t _dt_hash;
|
|
std::size_t _dt_strtab;
|
|
std::size_t _dt_symtab;
|
|
std::size_t _dt_rela;
|
|
std::size_t _dt_relasz;
|
|
std::size_t _dt_relaent;
|
|
std::size_t _dt_strsz;
|
|
std::size_t _dt_syment;
|
|
std::size_t _dt_pltrelsz;
|
|
std::size_t _dt_pltgot;
|
|
std::size_t _dt_pltrel;
|
|
std::size_t _dt_jmprel;
|
|
std::size_t _dt_init_array;
|
|
std::size_t _dt_init_arraysz;
|
|
std::size_t _dt_fini_array;
|
|
std::size_t _dt_fini_arraysz;
|
|
std::size_t _dt_textrel;
|
|
std::size_t _dt_init;
|
|
std::size_t _dt_fini;
|
|
TargetLayout<ELFT> &_layout;
|
|
DynamicSymbolTable<ELFT> *_dynamicSymbolTable;
|
|
HashSection<ELFT> *_hashTable;
|
|
|
|
const AtomLayout *getInitAtomLayout();
|
|
|
|
const AtomLayout *getFiniAtomLayout();
|
|
};
|
|
|
|
template <class ELFT> class InterpSection : public Section<ELFT> {
|
|
public:
|
|
InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order,
|
|
StringRef interp);
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer);
|
|
|
|
private:
|
|
StringRef _interp;
|
|
};
|
|
|
|
/// The hash table in the dynamic linker is organized into
|
|
///
|
|
/// [ nbuckets ]
|
|
/// [ nchains ]
|
|
/// [ buckets[0] ]
|
|
/// .........................
|
|
/// [ buckets[nbuckets-1] ]
|
|
/// [ chains[0] ]
|
|
/// .........................
|
|
/// [ chains[nchains - 1] ]
|
|
///
|
|
/// nbuckets - total number of hash buckets
|
|
/// nchains is equal to the number of dynamic symbols.
|
|
///
|
|
/// The symbol is searched by the dynamic linker using the below approach.
|
|
/// * Calculate the hash of the symbol that needs to be searched
|
|
/// * Take the value from the buckets[hash % nbuckets] as the index of symbol
|
|
/// * Compare the symbol's name, if true return, if false, look through the
|
|
/// * array since there was a collision
|
|
template <class ELFT> class HashSection : public Section<ELFT> {
|
|
struct SymbolTableEntry {
|
|
StringRef _name;
|
|
uint32_t _index;
|
|
};
|
|
|
|
public:
|
|
HashSection(const ELFLinkingContext &ctx, StringRef name, int32_t order);
|
|
|
|
/// \brief add the dynamic symbol into the table so that the
|
|
/// hash could be calculated
|
|
void addSymbol(StringRef name, uint32_t index);
|
|
|
|
/// \brief Set the dynamic symbol table
|
|
void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable);
|
|
|
|
// The size of the section has to be determined so that fileoffsets
|
|
// may be properly assigned. Let's calculate the buckets and the chains
|
|
// and fill the chains and the buckets hash table used by the dynamic
|
|
// linker and update the filesize and memory size accordingly
|
|
void doPreFlight() override;
|
|
|
|
void finalize() override;
|
|
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
private:
|
|
typedef
|
|
typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Word Elf_Word;
|
|
|
|
std::vector<SymbolTableEntry> _entries;
|
|
std::vector<Elf_Word> _buckets;
|
|
std::vector<Elf_Word> _chains;
|
|
const DynamicSymbolTable<ELFT> *_symbolTable = nullptr;
|
|
};
|
|
|
|
template <class ELFT> class EHFrameHeader : public Section<ELFT> {
|
|
public:
|
|
EHFrameHeader(const ELFLinkingContext &ctx, StringRef name,
|
|
TargetLayout<ELFT> &layout, int32_t order);
|
|
void doPreFlight() override;
|
|
void finalize() override;
|
|
void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
|
|
llvm::FileOutputBuffer &buffer) override;
|
|
|
|
private:
|
|
int32_t _ehFrameOffset = 0;
|
|
TargetLayout<ELFT> &_layout;
|
|
};
|
|
|
|
} // end namespace elf
|
|
} // end namespace lld
|
|
|
|
#endif
|