Merge::mergeByLargestSection is half-baked since it's defined in terms of section size, there's no way to get the section size of an atom. Currently we work around the issue by traversing the layout edges to both directions and calculate the sum of all atoms reachable. I wrote that code but I knew it's hacky. It's even not guaranteed to work. If you add layout edges before the core linking, it miscalculates a size. Also it's of course slow. It's basically a linked list traversal. In this patch I added DefinedAtom::sectionSize so that we can use that for mergeByLargestSection. I'm not very happy to add a new field to DefinedAtom base class, but I think it's legitimate since mergeByLargestSection is defined for section size, and the section size is currently just missing. http://reviews.llvm.org/D7966 llvm-svn: 231290
567 lines
20 KiB
C++
567 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();
|
|
ivar.sectionSize = atom.sectionSize();
|
|
_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
|