Add support for SharedLibraryAtoms (proxy atoms for exported symbols from a

shared library) and AbsoluteAtoms (proxy atoms for absolute address (e.g. ROM)).
Redesign weak importing as can-be-null-at-runtime and can-be-null-at-build-time.
Add lots of test cases for all the above.

llvm-svn: 151204
This commit is contained in:
Nick Kledzik 2012-02-22 21:56:59 +00:00
parent 1a3c3d4537
commit 6bc04c6904
23 changed files with 1233 additions and 137 deletions

View File

@ -0,0 +1,41 @@
//===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_ABSOLUTE_ATOM_H_
#define LLD_CORE_ABSOLUTE_ATOM_H_
#include "lld/Core/Atom.h"
namespace lld {
/// An AbsoluteAtom has no content.
/// It exists to represent content at fixed addresses in memory.
class AbsoluteAtom : public Atom {
public:
virtual Definition definition() const {
return Atom::definitionAbsolute;
}
/// like dynamic_cast, if atom is definitionAbsolute
/// returns atom cast to AbsoluteAtom*, else returns NULL
virtual const AbsoluteAtom* absoluteAtom() const {
return this;
}
virtual uint64_t value() const = 0;
protected:
AbsoluteAtom() {}
virtual ~AbsoluteAtom() {}
};
} // namespace lld
#endif // LLD_CORE_ABSOLUTE_ATOM_H_

View File

@ -21,8 +21,10 @@ namespace lld {
class File;
class DefinedAtom;
class UndefinedAtom;
class SharedLibraryAtom;
class AbsoluteAtom;
///
///
/// 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. An Atom can be a DefinedAtom which has
@ -52,12 +54,20 @@ public:
/// definedAtom - like dynamic_cast, if atom is definitionRegular
/// returns atom cast to DefinedAtom*, else returns nullptr;
virtual const DefinedAtom* definedAtom() const { return 0; }
virtual const DefinedAtom* definedAtom() const { return NULL; }
/// undefinedAtom - like dynamic_cast, if atom is definitionUndefined
/// returns atom cast to UndefinedAtom*, else returns NULL;
virtual const UndefinedAtom* undefinedAtom() const { return NULL; }
/// sharedLibraryAtom - like dynamic_cast, if atom is definitionSharedLibrary
/// returns atom cast to SharedLibraryAtom*, else returns nullptr;
virtual const SharedLibraryAtom* sharedLibraryAtom() const { return NULL; }
/// absoluteAtom - like dynamic_cast, if atom is definitionAbsolute
/// returns atom cast to AbsoluteAtom*, else returns nullptr;
virtual const AbsoluteAtom* absoluteAtom() const { return NULL; }
protected:
/// Atom is an abstract base class. Only subclasses can access constructor.
Atom() {}

View File

@ -14,6 +14,8 @@
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/AbsoluteAtom.h"
namespace lld {
@ -27,6 +29,8 @@ public:
virtual ~AtomHandler() {}
virtual void doDefinedAtom(const class DefinedAtom &) = 0;
virtual void doUndefinedAtom(const class UndefinedAtom &) = 0;
virtual void doSharedLibraryAtom(const class SharedLibraryAtom &) = 0;
virtual void doAbsoluteAtom(const class AbsoluteAtom &) = 0;
virtual void doFile(const class File &) = 0;
};

View File

@ -43,6 +43,8 @@ public:
// AtomHandler methods
virtual void doDefinedAtom(const class DefinedAtom&);
virtual void doUndefinedAtom(const class UndefinedAtom&);
virtual void doSharedLibraryAtom(const class SharedLibraryAtom &);
virtual void doAbsoluteAtom(const class AbsoluteAtom &);
virtual void doFile(const File&);
/// @brief do work of merging and resolving and return list

View File

@ -0,0 +1,51 @@
//===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_SHARED_LIBRARY_ATOM_H_
#define LLD_CORE_SHARED_LIBRARY_ATOM_H_
#include "lld/Core/Atom.h"
namespace llvm {
class StringRef;
}
namespace lld {
/// A SharedLibraryAtom has no content.
/// It exists to represent a symbol which will be bound at runtime.
class SharedLibraryAtom : public Atom {
public:
virtual Definition definition() const {
return Atom::definitionSharedLibrary;
}
/// like dynamic_cast, if atom is definitionSharedLibrary
/// returns atom cast to SharedLibraryAtom*, else returns NULL
virtual const SharedLibraryAtom* sharedLibraryAtom() const {
return this;
}
/// Returns shared library name used to load it at runtime.
/// On linux that is the DT_NEEDED name.
/// On Darwin it is the LC_DYLIB_LOAD dylib name.
virtual llvm::StringRef loadName() const = 0;
/// Returns if shared library symbol can be missing at runtime and if
/// so the loader should silently resolve address of symbol to be NULL.
virtual bool canBeNullAtRuntime() const = 0;
protected:
SharedLibraryAtom() {}
virtual ~SharedLibraryAtom() {}
};
} // namespace lld
#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H_

View File

@ -24,6 +24,8 @@ namespace lld {
class Atom;
class DefinedAtom;
class UndefinedAtom;
class SharedLibraryAtom;
class AbsoluteAtom;
class Platform;
/// The SymbolTable class is responsible for coalescing atoms.
@ -41,6 +43,12 @@ public:
/// @brief add atom to symbol table
void add(const UndefinedAtom &);
/// @brief add atom to symbol table
void add(const SharedLibraryAtom &);
/// @brief add atom to symbol table
void add(const AbsoluteAtom &);
/// @brief checks if name is in symbol table and if so atom is not
/// UndefinedAtom
bool isDefined(llvm::StringRef sym);

View File

@ -12,8 +12,6 @@
#include "lld/Core/Atom.h"
#include "llvm/ADT/StringRef.h"
namespace lld {
/// An UndefinedAtom has no content.
@ -30,9 +28,40 @@ public:
return this;
}
/// returns if undefined symbol can be missing at runtime
virtual bool weakImport() const = 0;
/// Whether this undefined symbol needs to be resolved,
/// or whether it can just evaluate to NULL.
/// This concept is often called "weak", but that term
/// is overloaded to mean other things too.
enum CanBeNull {
/// Normal symbols must be resolved at build time
canBeNullNever,
/// This symbol can be missing at runtime and will evalute to NULL.
/// That is, the static linker still must find a definition (usually
/// is some shared library), but at runtime, the dynamic loader
/// will allow the symbol to be missing and resolved to NULL.
///
/// On Darwin this is generated using a function prototype with
/// __attribute__((weak_import)).
/// On linux this is generated using a function prototype with
/// __attribute__((weak)).
canBeNullAtRuntime,
/// This symbol can be missing at build time.
/// That is, the static linker will not error if a definition for
/// this symbol is not found at build time. Instead, the linker
/// will build an executable that lets the dynamic loader find the
/// symbol at runtime.
/// This feature is not supported on Darwin.
/// On linux this is generated using a function prototype with
/// __attribute__((weak)).
canBeNullAtBuildtime
};
virtual CanBeNull canBeNull() const = 0;
protected:
UndefinedAtom() {}
virtual ~UndefinedAtom() {}

View File

@ -78,6 +78,24 @@ public:
virtual void errorWithUndefines(const std::vector<const Atom *>& undefs,
const std::vector<const Atom *>& all) = 0;
/// When core linking finds undefined atoms from different object
/// files that have different canBeNull values, this method is called.
/// The useUndef2 parameter is set to which canBeNull setting the
/// linker should use, and can be changed by this method. Or this
/// method can emit a warning/error about the mismatch.
virtual void undefineCanBeNullMismatch(const UndefinedAtom& undef1,
const UndefinedAtom& undef2,
bool& useUndef2) = 0;
/// When core linking finds shared library atoms from different object
/// files that have different attribute values, this method is called.
/// The useShlib2 parameter is set to which atom attributes the
/// linker should use, and can be changed by this method. Or this
/// method can emit a warning/error about the mismatch.
virtual void sharedLibrarylMismatch(const SharedLibraryAtom& shLib1,
const SharedLibraryAtom& shLib2,
bool& useShlib2) = 0;
/// @brief last chance for platform to tweak atoms
virtual void postResolveTweaks(std::vector<const Atom *>& all) = 0;
};

View File

@ -90,12 +90,14 @@ enum NativeChunkSignatures {
NCS_DefinedAtomsV1 = 1,
NCS_AttributesArrayV1 = 2,
NCS_UndefinedAtomsV1 = 3,
NCS_Strings = 4,
NCS_ReferencesArrayV1 = 5,
NCS_ReferencesArrayV2 = 6,
NCS_TargetsTable = 7,
NCS_AddendsTable = 8,
NCS_Content = 9,
NCS_SharedLibraryAtomsV1 = 4,
NCS_AbsoluteAtomsV1 = 5,
NCS_Strings = 6,
NCS_ReferencesArrayV1 = 7,
NCS_ReferencesArrayV2 = 8,
NCS_TargetsTable = 9,
NCS_AddendsTable = 10,
NCS_Content = 11,
};
//
@ -165,6 +167,27 @@ struct NativeUndefinedAtomIvarsV1 {
//
// The NCS_SharedLibraryAtomsV1 chunk contains an array of these structs
//
struct NativeSharedLibraryAtomIvarsV1 {
uint32_t nameOffset;
uint32_t loadNameOffset;
uint32_t flags;
};
//
// The NCS_AbsoluteAtomsV1 chunk contains an array of these structs
//
struct NativeAbsoluteAtomIvarsV1 {
uint32_t nameOffset;
uint32_t reserved;
uint64_t value;
};
//
// The NCS_ReferencesArrayV1 chunk contains an array of these structs

View File

@ -77,7 +77,7 @@ public:
virtual DefinedAtom::DeadStripKind deadStrip() const {
return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
}
}
virtual DefinedAtom::ContentPermissions permissions() const {
return (DefinedAtom::ContentPermissions)(attributes().permissions);
@ -117,16 +117,64 @@ public:
virtual const File& file() const;
virtual llvm::StringRef name() const;
virtual bool weakImport() const {
return (_ivarData->flags & 0x1);
virtual CanBeNull canBeNull() const {
return (CanBeNull)(_ivarData->flags & 0x3);
}
private:
const NativeFile* _file;
const NativeUndefinedAtomIvarsV1* _ivarData;
};
//
// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
// struct in the NCS_SharedLibraryAtomsV1 chunk.
//
class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
public:
NativeSharedLibraryAtomV1(const NativeFile& f,
const NativeSharedLibraryAtomIvarsV1* ivarData)
: _file(&f), _ivarData(ivarData) { }
virtual const File& file() const;
virtual llvm::StringRef name() const;
virtual llvm::StringRef loadName() const;
virtual bool canBeNullAtRuntime() const {
return (_ivarData->flags & 0x1);
}
private:
const NativeFile* _file;
const NativeSharedLibraryAtomIvarsV1* _ivarData;
};
//
// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
// struct in the NCS_AbsoluteAtomsV1 chunk.
//
class NativeAbsoluteAtomV1 : public AbsoluteAtom {
public:
NativeAbsoluteAtomV1(const NativeFile& f,
const NativeAbsoluteAtomIvarsV1* ivarData)
: _file(&f), _ivarData(ivarData) { }
virtual const File& file() const;
virtual llvm::StringRef name() const;
virtual uint64_t value() const {
return _ivarData->value;
}
private:
const NativeFile* _file;
const NativeAbsoluteAtomIvarsV1* _ivarData;
};
//
// An object of this class is instantied for each NativeReferenceIvarsV1
@ -206,6 +254,12 @@ public:
case NCS_UndefinedAtomsV1:
ec = file->processUndefinedAtomsV1(base, chunk);
break;
case NCS_SharedLibraryAtomsV1:
ec = file->processSharedLibraryAtomsV1(base, chunk);
break;
case NCS_AbsoluteAtomsV1:
ec = file->processAbsoluteAtomsV1(base, chunk);
break;
case NCS_ReferencesArrayV1:
ec = file->processReferencesV1(base, chunk);
break;
@ -247,23 +301,45 @@ public:
// to just delete the memory.
delete _definedAtoms.arrayStart;
delete _undefinedAtoms.arrayStart;
delete _sharedLibraryAtoms.arrayStart;
delete _absoluteAtoms.arrayStart;
delete _references.arrayStart;
delete _targetsTable;
}
// visits each atom in the file
virtual bool forEachAtom(AtomHandler& handler) const {
bool didSomething = false;
for(const uint8_t* p=_definedAtoms.arrayStart; p != _definedAtoms.arrayEnd;
p += _definedAtoms.elementSize) {
const DefinedAtom* atom = reinterpret_cast<const DefinedAtom*>(p);
handler.doDefinedAtom(*atom);
didSomething = true;
}
for(const uint8_t* p=_undefinedAtoms.arrayStart; p != _undefinedAtoms.arrayEnd;
p += _undefinedAtoms.elementSize) {
for(const uint8_t* p=_undefinedAtoms.arrayStart;
p != _undefinedAtoms.arrayEnd;
p += _undefinedAtoms.elementSize) {
const UndefinedAtom* atom = reinterpret_cast<const UndefinedAtom*>(p);
handler.doUndefinedAtom(*atom);
didSomething = true;
}
return (_definedAtoms.arrayStart != _definedAtoms.arrayEnd);
for(const uint8_t* p=_sharedLibraryAtoms.arrayStart;
p != _sharedLibraryAtoms.arrayEnd;
p += _sharedLibraryAtoms.elementSize) {
const SharedLibraryAtom* atom
= reinterpret_cast<const SharedLibraryAtom*>(p);
handler.doSharedLibraryAtom(*atom);
didSomething = true;
}
for(const uint8_t* p=_absoluteAtoms.arrayStart;
p != _absoluteAtoms.arrayEnd;
p += _absoluteAtoms.elementSize) {
const AbsoluteAtom* atom
= reinterpret_cast<const AbsoluteAtom*>(p);
handler.doAbsoluteAtom(*atom);
didSomething = true;
}
return didSomething;
}
// not used
@ -275,6 +351,8 @@ public:
private:
friend class NativeDefinedAtomV1;
friend class NativeUndefinedAtomV1;
friend class NativeSharedLibraryAtomV1;
friend class NativeAbsoluteAtomV1;
friend class NativeReferenceV1;
// instantiate array of DefinedAtoms from v1 ivar data in file
@ -308,12 +386,14 @@ private:
}
// set up pointers to attributes array
llvm::error_code processAttributesV1(const uint8_t* base, const NativeChunk* chunk) {
llvm::error_code processAttributesV1(const uint8_t* base,
const NativeChunk* chunk) {
this->_attributes = base + chunk->fileOffset;
this->_attributesMaxOffset = chunk->fileSize;
return make_error_code(native_reader_error::success);
}
// instantiate array of UndefinedAtoms from v1 ivar data in file
llvm::error_code processUndefinedAtomsV1(const uint8_t* base,
const NativeChunk* chunk) {
const size_t atomSize = sizeof(NativeUndefinedAtomV1);
@ -344,6 +424,70 @@ private:
}
// instantiate array of ShareLibraryAtoms from v1 ivar data in file
llvm::error_code processSharedLibraryAtomsV1(const uint8_t* base,
const NativeChunk* chunk) {
const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
size_t atomsArraySize = chunk->elementCount * atomSize;
uint8_t* atomsStart = reinterpret_cast<uint8_t*>
(operator new(atomsArraySize, std::nothrow));
if (atomsStart == NULL )
return make_error_code(native_reader_error::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
return make_error_code(native_reader_error::file_malformed);
uint8_t* atomsEnd = atomsStart + atomsArraySize;
const NativeSharedLibraryAtomIvarsV1* ivarData =
reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
(base + chunk->fileOffset);
for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
NativeSharedLibraryAtomV1* atomAllocSpace =
reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
++ivarData;
}
this->_sharedLibraryAtoms.arrayStart = atomsStart;
this->_sharedLibraryAtoms.arrayEnd = atomsEnd;
this->_sharedLibraryAtoms.elementSize = atomSize;
this->_sharedLibraryAtoms.elementCount = chunk->elementCount;
return make_error_code(native_reader_error::success);
}
// instantiate array of AbsoluteAtoms from v1 ivar data in file
llvm::error_code processAbsoluteAtomsV1(const uint8_t* base,
const NativeChunk* chunk) {
const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
size_t atomsArraySize = chunk->elementCount * atomSize;
uint8_t* atomsStart = reinterpret_cast<uint8_t*>
(operator new(atomsArraySize, std::nothrow));
if (atomsStart == NULL )
return make_error_code(native_reader_error::memory_error);
const size_t ivarElementSize = chunk->fileSize
/ chunk->elementCount;
if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
return make_error_code(native_reader_error::file_malformed);
uint8_t* atomsEnd = atomsStart + atomsArraySize;
const NativeAbsoluteAtomIvarsV1* ivarData =
reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
(base + chunk->fileOffset);
for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
NativeAbsoluteAtomV1* atomAllocSpace =
reinterpret_cast<NativeAbsoluteAtomV1*>(s);
new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
++ivarData;
}
this->_absoluteAtoms.arrayStart = atomsStart;
this->_absoluteAtoms.arrayEnd = atomsEnd;
this->_absoluteAtoms.elementSize = atomSize;
this->_absoluteAtoms.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) {
@ -398,7 +542,24 @@ private:
this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
continue;
}
return make_error_code(native_reader_error::file_malformed);
const uint32_t slIndex = index - _definedAtoms.elementCount
- _undefinedAtoms.elementCount;
if ( slIndex < _sharedLibraryAtoms.elementCount ) {
const uint8_t* p = _sharedLibraryAtoms.arrayStart
+ slIndex * _sharedLibraryAtoms.elementSize;
this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
continue;
}
const uint32_t abIndex = index - _definedAtoms.elementCount
- _undefinedAtoms.elementCount
- _sharedLibraryAtoms.elementCount;
if ( abIndex < _absoluteAtoms.elementCount ) {
const uint8_t* p = _absoluteAtoms.arrayStart
+ slIndex * _absoluteAtoms.elementSize;
this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
continue;
}
return make_error_code(native_reader_error::file_malformed);
}
return make_error_code(native_reader_error::success);
}
@ -491,7 +652,8 @@ private:
_contentStart(NULL),
_contentEnd(NULL)
{
_header = reinterpret_cast<const NativeFileHeader*>(_buffer->getBufferStart());
_header = reinterpret_cast<const NativeFileHeader*>
(_buffer->getBufferStart());
}
struct IvarArray {
@ -507,6 +669,8 @@ private:
const NativeFileHeader* _header;
IvarArray _definedAtoms;
IvarArray _undefinedAtoms;
IvarArray _sharedLibraryAtoms;
IvarArray _absoluteAtoms;
const uint8_t* _attributes;
uint32_t _attributesMaxOffset;
IvarArray _references;
@ -567,6 +731,31 @@ inline llvm::StringRef NativeUndefinedAtomV1::name() const {
}
inline const class File& NativeSharedLibraryAtomV1::file() const {
return *_file;
}
inline llvm::StringRef NativeSharedLibraryAtomV1::name() const {
return _file->string(_ivarData->nameOffset);
}
inline llvm::StringRef NativeSharedLibraryAtomV1::loadName() const {
return _file->string(_ivarData->loadNameOffset);
}
inline const class File& NativeAbsoluteAtomV1::file() const {
return *_file;
}
inline llvm::StringRef NativeAbsoluteAtomV1::name() const {
return _file->string(_ivarData->nameOffset);
}
inline const Atom* NativeReferenceV1::target() const {
return _file->target(_ivarData->targetIndex);
}

View File

@ -61,7 +61,21 @@ public:
out.write((char*)&_undefinedAtomIvars[0],
_undefinedAtomIvars.size()*sizeof(NativeUndefinedAtomIvarsV1));
}
if ( !_sharedLibraryAtomIvars.empty() ) {
assert( out.tell() == findChunk(NCS_SharedLibraryAtomsV1).fileOffset );
out.write((char*)&_sharedLibraryAtomIvars[0],
_sharedLibraryAtomIvars.size()
* sizeof(NativeSharedLibraryAtomIvarsV1));
}
if ( !_absoluteAtomIvars.empty() ) {
assert( out.tell() == findChunk(NCS_AbsoluteAtomsV1).fileOffset );
out.write((char*)&_absoluteAtomIvars[0],
_absoluteAtomIvars.size()
* sizeof(NativeAbsoluteAtomIvarsV1));
}
if (!_stringPool.empty()) {
assert( out.tell() == findChunk(NCS_Strings).fileOffset );
out.write(&_stringPool[0], _stringPool.size());
@ -110,23 +124,55 @@ private:
_undefinedAtomIndex[&atom] = _undefinedAtomIvars.size();
NativeUndefinedAtomIvarsV1 ivar;
ivar.nameOffset = getNameOffset(atom);
ivar.flags = (atom.weakImport() ? 1 : 0);
ivar.flags = (atom.canBeNull() & 0x03);
_undefinedAtomIvars.push_back(ivar);
}
// visitor routine called by forEachAtom()
virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
_sharedLibraryAtomIndex[&atom] = _sharedLibraryAtomIvars.size();
NativeSharedLibraryAtomIvarsV1 ivar;
ivar.nameOffset = getNameOffset(atom);
ivar.loadNameOffset = getSharedLibraryNameOffset(atom.loadName());
ivar.flags = atom.canBeNullAtRuntime();
_sharedLibraryAtomIvars.push_back(ivar);
}
// visitor routine called by forEachAtom()
virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
_absoluteAtomIndex[&atom] = _absoluteAtomIvars.size();
NativeAbsoluteAtomIvarsV1 ivar;
ivar.nameOffset = getNameOffset(atom);
ivar.reserved = 0;
ivar.value = atom.value();
_absoluteAtomIvars.push_back(ivar);
}
// visitor routine called by forEachAtom()
virtual void doFile(const File &) {
}
// fill out native file header and chunk directory
void makeHeader() {
const bool hasDefines = !_definedAtomIvars.empty();
const bool hasUndefines = !_undefinedAtomIvars.empty();
const bool hasSharedLibraries = !_sharedLibraryAtomIvars.empty();
const bool hasAbsolutes = !_absoluteAtomIvars.empty();
const bool hasReferences = !_references.empty();
const bool hasTargetsTable = !_targetsTableIndex.empty();
const bool hasAddendTable = !_addendsTableIndex.empty();
int chunkCount = 5;
const bool hasContent = !_contentPool.empty();
int chunkCount = 1; // always have string pool chunk
if ( hasDefines ) chunkCount += 2;
if ( hasUndefines ) ++chunkCount;
if ( hasSharedLibraries ) ++chunkCount;
if ( hasAbsolutes ) ++chunkCount;
if ( hasReferences ) ++chunkCount;
if ( hasTargetsTable ) ++chunkCount;
if ( hasAddendTable ) ++chunkCount;
if ( hasContent ) ++chunkCount;
_headerBufferSize = sizeof(NativeFileHeader)
+ chunkCount*sizeof(NativeChunk);
_headerBuffer = reinterpret_cast<NativeFileHeader*>
@ -140,23 +186,25 @@ private:
_headerBuffer->fileSize = 0;
_headerBuffer->chunkCount = chunkCount;
// create chunk for atom ivar array
// create chunk for defined atom ivar array
int nextIndex = 0;
NativeChunk& chd = chunks[nextIndex++];
chd.signature = NCS_DefinedAtomsV1;
chd.fileOffset = _headerBufferSize;
chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
chd.elementCount = _definedAtomIvars.size();
uint32_t nextFileOffset = chd.fileOffset + chd.fileSize;
uint32_t nextFileOffset = _headerBufferSize;
if ( hasDefines ) {
NativeChunk& chd = chunks[nextIndex++];
chd.signature = NCS_DefinedAtomsV1;
chd.fileOffset = nextFileOffset;
chd.fileSize = _definedAtomIvars.size()*sizeof(NativeDefinedAtomIvarsV1);
chd.elementCount = _definedAtomIvars.size();
nextFileOffset = chd.fileOffset + chd.fileSize;
// create chunk for attributes
NativeChunk& cha = chunks[nextIndex++];
cha.signature = NCS_AttributesArrayV1;
cha.fileOffset = nextFileOffset;
cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
cha.elementCount = _attributes.size();
nextFileOffset = cha.fileOffset + cha.fileSize;
// create chunk for attributes
NativeChunk& cha = chunks[nextIndex++];
cha.signature = NCS_AttributesArrayV1;
cha.fileOffset = nextFileOffset;
cha.fileSize = _attributes.size()*sizeof(NativeAtomAttributesV1);
cha.elementCount = _attributes.size();
nextFileOffset = cha.fileOffset + cha.fileSize;
}
// create chunk for undefined atom array
if ( hasUndefines ) {
@ -169,6 +217,28 @@ private:
nextFileOffset = chu.fileOffset + chu.fileSize;
}
// create chunk for shared library atom array
if ( hasSharedLibraries ) {
NativeChunk& chsl = chunks[nextIndex++];
chsl.signature = NCS_SharedLibraryAtomsV1;
chsl.fileOffset = nextFileOffset;
chsl.fileSize = _sharedLibraryAtomIvars.size() *
sizeof(NativeSharedLibraryAtomIvarsV1);
chsl.elementCount = _sharedLibraryAtomIvars.size();
nextFileOffset = chsl.fileOffset + chsl.fileSize;
}
// create chunk for shared library atom array
if ( hasAbsolutes ) {
NativeChunk& chsl = chunks[nextIndex++];
chsl.signature = NCS_AbsoluteAtomsV1;
chsl.fileOffset = nextFileOffset;
chsl.fileSize = _absoluteAtomIvars.size() *
sizeof(NativeAbsoluteAtomIvarsV1);
chsl.elementCount = _absoluteAtomIvars.size();
nextFileOffset = chsl.fileOffset + chsl.fileSize;
}
// create chunk for symbol strings
// pad end of string pool to 4-bytes
while ( (_stringPool.size() % 4) != 0 )
@ -181,13 +251,15 @@ private:
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;
if ( hasReferences ) {
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++];
@ -209,13 +281,15 @@ private:
}
// create chunk for content
NativeChunk& chc = chunks[nextIndex++];
chc.signature = NCS_Content;
chc.fileOffset = nextFileOffset;
chc.fileSize = _contentPool.size();
chc.elementCount = _contentPool.size();
nextFileOffset = chc.fileOffset + chc.fileSize;
if ( hasContent ) {
NativeChunk& chc = chunks[nextIndex++];
chc.signature = NCS_Content;
chc.fileOffset = nextFileOffset;
chc.fileSize = _contentPool.size();
chc.elementCount = _contentPool.size();
nextFileOffset = chc.fileOffset + chc.fileSize;
}
_headerBuffer->fileSize = nextFileOffset;
}
@ -237,7 +311,23 @@ private:
return this->getNameOffset(atom.name());
}
// append atom name to string pool and return offset
// check if name is already in pool or append and return offset
uint32_t getSharedLibraryNameOffset(llvm::StringRef name) {
assert( ! name.empty() );
// look to see if this library name was used by another atom
for(NameToOffsetVector::iterator it = _sharedLibraryNames.begin();
it != _sharedLibraryNames.end(); ++it) {
if ( name.equals(it->first) )
return it->second;
}
// first use of this library name
uint32_t result = this->getNameOffset(name);
_sharedLibraryNames.push_back(
std::make_pair<llvm::StringRef, uint32_t>(name, result));
return result;
}
// append atom name to string pool and return offset
uint32_t getNameOffset(llvm::StringRef name) {
if ( name.empty() )
return 0;
@ -356,8 +446,26 @@ private:
}
else {
pos = _undefinedAtomIndex.find(atom);
assert(pos != _undefinedAtomIndex.end());
atomIndex = pos->second + _definedAtomIvars.size();
if ( pos != _undefinedAtomIndex.end() ) {
atomIndex = pos->second + _definedAtomIvars.size();
}
else {
pos = _sharedLibraryAtomIndex.find(atom);
if ( pos != _sharedLibraryAtomIndex.end() ) {
assert(pos != _sharedLibraryAtomIndex.end());
atomIndex = pos->second
+ _definedAtomIvars.size()
+ _undefinedAtomIndex.size();
}
else {
pos = _absoluteAtomIndex.find(atom);
assert(pos != _absoluteAtomIndex.end());
atomIndex = pos->second
+ _definedAtomIvars.size()
+ _undefinedAtomIndex.size()
+ _sharedLibraryAtomIndex.size();
}
}
}
targetIndexes[targetIndex] = atomIndex;
}
@ -405,12 +513,17 @@ private:
std::vector<NativeDefinedAtomIvarsV1> _definedAtomIvars;
std::vector<NativeAtomAttributesV1> _attributes;
std::vector<NativeUndefinedAtomIvarsV1> _undefinedAtomIvars;
std::vector<NativeSharedLibraryAtomIvarsV1> _sharedLibraryAtomIvars;
std::vector<NativeAbsoluteAtomIvarsV1> _absoluteAtomIvars;
std::vector<NativeReferenceIvarsV1> _references;
TargetToIndex _targetsTableIndex;
TargetToIndex _definedAtomIndex;
TargetToIndex _undefinedAtomIndex;
TargetToIndex _sharedLibraryAtomIndex;
TargetToIndex _absoluteAtomIndex;
AddendToIndex _addendsTableIndex;
NameToOffsetVector _sectionNames;
NameToOffsetVector _sharedLibraryNames;
};

View File

@ -134,6 +134,24 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) {
}
}
void Resolver::doSharedLibraryAtom(const SharedLibraryAtom& atom) {
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
_symbolTable.add(atom);
}
void Resolver::doAbsoluteAtom(const AbsoluteAtom& atom) {
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
_symbolTable.add(atom);
}
// utility to add a vector of atoms
void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) {
for (std::vector<const DefinedAtom *>::const_iterator it = newAtoms.begin();

View File

@ -11,10 +11,11 @@
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/InputFiles.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Platform/Platform.h"
#include "llvm/Support/ErrorHandling.h"
@ -36,6 +37,14 @@ void SymbolTable::add(const UndefinedAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const SharedLibraryAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const AbsoluteAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const DefinedAtom &atom) {
assert(atom.scope() != DefinedAtom::scopeTranslationUnit);
if ( !atom.name().empty() ) {
@ -49,7 +58,9 @@ void SymbolTable::add(const DefinedAtom &atom) {
enum NameCollisionResolution {
NCR_First,
NCR_Second,
NCR_Dup,
NCR_DupDef,
NCR_DupUndef,
NCR_DupShLib,
NCR_Error
};
@ -57,7 +68,7 @@ static NameCollisionResolution cases[4][4] = {
//regular absolute undef sharedLib
{
// first is regular
NCR_Dup, NCR_Error, NCR_First, NCR_First
NCR_DupDef, NCR_Error, NCR_First, NCR_First
},
{
// first is absolute
@ -65,11 +76,11 @@ static NameCollisionResolution cases[4][4] = {
},
{
// first is undef
NCR_Second, NCR_Second, NCR_First, NCR_Second
NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
},
{
// first is sharedLib
NCR_Second, NCR_Second, NCR_First, NCR_First
NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
}
};
@ -129,7 +140,7 @@ void SymbolTable::addByName(const Atom & newAtom) {
case NCR_Second:
useNew = true;
break;
case NCR_Dup:
case NCR_DupDef:
assert(existing->definition() == Atom::definitionRegular);
assert(newAtom.definition() == Atom::definitionRegular);
switch ( mergeSelect(((DefinedAtom*)existing)->merge(),
@ -148,6 +159,39 @@ void SymbolTable::addByName(const Atom & newAtom) {
break;
}
break;
case NCR_DupUndef: {
const UndefinedAtom* existingUndef = existing->undefinedAtom();
const UndefinedAtom* newUndef = newAtom.undefinedAtom();
assert(existingUndef != NULL);
assert(newUndef != NULL);
if ( existingUndef->canBeNull() == newUndef->canBeNull() ) {
useNew = false;
}
else {
useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
// give platform a change to override which to use
_platform.undefineCanBeNullMismatch(*existingUndef,
*newUndef, useNew);
}
}
break;
case NCR_DupShLib: {
const SharedLibraryAtom* existingShLib = existing->sharedLibraryAtom();
const SharedLibraryAtom* newShLib = newAtom.sharedLibraryAtom();
assert(existingShLib != NULL);
assert(newShLib != NULL);
if ( (existingShLib->canBeNullAtRuntime()
== newShLib->canBeNullAtRuntime()) &&
existingShLib->loadName().equals(newShLib->loadName()) ) {
useNew = false;
}
else {
useNew = false; // use existing shared library by default
// give platform a change to override which to use
_platform.sharedLibrarylMismatch(*existingShLib, *newShLib, useNew);
}
}
break;
default:
llvm::report_fatal_error("SymbolTable::addByName(): unhandled switch clause");
}

View File

@ -30,10 +30,12 @@ const char* const KeyValues::isThumbKeyword = "is-thumb";
const char* const KeyValues::isAliasKeyword = "is-alias";
const char* const KeyValues::sectionNameKeyword = "section-name";
const char* const KeyValues::contentKeyword = "content";
const char* const KeyValues::loadNameKeyword = "load-name";
const char* const KeyValues::sizeKeyword = "size";
const char* const KeyValues::valueKeyword = "value";
const char* const KeyValues::fixupsKeyword = "fixups";
const char* const KeyValues::permissionsKeyword = "permissions";
const char* const KeyValues::weakImportKeyword = "weak-import";
const char* const KeyValues::canBeNullKeyword = "can-be-null";
const char* const KeyValues::fixupsKindKeyword = "kind";
const char* const KeyValues::fixupsOffsetKeyword = "offset";
const char* const KeyValues::fixupsTargetKeyword = "target";
@ -51,7 +53,7 @@ const DefinedAtom::Merge KeyValues::mergeDefault = DefinedAtom::mer
const DefinedAtom::ContentPermissions KeyValues::permissionsDefault = DefinedAtom::permR__;
const bool KeyValues::isThumbDefault = false;
const bool KeyValues::isAliasDefault = false;
const bool KeyValues::weakImportDefault = false;
const UndefinedAtom::CanBeNull KeyValues::canBeNullDefault = UndefinedAtom::canBeNullNever;
@ -389,17 +391,34 @@ const char* KeyValues::isAlias(bool b) {
bool KeyValues::weakImport(const char* s)
struct CanBeNullMapping {
const char* string;
UndefinedAtom::CanBeNull value;
};
static const CanBeNullMapping cbnMappings[] = {
{ "never", UndefinedAtom::canBeNullNever },
{ "at-runtime", UndefinedAtom::canBeNullAtRuntime },
{ "at-buildtime", UndefinedAtom::canBeNullAtBuildtime },
{ NULL, UndefinedAtom::canBeNullNever }
};
UndefinedAtom::CanBeNull KeyValues::canBeNull(const char* s)
{
if ( strcmp(s, "true") == 0 )
return true;
else if ( strcmp(s, "false") == 0 )
return false;
llvm::report_fatal_error("bad weak-import value");
for (const CanBeNullMapping* p = cbnMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
return p->value;
}
llvm::report_fatal_error("bad can-be-null value");
}
const char* KeyValues::weakImport(bool b) {
return b ? "true" : "false";
const char* KeyValues::canBeNull(UndefinedAtom::CanBeNull c) {
for (const CanBeNullMapping* p = cbnMappings; p->string != NULL; ++p) {
if ( p->value == c )
return p->string;
}
llvm::report_fatal_error("bad can-be-null value");
}

View File

@ -12,6 +12,7 @@
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
namespace lld {
@ -24,6 +25,8 @@ public:
static const char* const sectionNameKeyword;
static const char* const contentKeyword;
static const char* const sizeKeyword;
static const char* const loadNameKeyword;
static const char* const valueKeyword;
static const char* const fixupsKeyword;
static const char* const definitionKeyword;
@ -76,10 +79,10 @@ public:
static bool isAlias(const char*);
static const char* isAlias(bool);
static const char* const weakImportKeyword;
static const bool weakImportDefault;
static bool weakImport(const char*);
static const char* weakImport(bool);
static const char* const canBeNullKeyword;
static const UndefinedAtom::CanBeNull canBeNullDefault;
static UndefinedAtom::CanBeNull canBeNull(const char*);
static const char* canBeNull(UndefinedAtom::CanBeNull);
static const char* const fixupsKindKeyword;

View File

@ -13,6 +13,9 @@
#include "lld/Core/YamlReader.h"
#include "lld/Core/Atom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/Error.h"
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
@ -200,9 +203,7 @@ void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
}
break;
case inValue:
if (isalnum(c) || (c == '-') || (c == '_')) {
*p++ = c;
} else if (c == '\n') {
if (c == '\n') {
*p = '\0';
entries.push_back(new Entry(key, value, NULL, depth,
nextKeyIsStartOfDocument,
@ -212,6 +213,9 @@ void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
state = inDocument;
depth = 0;
}
else {
*p++ = c;
}
break;
case inValueSequence:
if (c == ']') {
@ -300,6 +304,8 @@ public:
void bindTargetReferences();
void addDefinedAtom(YAMLDefinedAtom* atom, const char* refName);
void addUndefinedAtom(UndefinedAtom* atom);
void addSharedLibraryAtom(SharedLibraryAtom* atom);
void addAbsoluteAtom(AbsoluteAtom* atom);
Atom* findAtom(const char* name);
struct NameAtomPair {
@ -310,6 +316,8 @@ public:
std::vector<YAMLDefinedAtom*> _definedAtoms;
std::vector<UndefinedAtom*> _undefinedAtoms;
std::vector<SharedLibraryAtom*> _sharedLibraryAtoms;
std::vector<AbsoluteAtom*> _absoluteAtoms;
std::vector<YAMLReference> _references;
std::vector<NameAtomPair> _nameToAtomMapping;
unsigned int _lastRefIndex;
@ -465,8 +473,9 @@ private:
class YAMLUndefinedAtom : public UndefinedAtom {
public:
YAMLUndefinedAtom(YAMLFile& f, int32_t ord, const char* nm, bool wi)
: _file(f), _name(nm), _ordinal(ord), _weakImport(wi) { }
YAMLUndefinedAtom(YAMLFile& f, int32_t ord, const char* nm,
UndefinedAtom::CanBeNull cbn)
: _file(f), _name(nm), _ordinal(ord), _canBeNull(cbn) { }
virtual const class File& file() const {
return _file;
@ -476,18 +485,81 @@ public:
return _name;
}
virtual bool weakImport() const {
return _weakImport;
virtual CanBeNull canBeNull() const {
return _canBeNull;
}
private:
YAMLFile& _file;
const char * _name;
uint32_t _ordinal;
bool _weakImport;
UndefinedAtom::CanBeNull _canBeNull;
};
class YAMLSharedLibraryAtom : public SharedLibraryAtom {
public:
YAMLSharedLibraryAtom(YAMLFile& f, int32_t ord, const char* nm,
const char* ldnm, bool cbn)
: _file(f), _name(nm), _ordinal(ord),
_loadName(ldnm), _canBeNull(cbn) { }
virtual const class File& file() const {
return _file;
}
virtual llvm::StringRef name() const {
return _name;
}
virtual llvm::StringRef loadName() const {
return _loadName;
}
virtual bool canBeNullAtRuntime() const {
return _canBeNull;
}
private:
YAMLFile& _file;
const char * _name;
uint32_t _ordinal;
const char * _loadName;
bool _canBeNull;
};
class YAMLAbsoluteAtom : public AbsoluteAtom {
public:
YAMLAbsoluteAtom(YAMLFile& f, int32_t ord, const char* nm, uint64_t v)
: _file(f), _name(nm), _ordinal(ord), _value(v) { }
virtual const class File& file() const {
return _file;
}
virtual llvm::StringRef name() const {
return _name;
}
virtual uint64_t value() const {
return _value;
}
private:
YAMLFile& _file;
const char * _name;
uint32_t _ordinal;
uint64_t _value;
};
bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
handler.doFile(*this);
for (std::vector<YAMLDefinedAtom *>::const_iterator it = _definedAtoms.begin();
@ -498,6 +570,17 @@ bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
it != _undefinedAtoms.end(); ++it) {
handler.doUndefinedAtom(**it);
}
for (std::vector<SharedLibraryAtom *>::const_iterator
it = _sharedLibraryAtoms.begin();
it != _sharedLibraryAtoms.end(); ++it) {
handler.doSharedLibraryAtom(**it);
}
for (std::vector<AbsoluteAtom *>::const_iterator
it = _absoluteAtoms.begin();
it != _absoluteAtoms.end(); ++it) {
handler.doAbsoluteAtom(**it);
}
return true;
}
@ -534,6 +617,16 @@ void YAMLFile::addUndefinedAtom(UndefinedAtom* atom) {
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
}
void YAMLFile::addSharedLibraryAtom(SharedLibraryAtom* atom) {
_sharedLibraryAtoms.push_back(atom);
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
}
void YAMLFile::addAbsoluteAtom(AbsoluteAtom* atom) {
_absoluteAtoms.push_back(atom);
_nameToAtomMapping.push_back(NameAtomPair(atom->name().data(), atom));
}
class YAMLAtomState {
public:
@ -544,9 +637,7 @@ public:
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&);
@ -554,7 +645,9 @@ public:
const char * _name;
const char * _refName;
const char * _sectionName;
const char* _loadName;
unsigned long long _size;
uint64_t _value;
uint32_t _ordinal;
std::vector<uint8_t>* _content;
DefinedAtom::Alignment _alignment;
@ -568,7 +661,7 @@ public:
DefinedAtom::ContentPermissions _permissions;
bool _isThumb;
bool _isAlias;
bool _weakImport;
UndefinedAtom::CanBeNull _canBeNull;
YAMLReference _ref;
};
@ -577,7 +670,9 @@ YAMLAtomState::YAMLAtomState()
: _name(NULL)
, _refName(NULL)
, _sectionName(NULL)
, _loadName(NULL)
, _size(0)
, _value(0)
, _ordinal(0)
, _content(NULL)
, _alignment(0, 0)
@ -591,7 +686,7 @@ YAMLAtomState::YAMLAtomState()
, _permissions(KeyValues::permissionsDefault)
, _isThumb(KeyValues::isThumbDefault)
, _isAlias(KeyValues::isAliasDefault)
, _weakImport(false)
, _canBeNull(KeyValues::canBeNullDefault)
{
}
@ -606,16 +701,30 @@ void YAMLAtomState::makeAtom(YAMLFile& f) {
++_ordinal;
}
else if ( _definition == Atom::definitionUndefined ) {
UndefinedAtom *a = new YAMLUndefinedAtom(f, _ordinal, _name, _weakImport);
UndefinedAtom *a = new YAMLUndefinedAtom(f, _ordinal, _name, _canBeNull);
f.addUndefinedAtom(a);
++_ordinal;
}
else if ( _definition == Atom::definitionSharedLibrary ) {
bool nullable = (_canBeNull == UndefinedAtom::canBeNullAtRuntime);
SharedLibraryAtom *a = new YAMLSharedLibraryAtom(f, _ordinal, _name,
_loadName, nullable);
f.addSharedLibraryAtom(a);
++_ordinal;
}
else if ( _definition == Atom::definitionAbsolute ) {
AbsoluteAtom *a = new YAMLAbsoluteAtom(f, _ordinal, _name, _value);
f.addAbsoluteAtom(a);
++_ordinal;
}
// reset state for next atom
_name = NULL;
_refName = NULL;
_sectionName = NULL;
_loadName = NULL;
_size = 0;
_value = 0;
_ordinal = 0;
_content = NULL;
_alignment.powerOf2= 0;
@ -630,7 +739,7 @@ void YAMLAtomState::makeAtom(YAMLFile& f) {
_permissions = KeyValues::permissionsDefault;
_isThumb = KeyValues::isThumbDefault;
_isAlias = KeyValues::isAliasDefault;
_weakImport = KeyValues::weakImportDefault;
_canBeNull = KeyValues::canBeNullDefault;
_ref._target = NULL;
_ref._targetName = NULL;
_ref._addend = 0;
@ -666,24 +775,10 @@ void YAMLAtomState::setFixupKind(const char *s) {
}
}
void YAMLAtomState::setFixupOffset(const char *s) {
if ((s[0] == '0') && (s[1] == 'x'))
llvm::StringRef(s).getAsInteger(16, _ref._offsetInAtom);
else
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);
@ -805,8 +900,12 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
atomState._isAlias = KeyValues::isAlias(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::weakImportKeyword) == 0) {
atomState._weakImport = KeyValues::weakImport(entry->value);
else if (strcmp(entry->key, KeyValues::canBeNullKeyword) == 0) {
atomState._canBeNull = KeyValues::canBeNull(entry->value);
if ( atomState._definition == Atom::definitionSharedLibrary ) {
if ( atomState._canBeNull == UndefinedAtom::canBeNullAtBuildtime )
return make_error_code(yaml_reader_error::illegal_value);
}
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::sectionNameKeyword) == 0) {
@ -829,7 +928,14 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
}
else if (strcmp(entry->key, KeyValues::fixupsKeyword) == 0) {
inFixups = true;
}
else if (strcmp(entry->key, KeyValues::loadNameKeyword) == 0) {
atomState._loadName = entry->value;
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::valueKeyword) == 0) {
llvm::StringRef(entry->value).getAsInteger(0, atomState._value);
haveAtom = true;
}
else {
return make_error_code(yaml_reader_error::unknown_keyword);
@ -847,7 +953,8 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
haveFixup = true;
}
else if (strcmp(entry->key, KeyValues::fixupsOffsetKeyword) == 0) {
atomState.setFixupOffset(entry->value);
llvm::StringRef(entry->value).getAsInteger(0,
atomState._ref._offsetInAtom);
haveFixup = true;
}
else if (strcmp(entry->key, KeyValues::fixupsTargetKeyword) == 0) {
@ -855,7 +962,8 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
haveFixup = true;
}
else if (strcmp(entry->key, KeyValues::fixupsAddendKeyword) == 0) {
atomState.setFixupAddend(entry->value);
llvm::StringRef(entry->value).getAsInteger(0,
atomState._ref._addend);
haveFixup = true;
}
}
@ -865,9 +973,10 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
if (haveAtom) {
atomState.makeAtom(*file);
}
file->bindTargetReferences();
result.push_back(file);
if ( file != NULL ) {
file->bindTargetReferences();
result.push_back(file);
}
return make_error_code(yaml_reader_error::success);
}

View File

@ -71,6 +71,14 @@ public:
buildDuplicateNameMap(atom);
}
virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
buildDuplicateNameMap(atom);
}
virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
buildDuplicateNameMap(atom);
}
void buildDuplicateNameMap(const Atom& atom) {
assert(!atom.name().empty());
NameToAtom::iterator pos = _nameMap.find(atom.name());
@ -132,10 +140,14 @@ public:
virtual void doFile(const class File &) { _firstAtom = true; }
virtual void doDefinedAtom(const class DefinedAtom &atom) {
// add blank line between atoms for readability
if ( !_firstAtom )
if ( _firstAtom ) {
_out << "atoms:\n";
_firstAtom = false;
}
else {
// add blank line between atoms for readability
_out << "\n";
_firstAtom = false;
}
bool hasDash = false;
if ( !atom.name().empty() ) {
@ -313,35 +325,115 @@ public:
virtual void doUndefinedAtom(const class UndefinedAtom &atom) {
// add blank line between atoms for readability
if ( !_firstAtom )
_out << "\n";
if ( _firstAtom ) {
_out << "atoms:\n";
_firstAtom = false;
}
else {
// add blank line between atoms for readability
_out << "\n";
}
_out << " - "
<< KeyValues::nameKeyword
<< ":"
<< spacePadding(KeyValues::nameKeyword)
<< atom.name()
<< "\n";
_out << " - "
<< KeyValues::nameKeyword
<< ":"
<< spacePadding(KeyValues::nameKeyword)
<< atom.name()
<< "\n";
_out << " "
<< KeyValues::definitionKeyword
<< ":"
<< spacePadding(KeyValues::definitionKeyword)
<< KeyValues::definition(atom.definition())
<< "\n";
_out << " "
<< KeyValues::definitionKeyword
<< ":"
<< spacePadding(KeyValues::definitionKeyword)
<< KeyValues::definition(atom.definition())
<< "\n";
if ( atom.weakImport() != KeyValues::weakImportDefault ) {
if ( atom.canBeNull() != KeyValues::canBeNullDefault ) {
_out << " "
<< KeyValues::weakImportKeyword
<< KeyValues::canBeNullKeyword
<< ":"
<< spacePadding(KeyValues::weakImportKeyword)
<< KeyValues::weakImport(atom.weakImport())
<< spacePadding(KeyValues::canBeNullKeyword)
<< KeyValues::canBeNull(atom.canBeNull())
<< "\n";
}
}
virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
if ( _firstAtom ) {
_out << "atoms:\n";
_firstAtom = false;
}
else {
// add blank line between atoms for readability
_out << "\n";
}
_out << " - "
<< KeyValues::nameKeyword
<< ":"
<< spacePadding(KeyValues::nameKeyword)
<< atom.name()
<< "\n";
_out << " "
<< KeyValues::definitionKeyword
<< ":"
<< spacePadding(KeyValues::definitionKeyword)
<< KeyValues::definition(atom.definition())
<< "\n";
if ( !atom.loadName().empty() ) {
_out << " "
<< KeyValues::loadNameKeyword
<< ":"
<< spacePadding(KeyValues::loadNameKeyword)
<< atom.loadName()
<< "\n";
}
if ( atom.canBeNullAtRuntime() ) {
_out << " "
<< KeyValues::canBeNullKeyword
<< ":"
<< spacePadding(KeyValues::canBeNullKeyword)
<< KeyValues::canBeNull(UndefinedAtom::canBeNullAtRuntime)
<< "\n";
}
}
virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
if ( _firstAtom ) {
_out << "atoms:\n";
_firstAtom = false;
}
else {
// add blank line between atoms for readability
_out << "\n";
}
_out << " - "
<< KeyValues::nameKeyword
<< ":"
<< spacePadding(KeyValues::nameKeyword)
<< atom.name()
<< "\n";
_out << " "
<< KeyValues::definitionKeyword
<< ":"
<< spacePadding(KeyValues::definitionKeyword)
<< KeyValues::definition(atom.definition())
<< "\n";
_out << " "
<< KeyValues::valueKeyword
<< ":"
<< spacePadding(KeyValues::valueKeyword)
<< "0x";
_out.write_hex(atom.value());
_out << "\n";
}
private:
// return a string of the correct number of spaces to align value
@ -380,7 +472,6 @@ void writeObjectText(const File &file, llvm::raw_ostream &out) {
// Write out all atoms
AtomWriter h(rnb, out);
out << "---\n";
out << "atoms:\n";
file.forEachAtom(h);
out << "...\n";
}

View File

@ -0,0 +1,25 @@
# RUN: lld-core %s | FileCheck %s
#
# Test that absolute symbols are parsed and preserved
#
---
atoms:
- name: putchar
definition: absolute
value: 0xFFFF0040
- name: reset
definition: absolute
value: 0xFFFF0080
...
# CHECK: name: putchar
# CHECK: definition: absolute
# CHECK: value: 0xffff0040
# CHECK: name: reset
# CHECK: definition: absolute
# CHECK: value: 0xffff0080
# CHECK: ...

11
lld/test/empty.objtxt Normal file
View File

@ -0,0 +1,11 @@
# RUN: lld-core %s | FileCheck %s
#
# Test that an empty file is handled properly
#
---
...
# CHECK: ---
# CHECK: ...

View File

@ -0,0 +1,34 @@
# RUN: lld-core %s | FileCheck %s
#
# Test that shared-library symbols are parsed and preserved
#
---
atoms:
- name: malloc
definition: shared-library
load-name: libc.so
- name: free
definition: shared-library
load-name: libc.so
- name: fast_malloc
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
...
# CHECK: name: malloc
# CHECK: definition: shared-library
# CHECK: load-name: libc.so
# CHECK: name: free
# CHECK: definition: shared-library
# CHECK: load-name: libc.so
# CHECK: name: fast_malloc
# CHECK: definition: shared-library
# CHECK: load-name: libc.so
# CHECK: can-be-null: at-runtime
# CHECK: ...

View File

@ -0,0 +1,110 @@
# RUN: lld-core %s | FileCheck %s
#
# Test that shared library symbols preserve their attributes and merge properly
#
---
atoms:
- name: foo1
definition: shared-library
load-name: libc.so
- name: foo2
definition: shared-library
load-name: libc.so
- name: bar1
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
- name: bar2
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
- name: mismatchNull1
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
- name: mismatchNull2
definition: shared-library
load-name: libc.so
- name: mismatchload1
definition: shared-library
load-name: liba.so
- name: mismatchload2
definition: shared-library
load-name: libb.so
---
atoms:
- name: foo2
definition: shared-library
load-name: libc.so
- name: foo3
definition: shared-library
load-name: libc.so
- name: bar2
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
- name: bar3
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
- name: mismatchNull1
definition: shared-library
load-name: libc.so
- name: mismatchNull2
definition: shared-library
load-name: libc.so
can-be-null: at-runtime
- name: mismatchload1
definition: shared-library
load-name: libb.so
- name: mismatchload2
definition: shared-library
load-name: liba.so
...
# CHECK: name: foo1
# CHECK: definition: shared-library
# CHECK: name: foo2
# CHECK: definition: shared-library
# CHECK: name: bar1
# CHECK: definition: shared-library
# CHECK: can-be-null: at-runtime
# CHECK: name: bar2
# CHECK: definition: shared-library
# CHECK: can-be-null: at-runtime
# CHECK: name: mismatchNull1
# CHECK: definition: shared-library
# CHECK: can-be-null: at-runtime
# CHECK: name: mismatchNull2
# CHECK: definition: shared-library
# CHECK-NOT: can-be-null: at-runtime
# CHECK: name: mismatchload1
# CHECK: definition: shared-library
# CHECK: load-name: liba.so
# CHECK: name: mismatchload2
# CHECK: definition: shared-library
# CHECK: load-name: libb.so
# CHECK: name: foo3
# CHECK: definition: shared-library
# CHECK: name: bar3
# CHECK: definition: shared-library
# CHECK: can-be-null: at-runtime
# CHECK: ...

View File

@ -0,0 +1,117 @@
# RUN: lld-core %s | FileCheck %s
#
# Test that undefined symbols preserve their attributes and merge properly
#
---
atoms:
- name: regular_func
definition: undefined
can-be-null: never
- name: weak_import_func
definition: undefined
can-be-null: at-runtime
- name: weak_func
definition: undefined
can-be-null: at-buildtime
- name: bar1
definition: undefined
can-be-null: never
- name: bar2
definition: undefined
can-be-null: at-runtime
- name: bar3
definition: undefined
can-be-null: at-buildtime
- name: bar4
definition: undefined
can-be-null: never
- name: bar5
definition: undefined
can-be-null: at-runtime
- name: bar6
definition: undefined
can-be-null: at-buildtime
- name: bar7
definition: undefined
can-be-null: never
- name: bar8
definition: undefined
can-be-null: at-runtime
- name: bar9
definition: undefined
can-be-null: at-buildtime
---
atoms:
- name: bar1
definition: undefined
can-be-null: never
- name: bar2
definition: undefined
can-be-null: at-runtime
- name: bar3
definition: undefined
can-be-null: at-buildtime
- name: bar4
definition: undefined
can-be-null: at-runtime
- name: bar5
definition: undefined
can-be-null: at-buildtime
- name: bar6
definition: undefined
can-be-null: never
- name: bar7
definition: undefined
can-be-null: at-buildtime
- name: bar8
definition: undefined
can-be-null: never
- name: bar9
definition: undefined
can-be-null: at-runtime
...
# CHECK: name: regular_func
# CHECK: definition: undefined
# CHECK: name: weak_import_func
# CHECK: definition: undefined
# CHECK: can-be-null: at-runtime
# CHECK: name: weak_func
# CHECK: definition: undefined
# CHECK: can-be-null: at-buildtime
# CHECK: name: bar1
# CHECK: name: bar2
# CHECK: can-be-null: at-runtime
# CHECK: name: bar3
# CHECK: can-be-null: at-buildtime
# CHECK: name: bar4
# CHECK: name: bar5
# CHECK: can-be-null: at-runtime
# CHECK: name: bar7
# CHECK: name: bar6
# CHECK: name: bar8
# CHECK: name: bar9
# CHECK: can-be-null: at-runtime
# CHECK: ...

View File

@ -141,6 +141,17 @@ public:
virtual void errorWithUndefines(const std::vector<const Atom *> &undefs,
const std::vector<const Atom *> &all) {}
// print out undefined can-be-null mismatches
virtual void undefineCanBeNullMismatch(const UndefinedAtom& undef1,
const UndefinedAtom& undef2,
bool& useUndef2) { }
// print out shared library mismatches
virtual void sharedLibrarylMismatch(const SharedLibraryAtom& shLib1,
const SharedLibraryAtom& shLib2,
bool& useShlib2) { }
// last chance for platform to tweak atoms
virtual void postResolveTweaks(std::vector<const Atom *> &all) {}
@ -186,6 +197,20 @@ public:
if ( atom )
handler.doUndefinedAtom(*atom);
}
// visit shared library atoms
for (std::vector<const Atom *>::iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
const SharedLibraryAtom* atom = (*it)->sharedLibraryAtom();
if ( atom )
handler.doSharedLibraryAtom(*atom);
}
// visit absolute atoms
for (std::vector<const Atom *>::iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
const AbsoluteAtom* atom = (*it)->absoluteAtom();
if ( atom )
handler.doAbsoluteAtom(*atom);
}
return true;
}
@ -220,7 +245,7 @@ int main(int argc, const char *argv[]) {
// write new atom graph out as YAML doc
std::string errorInfo;
llvm::raw_fd_ostream out("-", errorInfo);
//yaml::writeObjectText(outFile, out);
// yaml::writeObjectText(outFile, out);
// make unique temp .o file to put generated object file
int fd;
@ -232,6 +257,8 @@ int main(int argc, const char *argv[]) {
writeNativeObjectFile(outFile, binaryOut);
binaryOut.close(); // manually close so that file can be read next
// out << "native file: " << tempPath.str() << "\n";
// read native file
llvm::OwningPtr<lld::File> natFile;
if ( error(parseNativeObjectFileOrSTDIN(tempPath, natFile)) )