(no commit message)

llvm-svn: 150539
This commit is contained in:
Nick Kledzik 2012-02-15 00:38:09 +00:00
parent f0687634c3
commit 49d6cc8457
19 changed files with 1080 additions and 245 deletions

View File

@ -34,7 +34,7 @@ class File;
/// Here are some example attribute sets for common atoms. If a particular
/// attribute is not listed, the default values are: definition=regular,
/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
/// internalName=false, deadStrip=normal, interposable=no
/// deadStrip=normal, interposable=no
///
/// C function: void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global
@ -71,16 +71,16 @@ class File;
/// mergeDupes=asAddressedWeak
///
/// literal c-string: "hello" <br>
/// name=L0, internalName=true, type=cstring, perm=r__, scope=linkageUnit
/// name="" type=cstring, perm=r__, scope=linkageUnit
///
/// literal double: 1.234 <br>
/// name=L0, internalName=true, type=literal8, perm=r__, scope=linkageUnit
/// name="" type=literal8, perm=r__, scope=linkageUnit
///
/// constant: { 1,2,3 } <br>
/// name=L0, internalName=true, type=constant, perm=r__, scope=linkageUnit
/// name="" type=constant, perm=r__, scope=linkageUnit
///
/// Pointer to initializer function: <br>
/// name=_init, internalName=true, type=initializer, perm=rw_l,
/// name="" type=initializer, perm=rw_l,
/// sectionChoice=customRequired
///
/// C function place in custom section: __attribute__((section("__foo")))
@ -195,15 +195,18 @@ public:
uint16_t modulus;
};
/// for use iterating over this Atom's References
class ReferenceHandler {
public:
virtual ~ReferenceHandler() {}
virtual void doReference(const Reference &) = 0;
};
/// ordinal - returns a value for the order of this Atom within its file.
/// This is used by the linker to order the layout of Atoms so that
/// the resulting image is stable and reproducible.
virtual uint64_t ordinal() const = 0;
/// internalName - If the name is just a temporary label that should
/// not show up in the final linked image.
virtual bool internalName() const = 0;
/// size - the number of bytes of space this atom's content will occupy
/// in the final linked image. For a function atom, it is the number
/// of bytes of code in the function.
@ -264,12 +267,9 @@ public:
/// this Atom's content.
virtual llvm::ArrayRef<uint8_t> rawContent() const = 0;
/// referencesBegin - used to start iterating this Atom's References
virtual Reference::iterator referencesBegin() const = 0;
/// referencesEnd - used to end iterating this Atom's References
virtual Reference::iterator referencesEnd() const = 0;
/// iterator over this Atom's References
virtual void forEachReference(ReferenceHandler&) const = 0;
protected:
/// DefinedAtom is an abstract base class.
/// Only subclasses can access constructor.

View File

@ -12,22 +12,60 @@
#include <stdint.h>
namespace lld {
class Atom;
///
/// The linker has a Graph Theory model of linking. An object file is seen
/// as a set of Atoms with References to other Atoms. Each Atom is a node
/// and each Reference is an edge.
///
/// For example if a function contains a call site to "malloc" 40 bytes into
/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
/// kind=callsite, target=malloc, addend=0.
///
/// Besides supporting traditional "relocations", References are also used
/// grouping atoms (group comdat), forcing layout (one atom must follow
/// another), marking data-in-code (jump tables or ARM constants), etc.
///
class Reference {
public:
typedef Reference *iterator;
/// The meaning of positive kind values is architecture specific.
/// Negative kind values are architecture independent.
typedef int32_t Kind;
const Atom *target;
uint64_t addend;
uint32_t offsetInAtom;
uint16_t kind;
uint16_t flags;
// A value to be added to the value of a target
typedef int64_t Addend;
/// What sort of reference this is.
virtual Kind kind() const = 0;
/// If the reference is a fixup in the Atom, then this returns the
/// byte offset into the Atom's content to do the fix up.
virtual uint64_t offsetInAtom() const = 0;
/// If the reference is an edge to another Atom, then this returns the
/// other Atom. Otherwise, it returns NULL.
virtual const class Atom * target() const = 0;
/// During linking, the linker may merge graphs which coalesces some nodes
/// (i.e. Atoms). To switch the target of a reference, this method is called.
virtual void setTarget(const class Atom *) = 0;
/// Some relocations require a symbol and a value (e.g. foo + 4).
virtual Addend addend() const = 0;
protected:
/// Atom is an abstract base class. Only subclasses can access constructor.
Reference() {}
/// The memory for Reference objects is always managed by the owning File
/// object. Therefore, no one but the owning File object should call
/// delete on an Reference. In fact, some File objects may bulk allocate
/// an array of References, so they cannot be individually deleted by anyone.
virtual ~Reference() {}
};
} // namespace lld
#endif // LLD_CORE_REFERENCES_H_

View File

@ -70,6 +70,22 @@ private:
void markLive(const Atom &atom, WhyLiveBackChain *previous);
void addAtoms(const std::vector<const DefinedAtom *>&);
// helper to update targets for use with forEachReference()
class MarkLiveReferences : public DefinedAtom::ReferenceHandler {
public:
MarkLiveReferences(Resolver& resolver, WhyLiveBackChain* chain)
: _resolver(resolver), _chain(chain) { }
virtual void doReference(const Reference& ref) {
_resolver.markLive(*ref.target(), _chain);
}
private:
Resolver& _resolver;
WhyLiveBackChain* _chain;
};
Platform &_platform;
const InputFiles &_inputFiles;
SymbolTable _symbolTable;

View File

@ -80,6 +80,7 @@ struct NativeFileHeader {
uint32_t architecture;
uint32_t fileSize;
uint32_t chunkCount;
// NativeChunk chunks[]
};
//
@ -90,8 +91,11 @@ enum NativeChunkSignatures {
NCS_AttributesArrayV1 = 2,
NCS_UndefinedAtomsV1 = 3,
NCS_Strings = 4,
NCS_Content = 5,
NCS_ReferencesArray = 6,
NCS_ReferencesArrayV1 = 5,
NCS_ReferencesArrayV2 = 6,
NCS_TargetsTable = 7,
NCS_AddendsTable = 8,
NCS_Content = 9,
};
//
@ -125,6 +129,8 @@ enum {
struct NativeDefinedAtomIvarsV1 {
uint32_t nameOffset;
uint32_t attributesOffset;
uint32_t referencesStartIndex;
uint32_t referencesCount;
uint32_t contentOffset;
uint32_t contentSize;
};
@ -137,7 +143,6 @@ struct NativeAtomAttributesV1 {
uint32_t sectionNameOffset;
uint16_t align2;
uint16_t alignModulus;
uint8_t internalName;
uint8_t scope;
uint8_t interposable;
uint8_t merge;
@ -145,10 +150,7 @@ struct NativeAtomAttributesV1 {
uint8_t sectionChoice;
uint8_t deadStrip;
uint8_t permissions;
uint8_t thumb;
uint8_t alias;
uint8_t pad1;
uint8_t pad2;
};
@ -164,6 +166,51 @@ struct NativeUndefinedAtomIvarsV1 {
//
// The NCS_ReferencesArrayV1 chunk contains an array of these structs
//
struct NativeReferenceIvarsV1 {
uint16_t offsetInAtom;
int16_t kind;
uint16_t targetIndex;
uint16_t addendIndex;
};
//
// The NCS_ReferencesArrayV2 chunk contains an array of these structs
//
struct NativeReferenceIvarsV2 {
uint64_t offsetInAtom;
int64_t addend;
int32_t kind;
uint32_t targetIndex;
};
//
// The NCS_TargetsTable chunk contains an array of uint32_t entries.
// The C++ class Reference has a target() method that returns a
// pointer to another Atom. We can't have pointers in object files,
// so instead NativeReferenceIvarsV1 contains an index to the target.
// The index is into this NCS_TargetsTable of uint32_t entries.
// The values in this table are the index of the (target) atom in this file.
// For DefinedAtoms the value is from 0 to NCS_DefinedAtomsV1.elementCount.
// For UndefinedAtoms the value is from NCS_DefinedAtomsV1.elementCount to
// NCS_DefinedAtomsV1.elementCount+NCS_UndefinedAtomsV1.elementCount.
//
//
// The NCS_AddendsTable chunk contains an array of int64_t entries.
// If we allocated space for addends directly in NativeReferenceIvarsV1
// it would double the size of that struct. But since addends are rare,
// we instead just keep a pool of addends and have NativeReferenceIvarsV1
// (if it needs an addend) just store the index (into the pool) of the
// addend it needs.
//
} // namespace lld

View File

@ -44,10 +44,6 @@ public:
virtual llvm::StringRef name() const;
virtual bool internalName() const {
return attributes().internalName;
}
virtual uint64_t size() const {
return _ivarData->contentSize;
}
@ -88,23 +84,17 @@ public:
}
virtual bool isThumb() const {
return (attributes().thumb != 0);
return false; //(attributes().thumb != 0);
}
virtual bool isAlias() const {
return (attributes().alias != 0);
}
llvm::ArrayRef<uint8_t> rawContent() const;
virtual llvm::ArrayRef<uint8_t> rawContent() const;
virtual Reference::iterator referencesBegin() const {
return 0;
}
virtual Reference::iterator referencesEnd() const {
return 0;
}
virtual void forEachReference(ReferenceHandler&) const;
private:
const NativeAtomAttributesV1& attributes() const;
@ -138,6 +128,35 @@ private:
//
// An object of this class is instantied for each NativeReferenceIvarsV1
// struct in the NCS_ReferencesArrayV1 chunk.
//
class NativeReferenceV1 : public Reference {
public:
NativeReferenceV1(const NativeFile& f,
const NativeReferenceIvarsV1* ivarData)
: _file(&f), _ivarData(ivarData) { }
virtual uint64_t offsetInAtom() const {
return _ivarData->offsetInAtom;
}
virtual Kind kind() const {
return _ivarData->kind;
}
virtual const Atom* target() const;
virtual Addend addend() const;
virtual void setTarget(const Atom* newAtom);
private:
const NativeFile* _file;
const NativeReferenceIvarsV1* _ivarData;
};
//
// lld::File object for native llvm object file
//
@ -187,6 +206,15 @@ public:
case NCS_UndefinedAtomsV1:
ec = file->processUndefinedAtomsV1(base, chunk);
break;
case NCS_ReferencesArrayV1:
ec = file->processReferencesV1(base, chunk);
break;
case NCS_TargetsTable:
ec = file->processTargetsTable(base, chunk);
break;
case NCS_AddendsTable:
ec = file->processAddendsTable(base, chunk);
break;
case NCS_Content:
ec = file->processContent(base, chunk);
break;
@ -219,6 +247,8 @@ public:
// to just delete the memory.
delete _definedAtoms.arrayStart;
delete _undefinedAtoms.arrayStart;
delete _references.arrayStart;
delete _targetsTable;
}
// visits each atom in the file
@ -245,6 +275,7 @@ public:
private:
friend class NativeDefinedAtomV1;
friend class NativeUndefinedAtomV1;
friend class NativeReferenceV1;
// instantiate array of DefinedAtoms from v1 ivar data in file
llvm::error_code processDefinedAtomsV1(const uint8_t* base,
@ -272,6 +303,7 @@ private:
this->_definedAtoms.arrayStart = atomsStart;
this->_definedAtoms.arrayEnd = atomsEnd;
this->_definedAtoms.elementSize = atomSize;
this->_definedAtoms.elementCount = chunk->elementCount;
return make_error_code(native_reader_error::success);
}
@ -307,6 +339,77 @@ private:
this->_undefinedAtoms.arrayStart = atomsStart;
this->_undefinedAtoms.arrayEnd = atomsEnd;
this->_undefinedAtoms.elementSize = atomSize;
this->_undefinedAtoms.elementCount = chunk->elementCount;
return make_error_code(native_reader_error::success);
}
// instantiate array of Referemces from v1 ivar data in file
llvm::error_code processReferencesV1(const uint8_t* base,
const NativeChunk* chunk) {
if ( chunk->elementCount == 0 )
return make_error_code(native_reader_error::success);
const size_t refSize = sizeof(NativeReferenceV1);
size_t refsArraySize = chunk->elementCount * refSize;
uint8_t* refsStart = reinterpret_cast<uint8_t*>
(operator new(refsArraySize, std::nothrow));
if (refsStart == NULL )
return make_error_code(native_reader_error::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeReferenceIvarsV1) )
return make_error_code(native_reader_error::file_malformed);
uint8_t* refsEnd = refsStart + refsArraySize;
const NativeReferenceIvarsV1* ivarData =
reinterpret_cast<const NativeReferenceIvarsV1*>
(base + chunk->fileOffset);
for(uint8_t* s = refsStart; s != refsEnd; s += refSize) {
NativeReferenceV1* atomAllocSpace =
reinterpret_cast<NativeReferenceV1*>(s);
new (atomAllocSpace) NativeReferenceV1(*this, ivarData);
++ivarData;
}
this->_references.arrayStart = refsStart;
this->_references.arrayEnd = refsEnd;
this->_references.elementSize = refSize;
this->_references.elementCount = chunk->elementCount;
return make_error_code(native_reader_error::success);
}
// set up pointers to target table
llvm::error_code processTargetsTable(const uint8_t* base,
const NativeChunk* chunk) {
const uint32_t* targetIndexes = reinterpret_cast<const uint32_t*>
(base + chunk->fileOffset);
this->_targetsTableCount = chunk->elementCount;
this->_targetsTable = new const Atom*[chunk->elementCount];
for (uint32_t i=0; i < chunk->elementCount; ++i) {
const uint32_t index = targetIndexes[i];
if ( index < _definedAtoms.elementCount ) {
const uint8_t* p = _definedAtoms.arrayStart
+ index * _definedAtoms.elementSize;
this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
continue;
}
const uint32_t undefIndex = index - _definedAtoms.elementCount;
if ( undefIndex < _undefinedAtoms.elementCount ) {
const uint8_t* p = _undefinedAtoms.arrayStart
+ undefIndex * _undefinedAtoms.elementSize;
this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
continue;
}
return make_error_code(native_reader_error::file_malformed);
}
return make_error_code(native_reader_error::success);
}
// set up pointers to addend pool in file
llvm::error_code processAddendsTable(const uint8_t* base,
const NativeChunk* chunk) {
this->_addends = reinterpret_cast<const Reference::Addend*>
(base + chunk->fileOffset);
this->_addendsMaxIndex = chunk->elementCount;
return make_error_code(native_reader_error::success);
}
@ -331,9 +434,16 @@ private:
return llvm::StringRef(&_strings[offset]);
}
const NativeAtomAttributesV1& attribute(uint32_t offset) const {
assert(offset < _attributesMaxOffset);
return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + offset);
Reference::Addend addend(uint32_t index) const {
if ( index == 0 )
return 0; // addend index zero is used to mean "no addend"
assert(index <= _addendsMaxIndex);
return _addends[index-1]; // one-based indexing
}
const NativeAtomAttributesV1& attribute(uint32_t off) const {
assert(off < _attributesMaxOffset);
return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + off);
}
const uint8_t* content(uint32_t offset, uint32_t size) const {
@ -342,44 +452,75 @@ private:
return result;
}
void forEachReference(DefinedAtom::ReferenceHandler& handler,
uint32_t start, uint32_t count) const {
assert(start < _references.elementCount);
assert(start+count <= _references.elementCount);
const uint8_t* arrStart = _references.arrayStart
+ start * _references.elementSize;
const uint8_t* arrEnd = arrStart + count * _references.elementSize;
for(const uint8_t* p=arrStart; p != arrEnd; p += _references.elementSize) {
const NativeReferenceV1* ref
= reinterpret_cast<const NativeReferenceV1*>(p);
handler.doReference(*ref);
}
}
const Atom* target(uint32_t index) const {
assert(index < _targetsTableCount);
return _targetsTable[index];
}
void setTarget(uint32_t index, const Atom* newAtom) const {
assert(index > _targetsTableCount);
_targetsTable[index] = newAtom;
}
// private constructor, only called by make()
NativeFile(llvm::OwningPtr<llvm::MemoryBuffer>& mb, llvm::StringRef path) :
lld::File(path),
_buffer(mb.take()), // NativeFile now takes ownership of buffer
_header(NULL),
_targetsTable(NULL),
_targetsTableCount(0),
_strings(NULL),
_stringsMaxOffset(0),
_addends(NULL),
_addendsMaxIndex(0),
_contentStart(NULL),
_contentEnd(NULL)
{
_header = reinterpret_cast<const NativeFileHeader*>(_buffer->getBufferStart());
_definedAtoms.arrayStart = NULL;
_undefinedAtoms.arrayStart = NULL;
}
struct AtomArray {
AtomArray() : arrayStart(NULL), arrayEnd(NULL),
elementSize(0) { }
struct IvarArray {
IvarArray() : arrayStart(NULL), arrayEnd(NULL),
elementSize(0), elementCount(0) { }
const uint8_t* arrayStart;
const uint8_t* arrayEnd;
uint32_t elementSize;
};
uint32_t elementCount;
};
llvm::OwningPtr<llvm::MemoryBuffer> _buffer;
const NativeFileHeader* _header;
AtomArray _definedAtoms;
AtomArray _undefinedAtoms;
IvarArray _definedAtoms;
IvarArray _undefinedAtoms;
const uint8_t* _attributes;
uint32_t _attributesMaxOffset;
IvarArray _references;
const Atom** _targetsTable;
uint32_t _targetsTableCount;
const char* _strings;
uint32_t _stringsMaxOffset;
const Reference::Addend* _addends;
uint32_t _addendsMaxIndex;
const uint8_t* _contentStart;
const uint8_t* _contentEnd;
};
inline const class File& NativeDefinedAtomV1::file() const {
return *_file;
}
@ -410,8 +551,12 @@ inline llvm::StringRef NativeDefinedAtomV1::customSectionName() const {
return _file->string(offset);
}
inline void NativeDefinedAtomV1::forEachReference(ReferenceHandler& hnd) const {
if ( _ivarData->referencesCount == 0 )
return;
_file->forEachReference(hnd, _ivarData->referencesStartIndex,
_ivarData->referencesCount);
}
inline const class File& NativeUndefinedAtomV1::file() const {
return *_file;
@ -422,6 +567,17 @@ inline llvm::StringRef NativeUndefinedAtomV1::name() const {
}
inline const Atom* NativeReferenceV1::target() const {
return _file->target(_ivarData->targetIndex);
}
inline Reference::Addend NativeReferenceV1::addend() const {
return _file->addend(_ivarData->addendIndex);
}
inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
return _file->setTarget(_ivarData->targetIndex, newAtom);
}
//

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "lld/Core/File.h"
#include "lld/Core/NativeWriter.h"
@ -25,10 +26,13 @@ namespace lld {
///
/// Class for writing native object files.
///
class NativeWriter : public File::AtomHandler {
class NativeWriter : public File::AtomHandler,
public DefinedAtom::ReferenceHandler {
public:
/// construct writer for an lld::File object
NativeWriter(const lld::File& file) : _file(file) {
// reserve first byte for unnamed atoms
_stringPool.push_back('\0');
// visit all atoms
_file.forEachAtom(*this);
// construct file header based on atom information accumulated
@ -37,36 +41,73 @@ public:
// write the lld::File in native format to the specified stream
void write(llvm::raw_ostream& out) {
assert( out.tell() == 0 );
out.write((char*)_headerBuffer, _headerBufferSize);
if (!_definedAtomIvars.empty())
if (!_definedAtomIvars.empty()) {
assert( out.tell() == findChunk(NCS_DefinedAtomsV1).fileOffset );
out.write((char*)&_definedAtomIvars[0],
_definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1));
if (!_attributes.empty())
}
if (!_attributes.empty()) {
assert( out.tell() == findChunk(NCS_AttributesArrayV1).fileOffset );
out.write((char*)&_attributes[0],
_attributes.size()*sizeof(NativeAtomAttributesV1));
if ( !_undefinedAtomIvars.empty() )
}
if ( !_undefinedAtomIvars.empty() ) {
assert( out.tell() == findChunk(NCS_UndefinedAtomsV1).fileOffset );
out.write((char*)&_undefinedAtomIvars[0],
_undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
if (!_stringPool.empty())
}
if (!_stringPool.empty()) {
assert( out.tell() == findChunk(NCS_Strings).fileOffset );
out.write(&_stringPool[0], _stringPool.size());
if (!_contentPool.empty())
}
if ( !_references.empty() ) {
assert( out.tell() == findChunk(NCS_ReferencesArrayV1).fileOffset );
out.write((char*)&_references[0],
_references.size()*sizeof(NativeReferenceIvarsV1));
}
if ( !_targetsTableIndex.empty() ) {
assert( out.tell() == findChunk(NCS_TargetsTable).fileOffset );
writeTargetTable(out);
}
if ( !_addendsTableIndex.empty() ) {
assert( out.tell() == findChunk(NCS_AddendsTable).fileOffset );
writeAddendTable(out);
}
if (!_contentPool.empty()) {
assert( out.tell() == findChunk(NCS_Content).fileOffset );
out.write((char*)&_contentPool[0], _contentPool.size());
}
}
private:
// visitor routine called by forEachAtom()
virtual void doDefinedAtom(const class DefinedAtom& atom) {
virtual void doDefinedAtom(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);
}
// visitor routine called by forEachAtom()
virtual void doUndefinedAtom(const class UndefinedAtom& atom) {
virtual void doUndefinedAtom(const UndefinedAtom& atom) {
_undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
NativeUndefinedAtomIvarsV1 ivar;
ivar.nameOffset = getNameOffset(atom);
ivar.flags = (atom.weakImport() ? 1 : 0);
@ -74,13 +115,18 @@ private:
}
// visitor routine called by forEachAtom()
virtual void doFile(const class File &) {
virtual void doFile(const File &) {
}
// fill out native file header and chunk directory
void makeHeader() {
const bool hasUndefines = !_undefinedAtomIvars.empty();
const int chunkCount = hasUndefines ? 5 : 4;
const bool hasTargetsTable = !_targetsTableIndex.empty();
const bool hasAddendTable = !_addendsTableIndex.empty();
int chunkCount = 5;
if ( hasUndefines ) ++chunkCount;
if ( hasTargetsTable ) ++chunkCount;
if ( hasAddendTable ) ++chunkCount;
_headerBufferSize = sizeof(NativeFileHeader)
+ chunkCount*sizeof(NativeChunk);
_headerBuffer = reinterpret_cast<NativeFileHeader*>
@ -124,6 +170,9 @@ private:
}
// create chunk for symbol strings
// pad end of string pool to 4-bytes
while ( (_stringPool.size() % 4) != 0 )
_stringPool.push_back('\0');
NativeChunk& chs = chunks[nextIndex++];
chs.signature = NCS_Strings;
chs.fileOffset = nextFileOffset;
@ -131,6 +180,34 @@ private:
chs.elementCount = _stringPool.size();
nextFileOffset = chs.fileOffset + chs.fileSize;
// create chunk for references
NativeChunk& chr = chunks[nextIndex++];
chr.signature = NCS_ReferencesArrayV1;
chr.fileOffset = nextFileOffset;
chr.fileSize = _references.size() * sizeof(NativeReferenceIvarsV1);
chr.elementCount = _references.size();
nextFileOffset = chr.fileOffset + chr.fileSize;
// 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
NativeChunk& chc = chunks[nextIndex++];
chc.signature = NCS_Content;
@ -142,6 +219,18 @@ private:
_headerBuffer->fileSize = nextFileOffset;
}
// 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];
}
assert(0 && "findChunk() signature not found");
}
// append atom name to string pool and return offset
uint32_t getNameOffset(const Atom& atom) {
@ -150,6 +239,8 @@ private:
// append atom name to string pool and return offset
uint32_t getNameOffset(llvm::StringRef name) {
if ( name.empty() )
return 0;
uint32_t result = _stringPool.size();
_stringPool.insert(_stringPool.end(), name.size()+1, 0);
strcpy(&_stringPool[result], name.data());
@ -206,7 +297,6 @@ private:
attrs.sectionNameOffset = sectionNameOffset(atom);
attrs.align2 = atom.alignment().powerOf2;
attrs.alignModulus = atom.alignment().modulus;
attrs.internalName = atom.internalName();
attrs.scope = atom.scope();
attrs.interposable = atom.interposable();
attrs.merge = atom.merge();
@ -214,12 +304,99 @@ private:
attrs.sectionChoice = atom.sectionChoice();
attrs.deadStrip = atom.deadStrip();
attrs.permissions = atom.permissions();
attrs.thumb = atom.isThumb();
//attrs.thumb = atom.isThumb();
attrs.alias = atom.isAlias();
}
// add references for this atom in a contiguous block in NCS_ReferencesArrayV1
uint32_t getReferencesIndex(const DefinedAtom& atom, unsigned& count) {
count = 0;
size_t startRefSize = _references.size();
uint32_t result = startRefSize;
atom.forEachReference(*this);
count = _references.size() - startRefSize;
if ( count == 0 )
return 0;
else
return result;
}
void doReference(const Reference& ref) {
NativeReferenceIvarsV1 nref;
nref.offsetInAtom = ref.offsetInAtom();
nref.kind = ref.kind();
nref.targetIndex = this->getTargetIndex(ref.target());
nref.addendIndex = this->getAddendIndex(ref.addend());
_references.push_back(nref);
}
uint32_t getTargetIndex(const Atom* target) {
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(llvm::raw_ostream& out) {
// Build table of target indexes
uint32_t maxTargetIndex = _targetsTableIndex.size();
uint32_t targetIndexes[maxTargetIndex];
for (TargetToIndex::iterator it = _targetsTableIndex.begin();
it != _targetsTableIndex.end(); ++it) {
const Atom* atom = it->first;
uint32_t targetIndex = it->second;
assert(targetIndex < maxTargetIndex);
uint32_t atomIndex = 0;
TargetToIndex::iterator pos = _definedAtomIndex.find(atom);
if ( pos != _definedAtomIndex.end() ) {
atomIndex = pos->second;
}
else {
pos = _undefinedAtomIndex.find(atom);
assert(pos != _undefinedAtomIndex.end());
atomIndex = pos->second + _definedAtomIvars.size();
}
targetIndexes[targetIndex] = atomIndex;
}
// 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(llvm::raw_ostream& out) {
// Build table of addends
uint32_t maxAddendIndex = _addendsTableIndex.size();
Reference::Addend addends[maxAddendIndex];
for (AddendToIndex::iterator it = _addendsTableIndex.begin();
it != _addendsTableIndex.end(); ++it) {
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<llvm::StringRef, uint32_t> > NameToOffsetVector;
typedef llvm::DenseMap<const Atom*, uint32_t> TargetToIndex;
typedef llvm::DenseMap<Reference::Addend, uint32_t> AddendToIndex;
const lld::File& _file;
NativeFileHeader* _headerBuffer;
size_t _headerBufferSize;
@ -228,6 +405,11 @@ private:
std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
std::vector<NativeAtomAttributesV1> _attributes;
std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
std::vector<NativeReferenceIvarsV1> _references;
TargetToIndex _targetsTableIndex;
TargetToIndex _definedAtomIndex;
TargetToIndex _undefinedAtomIndex;
AddendToIndex _addendsTableIndex;
NameToOffsetVector _sectionNames;
};

View File

@ -199,20 +199,34 @@ void Resolver::resolveUndefines() {
}
}
// helper to update targets for use with forEachReference()
class ReferenceUpdater : public DefinedAtom::ReferenceHandler {
public:
ReferenceUpdater(SymbolTable& sym) : _symbolTable(sym) { }
virtual void doReference(const Reference& ref) {
const Atom* newTarget = _symbolTable.replacement(ref.target());
(const_cast<Reference*>(&ref))->setTarget(newTarget);
}
private:
SymbolTable& _symbolTable;
};
// switch all references to undefined or coalesced away atoms
// to the new defined atom
void Resolver::updateReferences() {
ReferenceUpdater updater(_symbolTable);
for (std::vector<const Atom *>::iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
if ( const DefinedAtom* defAtom = (*it)->definedAtom() ) {
for (Reference::iterator rit = defAtom->referencesBegin(),
end = defAtom->referencesEnd(); rit != end; ++rit) {
rit->target = _symbolTable.replacement(rit->target);
}
defAtom->forEachReference(updater);
}
}
}
// for dead code stripping, recursively mark atom "live"
void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) {
// if -why_live cares about this symbol, then dump chain
@ -240,10 +254,8 @@ void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) {
thisChain.previous = previous;
thisChain.referer = &atom;
if ( const DefinedAtom* defAtom = atom.definedAtom() ) {
for (Reference::iterator rit = defAtom->referencesBegin(),
end = defAtom->referencesEnd(); rit != end; ++rit) {
this->markLive(*(rit->target), &thisChain);
}
MarkLiveReferences markRefs(*this, &thisChain);
defAtom->forEachReference(markRefs);
}
}

View File

@ -38,7 +38,7 @@ void SymbolTable::add(const UndefinedAtom &atom) {
void SymbolTable::add(const DefinedAtom &atom) {
assert(atom.scope() != DefinedAtom::scopeTranslationUnit);
if ( !atom.internalName() ) {
if ( !atom.name().empty() ) {
this->addByName(atom);
}
else {

View File

@ -18,12 +18,12 @@ namespace yaml {
const char* const KeyValues::nameKeyword = "name";
const char* const KeyValues::refNameKeyword = "ref-name";
const char* const KeyValues::definitionKeyword = "definition";
const char* const KeyValues::scopeKeyword = "scope";
const char* const KeyValues::contentTypeKeyword = "type";
const char* const KeyValues::deadStripKindKeyword = "dead-strip";
const char* const KeyValues::sectionChoiceKeyword = "section-choice";
const char* const KeyValues::internalNameKeyword = "internal-name";
const char* const KeyValues::interposableKeyword = "interposable";
const char* const KeyValues::mergeKeyword = "merge";
const char* const KeyValues::isThumbKeyword = "is-thumb";
@ -31,8 +31,14 @@ const char* const KeyValues::isAliasKeyword = "is-alias";
const char* const KeyValues::sectionNameKeyword = "section-name";
const char* const KeyValues::contentKeyword = "content";
const char* const KeyValues::sizeKeyword = "size";
const char* const KeyValues::fixupsKeyword = "fixups";
const char* const KeyValues::permissionsKeyword = "permissions";
const char* const KeyValues::weakImportKeyword = "weak-import";
const char* const KeyValues::fixupsKindKeyword = "kind";
const char* const KeyValues::fixupsOffsetKeyword = "offset";
const char* const KeyValues::fixupsTargetKeyword = "target";
const char* const KeyValues::fixupsAddendKeyword = "addend";
const DefinedAtom::Definition KeyValues::definitionDefault = Atom::definitionRegular;
@ -43,7 +49,6 @@ const DefinedAtom::SectionChoice KeyValues::sectionChoiceDefault = DefinedA
const DefinedAtom::Interposable KeyValues::interposableDefault = DefinedAtom::interposeNo;
const DefinedAtom::Merge KeyValues::mergeDefault = DefinedAtom::mergeNo;
const DefinedAtom::ContentPermissions KeyValues::permissionsDefault = DefinedAtom::permR__;
const bool KeyValues::internalNameDefault = false;
const bool KeyValues::isThumbDefault = false;
const bool KeyValues::isAliasDefault = false;
const bool KeyValues::weakImportDefault = false;
@ -352,22 +357,6 @@ const char* KeyValues::permissions(DefinedAtom::ContentPermissions s) {
bool KeyValues::internalName(const char* s)
{
if ( strcmp(s, "true") == 0 )
return true;
else if ( strcmp(s, "false") == 0 )
return false;
llvm::report_fatal_error("bad internal-name value");
}
const char* KeyValues::internalName(bool b) {
return b ? "true" : "false";
}
bool KeyValues::isThumb(const char* s)
{
if ( strcmp(s, "true") == 0 )

View File

@ -20,10 +20,12 @@ namespace yaml {
class KeyValues {
public:
static const char* const nameKeyword;
static const char* const refNameKeyword;
static const char* const sectionNameKeyword;
static const char* const contentKeyword;
static const char* const sizeKeyword;
static const char* const fixupsKeyword;
static const char* const definitionKeyword;
static const Atom::Definition definitionDefault;
static Atom::Definition definition(const char*);
@ -64,11 +66,6 @@ public:
static DefinedAtom::ContentPermissions permissions(const char*);
static const char* permissions(DefinedAtom::ContentPermissions);
static const char* const internalNameKeyword;
static const bool internalNameDefault;
static bool internalName(const char*);
static const char* internalName(bool);
static const char* const isThumbKeyword;
static const bool isThumbDefault;
static bool isThumb(const char*);
@ -84,6 +81,12 @@ public:
static bool weakImport(const char*);
static const char* weakImport(bool);
static const char* const fixupsKindKeyword;
static const char* const fixupsOffsetKeyword;
static const char* const fixupsTargetKeyword;
static const char* const fixupsAddendKeyword;
};
} // namespace yaml

View File

@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include <string.h>
#include "YamlKeyValues.h"
#include "lld/Core/YamlReader.h"
@ -30,6 +32,8 @@
namespace lld {
namespace yaml {
namespace {
class YAML {
public:
struct Entry {
@ -214,7 +218,7 @@ void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
sequenceBytes->push_back(contentByte);
state = inValueSequenceEnd;
}
else if (c == ' ') {
else if ( (c == ' ') || (c == '\n') ) {
// eat white space
}
else if (c == ',') {
@ -245,6 +249,44 @@ void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
}
}
class YAMLReference : public Reference {
public:
YAMLReference() : _target(NULL), _targetName(NULL),
_offsetInAtom(0), _addend(0), _kind(0) { }
virtual uint64_t offsetInAtom() const {
return _offsetInAtom;
}
virtual Kind kind() const {
return _kind;
}
virtual const Atom* target() const {
return _target;
}
virtual Addend addend() const {
return _addend;
}
virtual void setTarget(const Atom* newAtom) {
_target = newAtom;
}
const Atom* _target;
const char* _targetName;
uint64_t _offsetInAtom;
Addend _addend;
Kind _kind;
};
class YAMLDefinedAtom;
class YAMLFile : public File {
public:
YAMLFile()
@ -255,29 +297,24 @@ public:
virtual bool justInTimeforEachAtom(llvm::StringRef name,
File::AtomHandler &) const;
std::vector<DefinedAtom*> _definedAtoms;
std::vector<UndefinedAtom*> _undefinedAtoms;
std::vector<Reference> _references;
unsigned int _lastRefIndex;
void bindTargetReferences();
void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
void addUndefinedAtom(UndefinedAtom* atom);
Atom* findAtom(const char* name);
struct NameAtomPair {
NameAtomPair(const char* n, Atom* a) : name(n), atom(a) {}
const char* name;
Atom* atom;
};
std::vector<YAMLDefinedAtom*> _definedAtoms;
std::vector<UndefinedAtom*> _undefinedAtoms;
std::vector<YAMLReference> _references;
std::vector<NameAtomPair> _nameToAtomMapping;
unsigned int _lastRefIndex;
};
bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
handler.doFile(*this);
for (std::vector<DefinedAtom *>::const_iterator it = _definedAtoms.begin();
it != _definedAtoms.end(); ++it) {
handler.doDefinedAtom(**it);
}
for (std::vector<UndefinedAtom *>::const_iterator it = _undefinedAtoms.begin();
it != _undefinedAtoms.end(); ++it) {
handler.doUndefinedAtom(**it);
}
return true;
}
bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
File::AtomHandler &handler) const {
return false;
}
class YAMLDefinedAtom : public DefinedAtom {
@ -291,7 +328,6 @@ public:
, DefinedAtom::Merge merge
, DefinedAtom::DeadStripKind deadStrip
, DefinedAtom::ContentPermissions perms
, bool internalName
, bool isThumb
, bool isAlias
, DefinedAtom::Alignment alignment
@ -313,7 +349,6 @@ public:
, _merge(merge)
, _deadStrip(deadStrip)
, _permissions(perms)
, _internalName(internalName)
, _isThumb(isThumb)
, _isAlias(isAlias)
, _refStartIndex(file._lastRefIndex)
@ -326,13 +361,12 @@ public:
}
virtual llvm::StringRef name() const {
return _name;
if ( _name == NULL )
return llvm::StringRef();
else
return _name;
}
virtual bool internalName() const {
return _internalName;
}
virtual uint64_t size() const {
return (_content ? _content->size() : _size);
}
@ -393,16 +427,18 @@ public:
}
virtual Reference::iterator referencesBegin() const {
if (_file._references.size() < _refStartIndex)
return (Reference::iterator)&_file._references[_refStartIndex];
return 0;
virtual void forEachReference(ReferenceHandler& handler) const {
for (uint32_t i=_refStartIndex; i < _refEndIndex; ++i) {
handler.doReference(_file._references[i]);
}
}
virtual Reference::iterator referencesEnd() const {
if (_file._references.size() < _refEndIndex)
return (Reference::iterator)&_file._references[_refEndIndex];
return 0;
void bindTargetReferences() {
for (unsigned int i=_refStartIndex; i < _refEndIndex; ++i) {
const char* targetName = _file._references[i]._targetName;
Atom* targetAtom = _file.findAtom(targetName);
_file._references[i]._target = targetAtom;
}
}
private:
@ -420,7 +456,6 @@ private:
DefinedAtom::Merge _merge;
DefinedAtom::DeadStripKind _deadStrip;
DefinedAtom::ContentPermissions _permissions;
bool _internalName;
bool _isThumb;
bool _isAlias;
unsigned int _refStartIndex;
@ -453,22 +488,71 @@ private:
};
bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
handler.doFile(*this);
for (std::vector<YAMLDefinedAtom *>::const_iterator it = _definedAtoms.begin();
it != _definedAtoms.end(); ++it) {
handler.doDefinedAtom(**it);
}
for (std::vector<UndefinedAtom *>::const_iterator it = _undefinedAtoms.begin();
it != _undefinedAtoms.end(); ++it) {
handler.doUndefinedAtom(**it);
}
return true;
}
bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
File::AtomHandler &handler) const {
return false;
}
void YAMLFile::bindTargetReferences() {
for (std::vector<YAMLDefinedAtom *>::const_iterator
it = _definedAtoms.begin(); it != _definedAtoms.end(); ++it) {
YAMLDefinedAtom* atom = *it;
atom->bindTargetReferences();
}
}
Atom* YAMLFile::findAtom(const char* name) {
for (std::vector<NameAtomPair>::const_iterator it = _nameToAtomMapping.begin();
it != _nameToAtomMapping.end(); ++it) {
if ( strcmp(name, it->name) == 0 )
return it->atom;
}
llvm::report_fatal_error("reference to atom that does not exist");
}
void YAMLFile::addDefinedAtom(YAMLDefinedAtom* atom, const char* refName) {
_definedAtoms.push_back(atom);
assert(refName != NULL);
_nameToAtomMapping.push_back(NameAtomPair(refName, atom));
}
void YAMLFile::addUndefinedAtom(UndefinedAtom* atom) {
_undefinedAtoms.push_back(atom);
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
}
class YAMLAtomState {
public:
YAMLAtomState();
void setName(const char *n);
void setRefName(const char *n);
void setAlign2(const char *n);
void setFixupKind(const char *n);
void setFixupOffset(const char *n);
void setFixupTarget(const char *n);
void setFixupAddend(const char *n);
void addFixup(YAMLFile *f);
void makeAtom(YAMLFile&);
const char * _name;
const char * _refName;
const char * _sectionName;
unsigned long long _size;
uint32_t _ordinal;
@ -482,16 +566,16 @@ public:
DefinedAtom::Merge _merge;
DefinedAtom::DeadStripKind _deadStrip;
DefinedAtom::ContentPermissions _permissions;
bool _internalName;
bool _isThumb;
bool _isAlias;
bool _weakImport;
Reference _ref;
YAMLReference _ref;
};
YAMLAtomState::YAMLAtomState()
: _name(NULL)
, _refName(NULL)
, _sectionName(NULL)
, _size(0)
, _ordinal(0)
@ -505,38 +589,31 @@ YAMLAtomState::YAMLAtomState()
, _merge(KeyValues::mergeDefault)
, _deadStrip(KeyValues::deadStripKindDefault)
, _permissions(KeyValues::permissionsDefault)
, _internalName(KeyValues::internalNameDefault)
, _isThumb(KeyValues::isThumbDefault)
, _isAlias(KeyValues::isAliasDefault)
, _weakImport(false)
{
_ref.target = NULL;
_ref.addend = 0;
_ref.offsetInAtom = 0;
_ref.kind = 0;
_ref.flags = 0;
}
}
void YAMLAtomState::makeAtom(YAMLFile& f) {
if ( _definition == Atom::definitionRegular ) {
DefinedAtom *a = new YAMLDefinedAtom(_ordinal, f, _scope, _type,
YAMLDefinedAtom *a = new YAMLDefinedAtom(_ordinal, f, _scope, _type,
_sectionChoice, _interpose, _merge, _deadStrip,
_permissions, _internalName, _isThumb, _isAlias,
_permissions, _isThumb, _isAlias,
_alignment, _name, _sectionName, _size, _content);
f._definedAtoms.push_back(a);
f.addDefinedAtom(a, _refName ? _refName : _name);
++_ordinal;
}
else if ( _definition == Atom::definitionUndefined ) {
UndefinedAtom *a = new YAMLUndefinedAtom(f, _ordinal, _name, _weakImport);
f._undefinedAtoms.push_back(a);
f.addUndefinedAtom(a);
++_ordinal;
}
// reset state for next atom
_name = NULL;
_refName = NULL;
_sectionName = NULL;
_size = 0;
_ordinal = 0;
@ -554,17 +631,20 @@ void YAMLAtomState::makeAtom(YAMLFile& f) {
_isThumb = KeyValues::isThumbDefault;
_isAlias = KeyValues::isAliasDefault;
_weakImport = KeyValues::weakImportDefault;
_ref.target = NULL;
_ref.addend = 0;
_ref.offsetInAtom = 0;
_ref.kind = 0;
_ref.flags = 0;
_ref._target = NULL;
_ref._targetName = NULL;
_ref._addend = 0;
_ref._offsetInAtom = 0;
_ref._kind = 0;
}
void YAMLAtomState::setName(const char *n) {
_name = n;
}
void YAMLAtomState::setRefName(const char *n) {
_refName = n;
}
void YAMLAtomState::setAlign2(const char *s) {
llvm::StringRef str(s);
@ -576,33 +656,54 @@ void YAMLAtomState::setAlign2(const char *s) {
void YAMLAtomState::setFixupKind(const char *s) {
if (strcmp(s, "pcrel32") == 0)
_ref.kind = 1;
_ref._kind = 1;
else if (strcmp(s, "call32") == 0)
_ref.kind = 2;
else
llvm::report_fatal_error("bad fixup kind value");
_ref._kind = 2;
else {
int k;
llvm::StringRef(s).getAsInteger(10, k);
_ref._kind = k;
}
}
void YAMLAtomState::setFixupOffset(const char *s) {
if ((s[0] == '0') && (s[1] == 'x'))
llvm::StringRef(s).getAsInteger(16, _ref.offsetInAtom);
llvm::StringRef(s).getAsInteger(16, _ref._offsetInAtom);
else
llvm::StringRef(s).getAsInteger(10, _ref.offsetInAtom);
llvm::StringRef(s).getAsInteger(10, _ref._offsetInAtom);
}
void YAMLAtomState::setFixupTarget(const char *s) {
_ref._targetName = s;
}
void YAMLAtomState::setFixupAddend(const char *s) {
if ((s[0] == '0') && (s[1] == 'x'))
llvm::StringRef(s).getAsInteger(16, _ref._addend);
else
llvm::StringRef(s).getAsInteger(10, _ref._addend);
}
void YAMLAtomState::addFixup(YAMLFile *f) {
f->_references.push_back(_ref);
// clear for next ref
_ref.target = NULL;
_ref.addend = 0;
_ref.offsetInAtom = 0;
_ref.kind = 0;
_ref.flags = 0;
_ref._target = NULL;
_ref._targetName = NULL;
_ref._addend = 0;
_ref._offsetInAtom = 0;
_ref._kind = 0;
}
} // anonymous namespace
/// parseObjectText - Parse the specified YAML formatted MemoryBuffer
/// into lld::File object(s) and append each to the specified vector<File*>.
llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
, std::vector<File *> &result) {
std::vector<const YAML::Entry *> entries;
@ -628,6 +729,7 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
atomState.makeAtom(*file);
haveAtom = false;
}
file->bindTargetReferences();
result.push_back(file);
}
file = new YAMLFile();
@ -663,10 +765,10 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
atomState.setName(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::internalNameKeyword) == 0) {
atomState._internalName = KeyValues::internalName(entry->value);
else if (strcmp(entry->key, KeyValues::refNameKeyword) == 0) {
atomState.setRefName(entry->value);
haveAtom = true;
}
}
else if (strcmp(entry->key, KeyValues::definitionKeyword) == 0) {
atomState._definition = KeyValues::definition(entry->value);
haveAtom = true;
@ -725,8 +827,9 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
atomState.setAlign2(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, "fixups") == 0) {
else if (strcmp(entry->key, KeyValues::fixupsKeyword) == 0) {
inFixups = true;
}
else {
return make_error_code(yaml_reader_error::unknown_keyword);
@ -739,16 +842,22 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
haveFixup = false;
}
}
if (strcmp(entry->key, "kind") == 0) {
if (strcmp(entry->key, KeyValues::fixupsKindKeyword) == 0) {
atomState.setFixupKind(entry->value);
haveFixup = true;
} else if (strcmp(entry->key, "offset") == 0) {
}
else if (strcmp(entry->key, KeyValues::fixupsOffsetKeyword) == 0) {
atomState.setFixupOffset(entry->value);
haveFixup = true;
} else if (strcmp(entry->key, "target") == 0) {
}
else if (strcmp(entry->key, KeyValues::fixupsTargetKeyword) == 0) {
atomState.setFixupTarget(entry->value);
haveFixup = true;
}
else if (strcmp(entry->key, KeyValues::fixupsAddendKeyword) == 0) {
atomState.setFixupAddend(entry->value);
haveFixup = true;
}
}
}
lastDepth = entry->depth;
@ -757,10 +866,12 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
atomState.makeAtom(*file);
}
file->bindTargetReferences();
result.push_back(file);
return make_error_code(yaml_reader_error::success);
}
//
// Fill in vector<File*> from path to input text file.
//

View File

@ -15,6 +15,8 @@
#include "lld/Core/Reference.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/DataTypes.h"
@ -26,50 +28,154 @@
namespace lld {
namespace yaml {
class Handler : public File::AtomHandler {
namespace {
///
/// In most cases, atoms names are unambiguous, so references can just
/// use the atom name as the target (e.g. target: foo). But in a few
/// cases that does not work, so ref-names are added. These are labels
/// used only in yaml. The labels do not exist in the Atom model.
///
/// One need for ref-names are when atoms have no user supplied name
/// (e.g. c-string literal). Another case is when two object files with
/// identically named static functions are merged (ld -r) into one object file.
/// In that case referencing the function by name is ambiguous, so a unique
/// ref-name is added.
///
class RefNameBuilder : public File::AtomHandler,
public DefinedAtom::ReferenceHandler {
public:
Handler(llvm::raw_ostream &out) : _out(out), _firstAtom(true) { }
RefNameBuilder() { }
virtual void doReference(const Reference& ref) {
// create refname for any unnamed reference target
if ( ref.target()->name().empty() ) {
char* buffer;
asprintf(&buffer, "L%03d", _unnamedCounter++);
_refNames[ref.target()] = buffer;
}
}
virtual void doFile(const File &) { }
virtual void doDefinedAtom(const DefinedAtom& atom) {
// Build map of atoms names to detect duplicates
if ( ! atom.name().empty() )
buildDuplicateNameMap(atom);
// Find references to unnamed atoms and create ref-names for them.
_unnamedCounter = 0;
atom.forEachReference(*this);
}
virtual void doUndefinedAtom(const UndefinedAtom& atom) {
buildDuplicateNameMap(atom);
}
void buildDuplicateNameMap(const Atom& atom) {
assert(!atom.name().empty());
NameToAtom::iterator pos = _nameMap.find(atom.name());
if ( pos != _nameMap.end() ) {
// Found name collision, give each a unique ref-name.
char* buffer;
asprintf(&buffer, "%s.%03d", atom.name().data(), ++_collisionCount);
_refNames[&atom] = buffer;
const Atom* prevAtom = pos->second;
AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
if ( pos2 == _refNames.end() ) {
// only create ref-name for previous if none already created
asprintf(&buffer, "%s.%03d", prevAtom->name().data(), ++_collisionCount);
_refNames[prevAtom] = buffer;
}
}
else {
// First time we've seen this name, just add it to map.
_nameMap[atom.name()] = &atom;
}
}
bool hasRefName(const Atom* atom) {
return _refNames.count(atom);
}
const char* refName(const Atom* atom) {
return _refNames.find(atom)->second;
}
private:
struct MyMappingInfo {
static llvm::StringRef getEmptyKey() { return llvm::StringRef(); }
static llvm::StringRef getTombstoneKey() { return llvm::StringRef(" ", 0); }
static unsigned getHashValue(llvm::StringRef const val) {
return llvm::HashString(val); }
static bool isEqual(llvm::StringRef const lhs,
llvm::StringRef const rhs) { return lhs.equals(rhs); }
};
typedef llvm::DenseMap<llvm::StringRef, const Atom*, MyMappingInfo> NameToAtom;
typedef llvm::DenseMap<const Atom*, const char*> AtomToRefName;
unsigned int _collisionCount;
unsigned int _unnamedCounter;
NameToAtom _nameMap;
AtomToRefName _refNames;
};
///
/// Helper class for writeObjectText() to write out atoms in yaml format.
///
class AtomWriter : public File::AtomHandler,
public DefinedAtom::ReferenceHandler {
public:
AtomWriter(RefNameBuilder& rnb, llvm::raw_ostream &out)
: _out(out), _rnb(rnb), _firstAtom(true) { }
virtual void doFile(const class File &) { _firstAtom = true; }
virtual void doDefinedAtom(const class DefinedAtom &atom) {
// add blank line between atoms for readability
if ( !_firstAtom )
_out << "\n";
_firstAtom = false;
// add blank line between atoms for readability
if ( !_firstAtom )
_out << "\n";
_firstAtom = false;
bool hasDash = false;
if ( !atom.name().empty() ) {
_out << " - "
<< KeyValues::nameKeyword
<< ":"
<< spacePadding(KeyValues::nameKeyword)
<< atom.name()
<< "\n";
if ( atom.internalName() != KeyValues::internalNameDefault ) {
_out << " "
<< KeyValues::internalNameKeyword
hasDash = true;
}
if ( _rnb.hasRefName(&atom) ) {
_out << (hasDash ? " " : " - ")
<< KeyValues::refNameKeyword
<< ":"
<< spacePadding(KeyValues::internalNameKeyword)
<< KeyValues::internalName(atom.internalName())
<< spacePadding(KeyValues::refNameKeyword)
<< _rnb.refName(&atom)
<< "\n";
hasDash = true;
}
if ( atom.definition() != KeyValues::definitionDefault ) {
_out << " "
_out << (hasDash ? " " : " - ")
<< KeyValues::definitionKeyword
<< ":"
<< spacePadding(KeyValues::definitionKeyword)
<< KeyValues::definition(atom.definition())
<< "\n";
hasDash = true;
}
if ( atom.scope() != KeyValues::scopeDefault ) {
_out << " "
_out << (hasDash ? " " : " - ")
<< KeyValues::scopeKeyword
<< ":"
<< spacePadding(KeyValues::scopeKeyword)
<< KeyValues::scope(atom.scope())
<< "\n";
hasDash = true;
}
if ( atom.interposable() != KeyValues::interposableDefault ) {
@ -161,16 +267,50 @@ public:
_out << " ]\n";
}
if (atom.referencesBegin() != atom.referencesEnd()) {
_out << " fixups:\n";
for (Reference::iterator it = atom.referencesBegin(),
end = atom.referencesEnd(); it != end; ++it) {
_out << " - kind: " << it->kind << "\n";
_out << " offset: " << it->offsetInAtom << "\n";
}
}
_wroteFirstFixup = false;
atom.forEachReference(*this);
}
virtual void doReference(const Reference& ref) {
if ( !_wroteFirstFixup ) {
_out << " fixups:\n";
_wroteFirstFixup = true;
}
_out << " - "
<< KeyValues::fixupsOffsetKeyword
<< ":"
<< spacePadding(KeyValues::fixupsOffsetKeyword)
<< ref.offsetInAtom()
<< "\n";
_out << " "
<< KeyValues::fixupsKindKeyword
<< ":"
<< spacePadding(KeyValues::fixupsKindKeyword)
<< ref.kind()
<< "\n";
const Atom* target = ref.target();
if ( target != NULL ) {
llvm::StringRef refName = target->name();
if ( _rnb.hasRefName(target) )
refName = _rnb.refName(target);
assert(!refName.empty());
_out << " "
<< KeyValues::fixupsTargetKeyword
<< ":"
<< spacePadding(KeyValues::fixupsTargetKeyword)
<< refName
<< "\n";
}
if ( ref.addend() != 0 ) {
_out << " "
<< KeyValues::fixupsAddendKeyword
<< ":"
<< spacePadding(KeyValues::fixupsAddendKeyword)
<< ref.addend()
<< "\n";
}
}
virtual void doUndefinedAtom(const class UndefinedAtom &atom) {
// add blank line between atoms for readability
@ -219,11 +359,26 @@ private:
}
llvm::raw_ostream& _out;
RefNameBuilder _rnb;
bool _firstAtom;
bool _wroteFirstFixup;
};
} // anonymous namespace
///
/// writeObjectText - writes the lld::File object as in YAML
/// format to the specified stream.
///
void writeObjectText(const File &file, llvm::raw_ostream &out) {
Handler h(out);
// Figure what ref-name labels are needed
RefNameBuilder rnb;
file.forEachAtom(rnb);
// Write out all atoms
AtomWriter h(rnb, out);
out << "---\n";
out << "atoms:\n";
file.forEachAtom(h);

View File

@ -6,28 +6,24 @@
---
atoms:
- name: L0
internal-name: true
- ref-name: L0
scope: hidden
type: c-string
content: [ 68, 65, 6c, 6c, 6f, 00 ]
- name: L1
internal-name: true
- ref-name: L1
scope: hidden
type: c-string
content: [ 74, 68, 65, 72, 65, 00 ]
---
atoms:
- name: L2
internal-name: true
- ref-name: L2
scope: hidden
type: c-string
content: [ 68, 65, 6c, 6c, 6f, 00 ]
---
atoms:
- name: L2
internal-name: true
- ref-name: L2
scope: hidden
type: c-string
content: [ 74, 68, 65, 72, 65, 00 ]

View File

@ -0,0 +1,50 @@
# RUN: lld-core %s | FileCheck %s
#
# Test addends in fixups
#
---
atoms:
- name: foo
type: code
content: [ 48, 8D, 3D, 00, 00, 00, 00,
48, 8D, 3D, 00, 00, 00, 00 ]
fixups:
- offset: 3
kind: 3
target: bar
addend: 100
- offset: 10
kind: 3
target: bar
addend: -50
- name: func
type: code
content: [ 48, 8D, 3D, 00, 00, 00, 00,
48, 8D, 3D, 00, 00, 00, 00 ]
fixups:
- offset: 3
kind: 3
target: bar
addend: 8000000000
- offset: 10
kind: 3
target: bar
addend: -50
- name: bar
definition: undefined
...
# CHECK: name: foo
# CHECK: fixups:
# CHECK: addend: 100
# CHECK: addend: -50
# CHECK: name: func
# CHECK: fixups:
# CHECK: addend: 8000000000
# CHECK: addend: -50

View File

@ -0,0 +1,31 @@
# RUN: lld-core %s | FileCheck %s
#
# Test fixups referencing multiple atoms that have the same name
#
---
atoms:
- name: foo
type: code
content: [ E8, 00, 00, 00, 00, E8, 00, 00, 00, 00 ]
fixups:
- offset: 1
kind: 3
target: bar_1
- offset: 6
kind: 3
target: bar_2
- name: bar
ref-name: bar_1
scope: static
- name: bar
ref-name: bar_2
scope: static
...
# CHECK: ...

View File

@ -0,0 +1,35 @@
# RUN: lld-core %s | FileCheck %s
#
# Test fixups to simple named atoms
#
---
atoms:
- name: foo
type: code
content: [ E8, 00, 00, 00, 00, E8, 00, 00, 00, 00 ]
fixups:
- offset: 1
kind: 3
target: bar
- offset: 6
kind: 3
target: baz
- name: baz
scope: static
type: code
- name: bar
definition: undefined
...
# CHECK: name: foo
# CHECK: fixups:
# CHECK: target: bar
# CHECK: target: baz
# CHECK: ...

View File

@ -0,0 +1,40 @@
# RUN: lld-core %s | FileCheck %s
#
# Test fixups to unnamed atoms
#
---
atoms:
- name: foo
type: code
content: [ 48, 8D, 3D, 00, 00, 00, 00,
48, 8D, 3D, 00, 00, 00, 00 ]
fixups:
- offset: 3
kind: 3
target: LC1
- offset: 10
kind: 3
target: LC2
- ref-name: LC1
scope: hidden
type: c-string
content: [ 68, 65, 6c, 6c, 6f, 00 ]
- ref-name: LC2
scope: hidden
type: c-string
content: [ 74, 68, 65, 72, 65, 00 ]
...
# CHECK: name: foo
# CHECK: fixups:
# CHECK: offset: 3
# CHECK: offset: 10
# CHECK: ref-name:
# CHECK: ref-name:

View File

@ -1,27 +0,0 @@
# RUN: lld-core %s | FileCheck %s
#
# Test that internal-name attributes are preserved
#
---
atoms:
- name: foo
internal-name: false
- name: L0
internal-name: true
- name: L1
internal-name: true
- name: bar
...
# CHECK: name: foo
# CHECK-NOT: internal-name: false
# CHECK: name: L0
# CHECK: internal-name: true
# CHECK: name: L1
# CHECK: internal-name: true
# CHECK: name: bar
# CHECK-NOT: internal-name: false
# CHECK: ...

View File

@ -234,8 +234,9 @@ int main(int argc, const char *argv[]) {
// read native file
llvm::OwningPtr<lld::File> natFile;
parseNativeObjectFileOrSTDIN(tempPath, natFile);
if ( error(parseNativeObjectFileOrSTDIN(tempPath, natFile)) )
return 1;
// write new atom graph out as YAML doc
yaml::writeObjectText(*natFile, out);