566 lines
20 KiB
C++
566 lines
20 KiB
C++
//===- lib/ReaderWriter/Native/WriterNative.cpp ---------------------------===//
|
|
//
|
|
// The LLVM Linker
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "NativeFileFormat.h"
|
|
#include "lld/Core/File.h"
|
|
#include "lld/Core/LinkingContext.h"
|
|
#include "lld/Core/Writer.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cstdint>
|
|
#include <set>
|
|
#include <system_error>
|
|
#include <vector>
|
|
|
|
namespace lld {
|
|
namespace native {
|
|
|
|
///
|
|
/// Class for writing native object files.
|
|
///
|
|
class Writer : public lld::Writer {
|
|
public:
|
|
std::error_code writeFile(const lld::File &file, StringRef outPath) override {
|
|
// reserve first byte for unnamed atoms
|
|
_stringPool.push_back('\0');
|
|
// visit all atoms
|
|
for ( const DefinedAtom *defAtom : file.defined() ) {
|
|
this->addIVarsForDefinedAtom(*defAtom);
|
|
// We are trying to process all atoms, but the defined() iterator does not
|
|
// return group children. So, when a group parent is found, we need to
|
|
// handle each child atom.
|
|
if (defAtom->isGroupParent()) {
|
|
for (const Reference *r : *defAtom) {
|
|
if (r->kindNamespace() != lld::Reference::KindNamespace::all)
|
|
continue;
|
|
if (r->kindValue() == lld::Reference::kindGroupChild) {
|
|
const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
|
|
assert(target && "Internal Error: kindGroupChild references need "
|
|
"to be associated with Defined Atoms only");
|
|
this->addIVarsForDefinedAtom(*target);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for ( const UndefinedAtom *undefAtom : file.undefined() ) {
|
|
this->addIVarsForUndefinedAtom(*undefAtom);
|
|
}
|
|
for ( const SharedLibraryAtom *shlibAtom : file.sharedLibrary() ) {
|
|
this->addIVarsForSharedLibraryAtom(*shlibAtom);
|
|
}
|
|
for ( const AbsoluteAtom *absAtom : file.absolute() ) {
|
|
this->addIVarsForAbsoluteAtom(*absAtom);
|
|
}
|
|
|
|
maybeConvertReferencesToV1();
|
|
|
|
// construct file header based on atom information accumulated
|
|
this->makeHeader();
|
|
|
|
std::error_code ec;
|
|
llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_None);
|
|
if (ec)
|
|
return ec;
|
|
|
|
this->write(out);
|
|
|
|
return std::error_code();
|
|
}
|
|
|
|
virtual ~Writer() {
|
|
}
|
|
|
|
private:
|
|
|
|
// write the lld::File in native format to the specified stream
|
|
void write(raw_ostream &out) {
|
|
assert(out.tell() == 0);
|
|
out.write((char*)_headerBuffer, _headerBufferSize);
|
|
|
|
writeChunk(out, _definedAtomIvars, NCS_DefinedAtomsV1);
|
|
writeChunk(out, _attributes, NCS_AttributesArrayV1);
|
|
writeChunk(out, _undefinedAtomIvars, NCS_UndefinedAtomsV1);
|
|
writeChunk(out, _sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
|
|
writeChunk(out, _absoluteAtomIvars, NCS_AbsoluteAtomsV1);
|
|
writeChunk(out, _absAttributes, NCS_AbsoluteAttributesV1);
|
|
writeChunk(out, _stringPool, NCS_Strings);
|
|
writeChunk(out, _referencesV1, NCS_ReferencesArrayV1);
|
|
writeChunk(out, _referencesV2, NCS_ReferencesArrayV2);
|
|
|
|
if (!_targetsTableIndex.empty()) {
|
|
assert(out.tell() == findChunk(NCS_TargetsTable).fileOffset);
|
|
writeTargetTable(out);
|
|
}
|
|
|
|
if (!_addendsTableIndex.empty()) {
|
|
assert(out.tell() == findChunk(NCS_AddendsTable).fileOffset);
|
|
writeAddendTable(out);
|
|
}
|
|
|
|
writeChunk(out, _contentPool, NCS_Content);
|
|
}
|
|
|
|
template<class T>
|
|
void writeChunk(raw_ostream &out, std::vector<T> &vector, uint32_t signature) {
|
|
if (vector.empty())
|
|
return;
|
|
assert(out.tell() == findChunk(signature).fileOffset);
|
|
out.write((char*)&vector[0], vector.size() * sizeof(T));
|
|
}
|
|
|
|
void addIVarsForDefinedAtom(const DefinedAtom& atom) {
|
|
_definedAtomIndex[&atom] = _definedAtomIvars.size();
|
|
NativeDefinedAtomIvarsV1 ivar;
|
|
unsigned refsCount;
|
|
ivar.nameOffset = getNameOffset(atom);
|
|
ivar.attributesOffset = getAttributeOffset(atom);
|
|
ivar.referencesStartIndex = getReferencesIndex(atom, refsCount);
|
|
ivar.referencesCount = refsCount;
|
|
ivar.contentOffset = getContentOffset(atom);
|
|
ivar.contentSize = atom.size();
|
|
_definedAtomIvars.push_back(ivar);
|
|
}
|
|
|
|
void addIVarsForUndefinedAtom(const UndefinedAtom& atom) {
|
|
_undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
|
|
NativeUndefinedAtomIvarsV1 ivar;
|
|
ivar.nameOffset = getNameOffset(atom);
|
|
ivar.flags = (atom.canBeNull() & 0x03);
|
|
ivar.fallbackNameOffset = 0;
|
|
if (atom.fallback())
|
|
ivar.fallbackNameOffset = getNameOffset(*atom.fallback());
|
|
_undefinedAtomIvars.push_back(ivar);
|
|
}
|
|
|
|
void addIVarsForSharedLibraryAtom(const SharedLibraryAtom& atom) {
|
|
_sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
|
|
NativeSharedLibraryAtomIvarsV1 ivar;
|
|
ivar.size = atom.size();
|
|
ivar.nameOffset = getNameOffset(atom);
|
|
ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
|
|
ivar.type = (uint32_t)atom.type();
|
|
ivar.flags = atom.canBeNullAtRuntime();
|
|
_sharedLibraryAtomIvars.push_back(ivar);
|
|
}
|
|
|
|
void addIVarsForAbsoluteAtom(const AbsoluteAtom& atom) {
|
|
_absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
|
|
NativeAbsoluteAtomIvarsV1 ivar;
|
|
ivar.nameOffset = getNameOffset(atom);
|
|
ivar.attributesOffset = getAttributeOffset(atom);
|
|
ivar.reserved = 0;
|
|
ivar.value = atom.value();
|
|
_absoluteAtomIvars.push_back(ivar);
|
|
}
|
|
|
|
void convertReferencesToV1() {
|
|
for (const NativeReferenceIvarsV2 &v2 : _referencesV2) {
|
|
NativeReferenceIvarsV1 v1;
|
|
v1.offsetInAtom = v2.offsetInAtom;
|
|
v1.kindNamespace = v2.kindNamespace;
|
|
v1.kindArch = v2.kindArch;
|
|
v1.kindValue = v2.kindValue;
|
|
v1.targetIndex = (v2.targetIndex == NativeReferenceIvarsV2::noTarget) ?
|
|
(uint16_t)NativeReferenceIvarsV1::noTarget : v2.targetIndex;
|
|
v1.addendIndex = this->getAddendIndex(v2.addend);
|
|
_referencesV1.push_back(v1);
|
|
}
|
|
_referencesV2.clear();
|
|
}
|
|
|
|
bool canConvertReferenceToV1(const NativeReferenceIvarsV2 &ref) {
|
|
bool validOffset = (ref.offsetInAtom == NativeReferenceIvarsV2::noTarget) ||
|
|
ref.offsetInAtom < NativeReferenceIvarsV1::noTarget;
|
|
return validOffset && ref.targetIndex < UINT16_MAX;
|
|
}
|
|
|
|
// Convert vector of NativeReferenceIvarsV2 to NativeReferenceIvarsV1 if
|
|
// possible.
|
|
void maybeConvertReferencesToV1() {
|
|
std::set<int64_t> addends;
|
|
for (const NativeReferenceIvarsV2 &ref : _referencesV2) {
|
|
if (!canConvertReferenceToV1(ref))
|
|
return;
|
|
addends.insert(ref.addend);
|
|
if (addends.size() >= UINT16_MAX)
|
|
return;
|
|
}
|
|
convertReferencesToV1();
|
|
}
|
|
|
|
// fill out native file header and chunk directory
|
|
void makeHeader() {
|
|
const bool hasDefines = !_definedAtomIvars.empty();
|
|
const bool hasUndefines = !_undefinedAtomIvars.empty();
|
|
const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
|
|
const bool hasAbsolutes = !_absoluteAtomIvars.empty();
|
|
const bool hasReferencesV1 = !_referencesV1.empty();
|
|
const bool hasReferencesV2 = !_referencesV2.empty();
|
|
const bool hasTargetsTable = !_targetsTableIndex.empty();
|
|
const bool hasAddendTable = !_addendsTableIndex.empty();
|
|
const bool hasContent = !_contentPool.empty();
|
|
|
|
int chunkCount = 1; // always have string pool chunk
|
|
if ( hasDefines ) chunkCount += 2;
|
|
if ( hasUndefines ) ++chunkCount;
|
|
if ( hasSharedLibraries ) ++chunkCount;
|
|
if ( hasAbsolutes ) chunkCount += 2;
|
|
if ( hasReferencesV1 ) ++chunkCount;
|
|
if ( hasReferencesV2 ) ++chunkCount;
|
|
if ( hasTargetsTable ) ++chunkCount;
|
|
if ( hasAddendTable ) ++chunkCount;
|
|
if ( hasContent ) ++chunkCount;
|
|
|
|
_headerBufferSize = sizeof(NativeFileHeader)
|
|
+ chunkCount*sizeof(NativeChunk);
|
|
_headerBuffer = reinterpret_cast<NativeFileHeader*>
|
|
(operator new(_headerBufferSize, std::nothrow));
|
|
NativeChunk *chunks =
|
|
reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
|
|
+ sizeof(NativeFileHeader));
|
|
memcpy(_headerBuffer->magic, NATIVE_FILE_HEADER_MAGIC,
|
|
sizeof(_headerBuffer->magic));
|
|
_headerBuffer->endian = NFH_LittleEndian;
|
|
_headerBuffer->architecture = 0;
|
|
_headerBuffer->fileSize = 0;
|
|
_headerBuffer->chunkCount = chunkCount;
|
|
|
|
// create chunk for defined atom ivar array
|
|
int nextIndex = 0;
|
|
uint32_t nextFileOffset = _headerBufferSize;
|
|
if (hasDefines) {
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _definedAtomIvars,
|
|
NCS_DefinedAtomsV1);
|
|
|
|
// create chunk for attributes
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _attributes,
|
|
NCS_AttributesArrayV1);
|
|
}
|
|
|
|
// create chunk for undefined atom array
|
|
if (hasUndefines)
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _undefinedAtomIvars,
|
|
NCS_UndefinedAtomsV1);
|
|
|
|
// create chunk for shared library atom array
|
|
if (hasSharedLibraries)
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset,
|
|
_sharedLibraryAtomIvars, NCS_SharedLibraryAtomsV1);
|
|
|
|
// create chunk for shared library atom array
|
|
if (hasAbsolutes) {
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absoluteAtomIvars,
|
|
NCS_AbsoluteAtomsV1);
|
|
|
|
// create chunk for attributes
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _absAttributes,
|
|
NCS_AbsoluteAttributesV1);
|
|
}
|
|
|
|
// create chunk for symbol strings
|
|
// pad end of string pool to 4-bytes
|
|
while ((_stringPool.size() % 4) != 0)
|
|
_stringPool.push_back('\0');
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _stringPool,
|
|
NCS_Strings);
|
|
|
|
// create chunk for referencesV2
|
|
if (hasReferencesV1)
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV1,
|
|
NCS_ReferencesArrayV1);
|
|
|
|
// create chunk for referencesV2
|
|
if (hasReferencesV2)
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _referencesV2,
|
|
NCS_ReferencesArrayV2);
|
|
|
|
// create chunk for target table
|
|
if (hasTargetsTable) {
|
|
NativeChunk& cht = chunks[nextIndex++];
|
|
cht.signature = NCS_TargetsTable;
|
|
cht.fileOffset = nextFileOffset;
|
|
cht.fileSize = _targetsTableIndex.size() * sizeof(uint32_t);
|
|
cht.elementCount = _targetsTableIndex.size();
|
|
nextFileOffset = cht.fileOffset + cht.fileSize;
|
|
}
|
|
|
|
// create chunk for addend table
|
|
if (hasAddendTable) {
|
|
NativeChunk& chad = chunks[nextIndex++];
|
|
chad.signature = NCS_AddendsTable;
|
|
chad.fileOffset = nextFileOffset;
|
|
chad.fileSize = _addendsTableIndex.size() * sizeof(Reference::Addend);
|
|
chad.elementCount = _addendsTableIndex.size();
|
|
nextFileOffset = chad.fileOffset + chad.fileSize;
|
|
}
|
|
|
|
// create chunk for content
|
|
if (hasContent)
|
|
fillChunkHeader(chunks[nextIndex++], nextFileOffset, _contentPool,
|
|
NCS_Content);
|
|
|
|
_headerBuffer->fileSize = nextFileOffset;
|
|
}
|
|
|
|
template<class T>
|
|
void fillChunkHeader(NativeChunk &chunk, uint32_t &nextFileOffset,
|
|
const std::vector<T> &data, uint32_t signature) {
|
|
chunk.signature = signature;
|
|
chunk.fileOffset = nextFileOffset;
|
|
chunk.fileSize = data.size() * sizeof(T);
|
|
chunk.elementCount = data.size();
|
|
nextFileOffset = chunk.fileOffset + chunk.fileSize;
|
|
}
|
|
|
|
// scan header to find particular chunk
|
|
NativeChunk& findChunk(uint32_t signature) {
|
|
const uint32_t chunkCount = _headerBuffer->chunkCount;
|
|
NativeChunk* chunks =
|
|
reinterpret_cast<NativeChunk*>(reinterpret_cast<char*>(_headerBuffer)
|
|
+ sizeof(NativeFileHeader));
|
|
for (uint32_t i=0; i < chunkCount; ++i) {
|
|
if ( chunks[i].signature == signature )
|
|
return chunks[i];
|
|
}
|
|
llvm_unreachable("findChunk() signature not found");
|
|
}
|
|
|
|
// append atom name to string pool and return offset
|
|
uint32_t getNameOffset(const Atom& atom) {
|
|
return this->getNameOffset(atom.name());
|
|
}
|
|
|
|
// check if name is already in pool or append and return offset
|
|
uint32_t getSharedLibraryNameOffset(StringRef name) {
|
|
assert(!name.empty());
|
|
// look to see if this library name was used by another atom
|
|
for (auto &it : _sharedLibraryNames)
|
|
if (name.equals(it.first))
|
|
return it.second;
|
|
// first use of this library name
|
|
uint32_t result = this->getNameOffset(name);
|
|
_sharedLibraryNames.push_back(std::make_pair(name, result));
|
|
return result;
|
|
}
|
|
|
|
// append atom name to string pool and return offset
|
|
uint32_t getNameOffset(StringRef name) {
|
|
if ( name.empty() )
|
|
return 0;
|
|
uint32_t result = _stringPool.size();
|
|
_stringPool.insert(_stringPool.end(), name.begin(), name.end());
|
|
_stringPool.push_back(0);
|
|
return result;
|
|
}
|
|
|
|
// append atom cotent to content pool and return offset
|
|
uint32_t getContentOffset(const DefinedAtom& atom) {
|
|
if (!atom.occupiesDiskSpace())
|
|
return 0;
|
|
uint32_t result = _contentPool.size();
|
|
ArrayRef<uint8_t> cont = atom.rawContent();
|
|
_contentPool.insert(_contentPool.end(), cont.begin(), cont.end());
|
|
return result;
|
|
}
|
|
|
|
// reuse existing attributes entry or create a new one and return offet
|
|
uint32_t getAttributeOffset(const DefinedAtom& atom) {
|
|
NativeAtomAttributesV1 attrs = computeAttributesV1(atom);
|
|
return getOrPushAttribute(_attributes, attrs);
|
|
}
|
|
|
|
uint32_t getAttributeOffset(const AbsoluteAtom& atom) {
|
|
NativeAtomAttributesV1 attrs = computeAbsoluteAttributes(atom);
|
|
return getOrPushAttribute(_absAttributes, attrs);
|
|
}
|
|
|
|
uint32_t getOrPushAttribute(std::vector<NativeAtomAttributesV1> &dest,
|
|
const NativeAtomAttributesV1 &attrs) {
|
|
for (size_t i = 0, e = dest.size(); i < e; ++i) {
|
|
if (!memcmp(&dest[i], &attrs, sizeof(attrs))) {
|
|
// found that this set of attributes already used, so re-use
|
|
return i * sizeof(attrs);
|
|
}
|
|
}
|
|
// append new attribute set to end
|
|
uint32_t result = dest.size() * sizeof(attrs);
|
|
dest.push_back(attrs);
|
|
return result;
|
|
}
|
|
|
|
uint32_t sectionNameOffset(const DefinedAtom& atom) {
|
|
// if section based on content, then no custom section name available
|
|
if (atom.sectionChoice() == DefinedAtom::sectionBasedOnContent)
|
|
return 0;
|
|
StringRef name = atom.customSectionName();
|
|
assert(!name.empty());
|
|
// look to see if this section name was used by another atom
|
|
for (auto &it : _sectionNames)
|
|
if (name.equals(it.first))
|
|
return it.second;
|
|
// first use of this section name
|
|
uint32_t result = this->getNameOffset(name);
|
|
_sectionNames.push_back(std::make_pair(name, result));
|
|
return result;
|
|
}
|
|
|
|
NativeAtomAttributesV1 computeAttributesV1(const DefinedAtom& atom) {
|
|
NativeAtomAttributesV1 attrs;
|
|
attrs.sectionNameOffset = sectionNameOffset(atom);
|
|
attrs.align2 = atom.alignment().powerOf2;
|
|
attrs.alignModulus = atom.alignment().modulus;
|
|
attrs.scope = atom.scope();
|
|
attrs.interposable = atom.interposable();
|
|
attrs.merge = atom.merge();
|
|
attrs.contentType = atom.contentType();
|
|
attrs.sectionChoiceAndPosition
|
|
= atom.sectionChoice() << 4 | atom.sectionPosition();
|
|
attrs.deadStrip = atom.deadStrip();
|
|
attrs.dynamicExport = atom.dynamicExport();
|
|
attrs.codeModel = atom.codeModel();
|
|
attrs.permissions = atom.permissions();
|
|
return attrs;
|
|
}
|
|
|
|
NativeAtomAttributesV1 computeAbsoluteAttributes(const AbsoluteAtom& atom) {
|
|
NativeAtomAttributesV1 attrs;
|
|
attrs.scope = atom.scope();
|
|
return attrs;
|
|
}
|
|
|
|
// add references for this atom in a contiguous block in NCS_ReferencesArrayV2
|
|
uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& refsCount) {
|
|
size_t startRefSize = _referencesV2.size();
|
|
uint32_t result = startRefSize;
|
|
for (const Reference *ref : atom) {
|
|
NativeReferenceIvarsV2 nref;
|
|
nref.offsetInAtom = ref->offsetInAtom();
|
|
nref.kindNamespace = (uint8_t)ref->kindNamespace();
|
|
nref.kindArch = (uint8_t)ref->kindArch();
|
|
nref.kindValue = ref->kindValue();
|
|
nref.targetIndex = this->getTargetIndex(ref->target());
|
|
nref.addend = ref->addend();
|
|
_referencesV2.push_back(nref);
|
|
}
|
|
refsCount = _referencesV2.size() - startRefSize;
|
|
return (refsCount == 0) ? 0 : result;
|
|
}
|
|
|
|
uint32_t getTargetIndex(const Atom* target) {
|
|
if ( target == nullptr )
|
|
return NativeReferenceIvarsV2::noTarget;
|
|
TargetToIndex::const_iterator pos = _targetsTableIndex.find(target);
|
|
if ( pos != _targetsTableIndex.end() ) {
|
|
return pos->second;
|
|
}
|
|
uint32_t result = _targetsTableIndex.size();
|
|
_targetsTableIndex[target] = result;
|
|
return result;
|
|
}
|
|
|
|
void writeTargetTable(raw_ostream &out) {
|
|
// Build table of target indexes
|
|
uint32_t maxTargetIndex = _targetsTableIndex.size();
|
|
assert(maxTargetIndex > 0);
|
|
std::vector<uint32_t> targetIndexes(maxTargetIndex);
|
|
for (auto &it : _targetsTableIndex) {
|
|
const Atom* atom = it.first;
|
|
uint32_t targetIndex = it.second;
|
|
assert(targetIndex < maxTargetIndex);
|
|
|
|
TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
|
|
if (pos != _definedAtomIndex.end()) {
|
|
targetIndexes[targetIndex] = pos->second;
|
|
continue;
|
|
}
|
|
uint32_t base = _definedAtomIvars.size();
|
|
|
|
pos = _undefinedAtomIndex.find(atom);
|
|
if (pos != _undefinedAtomIndex.end()) {
|
|
targetIndexes[targetIndex] = pos->second + base;
|
|
continue;
|
|
}
|
|
base += _undefinedAtomIndex.size();
|
|
|
|
pos = _sharedLibraryAtomIndex.find(atom);
|
|
if (pos != _sharedLibraryAtomIndex.end()) {
|
|
targetIndexes[targetIndex] = pos->second + base;
|
|
continue;
|
|
}
|
|
base += _sharedLibraryAtomIndex.size();
|
|
|
|
pos = _absoluteAtomIndex.find(atom);
|
|
assert(pos != _absoluteAtomIndex.end());
|
|
targetIndexes[targetIndex] = pos->second + base;
|
|
}
|
|
// write table
|
|
out.write((char*)&targetIndexes[0], maxTargetIndex * sizeof(uint32_t));
|
|
}
|
|
|
|
uint32_t getAddendIndex(Reference::Addend addend) {
|
|
if ( addend == 0 )
|
|
return 0; // addend index zero is used to mean "no addend"
|
|
AddendToIndex::const_iterator pos = _addendsTableIndex.find(addend);
|
|
if ( pos != _addendsTableIndex.end() ) {
|
|
return pos->second;
|
|
}
|
|
uint32_t result = _addendsTableIndex.size() + 1; // one-based index
|
|
_addendsTableIndex[addend] = result;
|
|
return result;
|
|
}
|
|
|
|
void writeAddendTable(raw_ostream &out) {
|
|
// Build table of addends
|
|
uint32_t maxAddendIndex = _addendsTableIndex.size();
|
|
std::vector<Reference::Addend> addends(maxAddendIndex);
|
|
for (auto &it : _addendsTableIndex) {
|
|
Reference::Addend addend = it.first;
|
|
uint32_t index = it.second;
|
|
assert(index <= maxAddendIndex);
|
|
addends[index-1] = addend;
|
|
}
|
|
// write table
|
|
out.write((char*)&addends[0], maxAddendIndex*sizeof(Reference::Addend));
|
|
}
|
|
|
|
typedef std::vector<std::pair<StringRef, uint32_t>> NameToOffsetVector;
|
|
|
|
typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
|
|
typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
|
|
|
|
NativeFileHeader* _headerBuffer;
|
|
size_t _headerBufferSize;
|
|
std::vector<char> _stringPool;
|
|
std::vector<uint8_t> _contentPool;
|
|
std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
|
|
std::vector<NativeAtomAttributesV1> _attributes;
|
|
std::vector<NativeAtomAttributesV1> _absAttributes;
|
|
std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
|
|
std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
|
|
std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
|
|
std::vector<NativeReferenceIvarsV1> _referencesV1;
|
|
std::vector<NativeReferenceIvarsV2> _referencesV2;
|
|
TargetToIndex _targetsTableIndex;
|
|
TargetToIndex _definedAtomIndex;
|
|
TargetToIndex _undefinedAtomIndex;
|
|
TargetToIndex _sharedLibraryAtomIndex;
|
|
TargetToIndex _absoluteAtomIndex;
|
|
AddendToIndex _addendsTableIndex;
|
|
NameToOffsetVector _sectionNames;
|
|
NameToOffsetVector _sharedLibraryNames;
|
|
};
|
|
} // end namespace native
|
|
|
|
std::unique_ptr<Writer> createWriterNative() {
|
|
return std::unique_ptr<Writer>(new native::Writer());
|
|
}
|
|
} // end namespace lld
|