mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-07 18:10:24 +00:00
(no commit message)
llvm-svn: 150539
This commit is contained in:
parent
f0687634c3
commit
49d6cc8457
@ -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.
|
||||
|
@ -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_
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 )
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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);
|
||||
|
@ -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 ]
|
||||
|
50
lld/test/fixups-addend.objtxt
Normal file
50
lld/test/fixups-addend.objtxt
Normal 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
|
31
lld/test/fixups-dup-named.objtxt
Normal file
31
lld/test/fixups-dup-named.objtxt
Normal 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: ...
|
35
lld/test/fixups-named.objtxt
Normal file
35
lld/test/fixups-named.objtxt
Normal 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: ...
|
||||
|
40
lld/test/fixups-unnamed.objtxt
Normal file
40
lld/test/fixups-unnamed.objtxt
Normal 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:
|
@ -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: ...
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user