A couple of big refactorings: 1) Move most attributes of Atom down to DefinedAtom, so only atoms representing definitions need to implement them. 2) Remove definitionTentative, definitionWeak, mergeDuplicates, and autoHide. Replace with merge and interposable attributes. 3) Make all methods on Atom be virtual so that future object file readers can lazily generated attributes

llvm-svn: 147903
This commit is contained in:
Nick Kledzik 2012-01-11 01:06:19 +00:00
parent d9725a38d6
commit f4fb2c5ac8
22 changed files with 1009 additions and 862 deletions

View File

@ -12,173 +12,32 @@
#include <assert.h>
#include "lld/Core/Reference.h"
namespace llvm {
template <typename T>
class ArrayRef;
class StringRef;
}
namespace lld {
class File;
class DefinedAtom;
/// An atom is the fundamental unit of linking. A C function or global variable
/// is an atom. An atom has content and attributes. The content of a function
/// atom is the instructions that implement the function. The content of a
/// global variable atom is its initial bytes.
///
/// 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, mergeDupes=false,
/// autoHide=false, internalName=false, deadStrip=normal
///
/// C function: void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global
///
/// C static function: staic void func() {} <br>
/// name=func, type=code, perm=r_x
///
/// C global variable: int count = 1; <br>
/// name=count, type=data, perm=rw_, scope=global
///
/// C tentative definition: int bar; <br>
/// name=bar, type=data, perm=rw_, scope=global, definition=tentative
///
/// Uninitialized C static variable: static int stuff; <br>
/// name=stuff, type=zerofill, perm=rw_
///
/// Weak C function: __attribute__((weak)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, definition=weak
///
/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}<br>
/// name=foo, type=code, perm=r_x, scope=linkageUnit
///
/// No-dead-strip function: __attribute__((used)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never
///
/// Non-inlined C++ inline method: inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=true, autoHide=true
///
/// Non-inlined C++ inline method whose address is taken:
/// inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global, mergeDupes=true
///
/// literal c-string: "hello" <br>
/// name=L0, internalName=true, type=cstring, perm=r__,
/// scope=linkageUnit, mergeDupes=true
///
/// literal double: 1.234 <br>
/// name=L0, internalName=true, type=literal8, perm=r__,
/// scope=linkageUnit, mergeDupes=true
///
/// constant: { 1,2,3 } <br>
/// name=L0, internalName=true, type=constant, perm=r__,
/// scope=linkageUnit, mergeDupes=true
///
/// Pointer to initializer function: <br>
/// name=_init, internalName=true, type=initializer, perm=rw_l,
/// sectionChoice=customRequired
///
/// C function place in custom section: __attribute__((section("__foo")))
/// void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global,
/// sectionChoice=customRequired, sectionName=__foo
/// 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
/// content or a UndefinedAtom which is a placeholder and represents an
/// undefined symbol (extern declaration).
///
class Atom {
public:
/// The scope in which this atom is acessible to other atoms.
enum Scope {
scopeTranslationUnit, ///< Accessible only to atoms in the same translation
/// unit (e.g. a C static).
scopeLinkageUnit, ///< Accessible to atoms being linked but not visible
/// to runtime loader (e.g. visibility=hidden).
scopeGlobal ///< Accessible to all atoms and visible to runtime
/// loader (e.g. visibility=default) .
};
/// Whether this atom is defined or a proxy for an undefined symbol
enum Definition {
definitionRegular, ///< Normal C/C++ function or global variable.
definitionWeak, ///< Can be silently overridden by definitionRegular
definitionTentative, ///< C-only pre-ANSI support aka common.
definitionAbsolute, ///< Asm-only (foo = 10). Not tied to any content.
definitionUndefined, ///< Only in .o files to model reference to undef.
definitionSharedLibrary ///< Only in shared libraries to model export.
};
enum ContentType {
typeUnknown, // for use with definitionUndefined
typeCode, // executable code
typeResolver, // function which returns address of target
typeBranchIsland, // linker created for large binaries
typeBranchShim, // linker created to switch thumb mode
typeStub, // linker created for calling external function
typeStubHelper, // linker created for initial stub binding
typeConstant, // a read-only constant
typeCString, // a zero terminated UTF8 C string
typeUTF16String, // a zero terminated UTF16 string
typeCFI, // a FDE or CIE from dwarf unwind info
typeLSDA, // extra unwinding info
typeLiteral4, // a four-btye read-only constant
typeLiteral8, // an eight-btye read-only constant
typeLiteral16, // a sixteen-btye read-only constant
typeData, // read-write data
typeZeroFill, // zero-fill data
typeObjC1Class, // ObjC1 class [Darwin]
typeLazyPointer, // pointer through which a stub jumps
typeLazyDylibPointer, // pointer through which a stub jumps [Darwin]
typeCFString, // NS/CFString object [Darwin]
typeGOT, // pointer to external symbol
typeInitializerPtr, // pointer to initializer function
typeTerminatorPtr, // pointer to terminator function
typeCStringPtr, // pointer to UTF8 C string [Darwin]
typeObjCClassPtr, // pointer to ObjC class [Darwin]
typeObjC2CategoryList, // pointers to ObjC category [Darwin]
typeDTraceDOF, // runtime data for Dtrace [Darwin]
typeTempLTO, // temporary atom for bitcode reader
typeCompactUnwindInfo, // runtime data for unwinder [Darwin]
typeThunkTLV, // thunk used to access a TLV [Darwin]
typeTLVInitialData, // initial data for a TLV [Darwin]
typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
typeFirstInSection, // label for boundary of section [Darwin]
typeLastInSection, // label for boundary of section [Darwin]
};
enum ContentPermissions {
perm___ = 0, // mapped as unacessible
permR__ = 8, // mapped read-only
permR_X = 8 + 2, // mapped readable and executable
permRW_ = 8 + 4, // mapped readable and writable
permRW_L = 8 + 4 + 1, // initially mapped r/w, then made read-only
// loader writable
};
enum SectionChoice {
sectionBasedOnContent, // linker infers final section based on content
sectionCustomPreferred, // linker may place in specific section
sectionCustomRequired // linker must place in specific section
};
enum DeadStripKind {
deadStripNormal, // linker may dead strip this atom
deadStripNever, // linker must never dead strip this atom
deadStripAlways // linker must remove this atom if unused
};
struct Alignment {
Alignment(int p2, int m = 0)
: powerOf2(p2)
, modulus(m) {}
uint16_t powerOf2;
uint16_t modulus;
};
/// file - returns the File that produced/owns this Atom
virtual const class File& file() const = 0;
@ -186,204 +45,23 @@ public:
/// name of the function.
virtual llvm::StringRef name() const = 0;
/// internalName - If the name is just a temporary label that should
/// not show up in the final linked image.
bool internalName() const {
return _internalName;
}
/// 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.
virtual uint64_t size() const = 0;
/// scope - The visibility of this atom to other atoms. C static functions
/// have scope scopeTranslationUnit. Regular C functions have scope
/// scopeGlobal. Functions compiled with visibility=hidden have scope
/// scopeLinkageUnit so they can be see by other atoms being linked but not
/// by the OS loader.
Scope scope() const {
return _scope;
}
/// definition - Whether this atom is a definition or represents an undefined
/// or tentative symbol.
Definition definition() const {
return _definition;
}
/// symbol.
virtual Definition definition() const = 0;
/// mergeDuplicates - For definitionRegular atoms, this means the
/// atom can be silently coalesced with another atom that has the
/// same name or content.
bool mergeDuplicates() const {
return _mergeDuplicates;
}
/// definedAtom - like dynamic_cast, if atom is definitionRegular
/// returns atom cast to DefinedAtom*, else returns NULL;
virtual const DefinedAtom* definedAtom() const { return NULL; }
/// contentType - The type of this atom, such as code or data.
ContentType contentType() const {
return _contentType;
}
/// alignment - The alignment constraints on how this atom must be laid out
/// in the final linked image (e.g. 16-byte aligned).
Alignment alignment() const {
return Alignment(_alignmentPowerOf2, _alignmentModulus);
}
/// sectionChoice - Whether this atom must be in a specially named section
/// in the final linked image, or if the linker can infer the section
/// based on the contentType().
SectionChoice sectionChoice() const {
return _sectionChoice;
}
/// customSectionName - If sectionChoice() != sectionBasedOnContent, then
/// this return the name of the section the atom should be placed into.
virtual llvm::StringRef customSectionName() const;
/// deadStrip - constraints on whether the linker may dead strip away
/// this atom.
DeadStripKind deadStrip() const {
return _deadStrip;
}
/// autoHide - Whether it is ok for the linker to change the scope of this
/// atom to hidden as long as all other duplicates are also autoHide.
bool autoHide() const {
return _autoHide;
}
/// permissions - Returns the OS memory protections required for this atom's
/// content at runtime. A function atom is R_X, a global variable is RW_,
/// and a read-only constant is R__.
virtual ContentPermissions permissions() const;
/// isThumb - only applicable to ARM code. Tells the linker if the code
/// uses thumb or arm instructions. The linker needs to know this to
/// set the low bit of pointers to thumb functions.
bool isThumb() const {
return _thumb;
}
/// isAlias - means this is a zero size atom that exists to provide an
/// alternate name for another atom. Alias atoms must have a special
/// Reference to the atom they alias which the layout engine recognizes
/// and forces the alias atom to layout right before the target atom.
bool isAlias() const {
return _alias;
}
/// rawContent - returns a reference to the raw (unrelocated) bytes of
/// this Atom's content.
virtual llvm::ArrayRef<uint8_t> rawContent() const;
/// referencesBegin - used to start iterating this Atom's References
virtual Reference::iterator referencesBegin() const;
/// referencesEnd - used to end iterating this Atom's References
virtual Reference::iterator referencesEnd() const;
/// setLive - sets or clears the liveness bit. Used by linker to do
/// dead code stripping.
void setLive(bool l) { _live = l; }
/// live - returns the liveness bit. Used by linker to do
/// dead code stripping.
bool live() const { return _live; }
/// 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.
uint64_t ordinal() const {
assert(_mode == modeOrdinal);
return _address;
}
/// sectionOffset - returns the section offset assigned to this Atom within
/// its final section.
uint64_t sectionOffset() const {
assert(_mode == modeSectionOffset);
return _address;
}
/// finalAddress - returns the address assigned to Atom within the final
/// linked image.
uint64_t finalAddress() const {
assert(_mode == modeFinalAddress);
return _address;
}
/// setSectionOffset - assigns an offset within a section in the final
/// linked image.
void setSectionOffset(uint64_t off) {
assert(_mode != modeFinalAddress);
_address = off;
_mode = modeSectionOffset;
}
/// setSectionOffset - assigns an offset within a section in the final
/// linked image.
void setFinalAddress(uint64_t addr) {
assert(_mode == modeSectionOffset);
_address = addr;
_mode = modeFinalAddress;
}
/// constructor
Atom( uint64_t ord
, Definition d
, Scope s
, ContentType ct
, SectionChoice sc
, bool internalName
, bool mergeDupes
, bool autoHide
, DeadStripKind ds
, bool IsThumb
, bool IsAlias
, Alignment a)
: _address(ord)
, _alignmentModulus(a.modulus)
, _alignmentPowerOf2(a.powerOf2)
, _contentType(ct)
, _definition(d)
, _scope(s)
, _sectionChoice(sc)
, _internalName(internalName)
, _deadStrip(ds)
, _mode(modeOrdinal)
, _mergeDuplicates(mergeDupes)
, _thumb(IsThumb)
, _autoHide(autoHide)
, _alias(IsAlias)
{}
protected:
/// Atom is an abstract base class. Only subclasses can access constructor.
Atom() {}
/// The memory for Atom objects is always managed by the owning File
/// object. Therefore, no one but the owning File object should call
/// delete on an Atom. In fact, some File objects may bulk allocate
/// an array of Atoms, so they cannot be individually deleted by anyone.
virtual ~Atom();
/// The __address field has different meanings throughout the life of an Atom.
enum AddressMode { modeOrdinal, modeSectionOffset, modeFinalAddress };
uint64_t _address;
uint16_t _alignmentModulus;
uint8_t _alignmentPowerOf2;
ContentType _contentType : 8;
Definition _definition : 3;
Scope _scope : 2;
SectionChoice _sectionChoice: 2;
bool _internalName : 1;
DeadStripKind _deadStrip : 2;
AddressMode _mode : 2;
bool _mergeDuplicates : 1;
bool _thumb : 1;
bool _autoHide : 1;
bool _alias : 1;
bool _live : 1;
virtual ~Atom() {}
};
} // namespace lld

View File

@ -0,0 +1,287 @@
//===- Core/DefinedAtom.h - The Fundimental Unit of Linking ---------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_DEFINED_ATOM_H_
#define LLD_CORE_DEFINED_ATOM_H_
#include <assert.h>
#include "lld/Core/Atom.h"
#include "lld/Core/Reference.h"
namespace llvm {
template <typename T>
class ArrayRef;
class StringRef;
}
namespace lld {
class File;
/// An atom is the fundamental unit of linking. A C function or global variable
/// is an atom. An atom has content and attributes. The content of a function
/// atom is the instructions that implement the function. The content of a
/// global variable atom is its initial bytes.
///
/// 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
///
/// C function: void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global
///
/// C static function: staic void func() {} <br>
/// name=func, type=code, perm=r_x
///
/// C global variable: int count = 1; <br>
/// name=count, type=data, perm=rw_, scope=global
///
/// C tentative definition: int bar; <br>
/// name=bar, type=zerofill, perm=rw_, scope=global,
/// merge=asTentative, interposable=yesAndRuntimeWeak
///
/// Uninitialized C static variable: static int stuff; <br>
/// name=stuff, type=zerofill, perm=rw_
///
/// Weak C function: __attribute__((weak)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, merge=asWeak
///
/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}<br>
/// name=foo, type=code, perm=r_x, scope=linkageUnit
///
/// No-dead-strip function: __attribute__((used)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never
///
/// Non-inlined C++ inline method: inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=asWeak
///
/// Non-inlined C++ inline method whose address is taken:
/// inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=asAddressedWeak
///
/// literal c-string: "hello" <br>
/// name=L0, internalName=true, type=cstring, perm=r__, scope=linkageUnit
///
/// literal double: 1.234 <br>
/// name=L0, internalName=true, type=literal8, perm=r__, scope=linkageUnit
///
/// constant: { 1,2,3 } <br>
/// name=L0, internalName=true, type=constant, perm=r__, scope=linkageUnit
///
/// Pointer to initializer function: <br>
/// name=_init, internalName=true, type=initializer, perm=rw_l,
/// sectionChoice=customRequired
///
/// C function place in custom section: __attribute__((section("__foo")))
/// void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global,
/// sectionChoice=customRequired, sectionName=__foo
///
class DefinedAtom : public Atom {
public:
/// Whether this atom is defined or a proxy for an undefined symbol
virtual Definition definition() const {
return Atom::definitionRegular;
}
virtual const DefinedAtom* definedAtom() const {
return this;
}
/// The scope in which this atom is acessible to other atoms.
enum Scope {
scopeTranslationUnit, ///< Accessible only to atoms in the same translation
/// unit (e.g. a C static).
scopeLinkageUnit, ///< Accessible to atoms being linked but not visible
/// to runtime loader (e.g. visibility=hidden).
scopeGlobal ///< Accessible to all atoms and visible to runtime
/// loader (e.g. visibility=default).
};
enum Interposable {
interposeNo, // linker can directly bind uses of this atom
interposeYes, // linker must indirect (through GOT) uses
interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
// linked image
};
enum Merge {
mergeNo, // Another atom with same name is error
mergeAsTentative, // Is ANSI C tentative defintion, can be coalesced
mergeAsWeak, // is C++ inline definition that was not inlined,
// but address was not taken, so atom can be hidden
// by linker
mergeAsWeakAndAddressUsed // is C++ definition inline definition whose
// address was taken.
};
enum ContentType {
typeUnknown, // for use with definitionUndefined
typeCode, // executable code
typeResolver, // function which returns address of target
typeBranchIsland, // linker created for large binaries
typeBranchShim, // linker created to switch thumb mode
typeStub, // linker created for calling external function
typeStubHelper, // linker created for initial stub binding
typeConstant, // a read-only constant
typeCString, // a zero terminated UTF8 C string
typeUTF16String, // a zero terminated UTF16 string
typeCFI, // a FDE or CIE from dwarf unwind info
typeLSDA, // extra unwinding info
typeLiteral4, // a four-btye read-only constant
typeLiteral8, // an eight-btye read-only constant
typeLiteral16, // a sixteen-btye read-only constant
typeData, // read-write data
typeZeroFill, // zero-fill data
typeObjC1Class, // ObjC1 class [Darwin]
typeLazyPointer, // pointer through which a stub jumps
typeLazyDylibPointer, // pointer through which a stub jumps [Darwin]
typeCFString, // NS/CFString object [Darwin]
typeGOT, // pointer to external symbol
typeInitializerPtr, // pointer to initializer function
typeTerminatorPtr, // pointer to terminator function
typeCStringPtr, // pointer to UTF8 C string [Darwin]
typeObjCClassPtr, // pointer to ObjC class [Darwin]
typeObjC2CategoryList, // pointers to ObjC category [Darwin]
typeDTraceDOF, // runtime data for Dtrace [Darwin]
typeTempLTO, // temporary atom for bitcode reader
typeCompactUnwindInfo, // runtime data for unwinder [Darwin]
typeThunkTLV, // thunk used to access a TLV [Darwin]
typeTLVInitialData, // initial data for a TLV [Darwin]
typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
typeFirstInSection, // label for boundary of section [Darwin]
typeLastInSection, // label for boundary of section [Darwin]
};
enum ContentPermissions {
perm___ = 0, // mapped as unaccessible
permR__ = 8, // mapped read-only
permR_X = 8 + 2, // mapped readable and executable
permRW_ = 8 + 4, // mapped readable and writable
permRW_L = 8 + 4 + 1, // initially mapped r/w, then made read-only
// loader writable
};
enum SectionChoice {
sectionBasedOnContent, // linker infers final section based on content
sectionCustomPreferred, // linker may place in specific section
sectionCustomRequired // linker must place in specific section
};
enum DeadStripKind {
deadStripNormal, // linker may dead strip this atom
deadStripNever, // linker must never dead strip this atom
deadStripAlways // linker must remove this atom if unused
};
struct Alignment {
Alignment(int p2, int m = 0)
: powerOf2(p2)
, modulus(m) {}
uint16_t powerOf2;
uint16_t modulus;
};
/// 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.
virtual uint64_t size() const = 0;
/// scope - The visibility of this atom to other atoms. C static functions
/// have scope scopeTranslationUnit. Regular C functions have scope
/// scopeGlobal. Functions compiled with visibility=hidden have scope
/// scopeLinkageUnit so they can be see by other atoms being linked but not
/// by the OS loader.
virtual Scope scope() const = 0;
/// interposable - Whether the linker should use direct or indirect
/// access to this atom.
virtual Interposable interposable() const = 0;
/// merge - how the linker should handle if multiple atoms have
/// the same name.
virtual Merge merge() const = 0;
/// contentType - The type of this atom, such as code or data.
virtual ContentType contentType() const = 0;
/// alignment - The alignment constraints on how this atom must be laid out
/// in the final linked image (e.g. 16-byte aligned).
virtual Alignment alignment() const = 0;
/// sectionChoice - Whether this atom must be in a specially named section
/// in the final linked image, or if the linker can infer the section
/// based on the contentType().
virtual SectionChoice sectionChoice() const = 0;
/// customSectionName - If sectionChoice() != sectionBasedOnContent, then
/// this return the name of the section the atom should be placed into.
virtual llvm::StringRef customSectionName() const = 0;
/// deadStrip - constraints on whether the linker may dead strip away
/// this atom.
virtual DeadStripKind deadStrip() const = 0;
/// permissions - Returns the OS memory protections required for this atom's
/// content at runtime. A function atom is R_X, a global variable is RW_,
/// and a read-only constant is R__.
virtual ContentPermissions permissions() const = 0;
/// isThumb - only applicable to ARM code. Tells the linker if the code
/// uses thumb or arm instructions. The linker needs to know this to
/// set the low bit of pointers to thumb functions.
virtual bool isThumb() const = 0;
/// isAlias - means this is a zero size atom that exists to provide an
/// alternate name for another atom. Alias atoms must have a special
/// Reference to the atom they alias which the layout engine recognizes
/// and forces the alias atom to layout right before the target atom.
virtual bool isAlias() const = 0;
/// rawContent - returns a reference to the raw (unrelocated) bytes of
/// 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;
protected:
/// DefinedAtom is an abstract base class.
/// Only subclasses can access constructor.
DefinedAtom() { }
/// The memory for DefinedAtom objects is always managed by the owning File
/// object. Therefore, no one but the owning File object should call
/// delete on an Atom. In fact, some File objects may bulk allocate
/// an array of Atoms, so they cannot be individually deleted by anyone.
virtual ~DefinedAtom() {}
};
} // namespace lld
#endif // LLD_CORE_DEFINED_ATOM_H_

View File

@ -12,6 +12,9 @@
#include "llvm/ADT/StringRef.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
namespace lld {
class File {
@ -22,7 +25,8 @@ public:
class AtomHandler {
public:
virtual ~AtomHandler() {}
virtual void doAtom(const class Atom &) = 0;
virtual void doDefinedAtom(const class DefinedAtom &) = 0;
virtual void doUndefinedAtom(const class UndefinedAtom &) = 0;
virtual void doFile(const class File &) = 0;
};

View File

@ -13,6 +13,8 @@
#include "lld/Core/File.h"
#include "lld/Core/SymbolTable.h"
#include "llvm/ADT/DenseSet.h"
#include <vector>
#include <set>
@ -39,8 +41,9 @@ public:
, _completedInitialObjectFiles(false) {}
// AtomHandler methods
virtual void doAtom(const Atom &);
virtual void doFile(const File &);
virtual void doDefinedAtom(const class DefinedAtom&);
virtual void doUndefinedAtom(const class UndefinedAtom&);
virtual void doFile(const File&);
/// @brief do work of merging and resolving and return list
std::vector<const Atom *> &resolve();
@ -65,7 +68,7 @@ private:
const Atom *entryPoint();
void markLive(const Atom &atom, WhyLiveBackChain *previous);
void addAtoms(const std::vector<const Atom *>&);
void addAtoms(const std::vector<const DefinedAtom *>&);
Platform &_platform;
const InputFiles &_inputFiles;
@ -73,6 +76,7 @@ private:
std::vector<const Atom *> _atoms;
std::set<const Atom *> _deadStripRoots;
std::vector<const Atom *> _atomsWithUnresolvedReferences;
llvm::DenseSet<const Atom *> _liveAtoms;
bool _haveLLVMObjs;
bool _addToFinalSection;
bool _completedInitialObjectFiles;

View File

@ -21,6 +21,8 @@
namespace lld {
class Atom;
class DefinedAtom;
class UndefinedAtom;
class Platform;
/// The SymbolTable class is responsible for coalescing atoms.
@ -33,7 +35,10 @@ public:
SymbolTable(Platform& plat);
/// @brief add atom to symbol table
void add(const Atom &);
void add(const DefinedAtom &);
/// @brief add atom to symbol table
void add(const UndefinedAtom &);
/// @brief checks if name is in symbol table and if so atom is not
/// UndefinedAtom
@ -55,15 +60,16 @@ private:
typedef std::map<llvm::StringRef, const Atom *> NameToAtom;
typedef std::map<const Atom *, const Atom *> AtomToAtom;
struct MyMappingInfo {
static const Atom * getEmptyKey() { return NULL; }
static const Atom * getTombstoneKey() { return (Atom*)(-1); }
static unsigned getHashValue(const Atom * const Val);
static bool isEqual(const Atom * const LHS, const Atom * const RHS);
static const DefinedAtom * getEmptyKey() { return NULL; }
static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); }
static unsigned getHashValue(const DefinedAtom * const Val);
static bool isEqual(const DefinedAtom * const LHS,
const DefinedAtom * const RHS);
};
typedef llvm::DenseSet<const Atom*, MyMappingInfo> AtomContentSet;
typedef llvm::DenseSet<const DefinedAtom*, MyMappingInfo> AtomContentSet;
void addByName(const Atom &);
void addByContent(const Atom &);
void addByContent(const DefinedAtom &);
Platform& _platform;
AtomToAtom _replacedAtoms;

View File

@ -20,22 +20,9 @@ namespace lld {
/// It exists as a place holder for a future atom.
class UndefinedAtom : public Atom {
public:
UndefinedAtom(llvm::StringRef nm, const File& f)
: Atom( 0,
Atom::definitionUndefined
, Atom::scopeLinkageUnit
, Atom::typeUnknown
, Atom::sectionBasedOnContent
, false
, false
, false
, deadStripNormal
, false
, false
, Atom::Alignment(0))
, _name(nm), _file(f) {}
UndefinedAtom(llvm::StringRef nm, bool weakImport, const File& f)
: _name(nm), _file(f), _weakImport(weakImport) {}
// overrides of Atom
virtual const File& file() const {
return _file;
}
@ -43,21 +30,21 @@ public:
virtual llvm::StringRef name() const {
return _name;
}
virtual uint64_t size() const {
return 0;
virtual Definition definition() const {
return Atom::definitionUndefined;
}
virtual uint64_t objectAddress() const {
return 0;
virtual bool weakImport() const {
return _weakImport;
}
virtual void copyRawContent(uint8_t buffer[]) const { }
virtual void setScope(Scope) { }
bool weakImport();
protected:
virtual ~UndefinedAtom() {}
llvm::StringRef _name;
const File& _file;
bool _weakImport;
};
} // namespace lld

View File

@ -14,6 +14,7 @@
namespace lld {
class Atom;
class DefinedAtom;
/// The Platform class encapsulated plaform specific linking knowledge.
///
@ -29,15 +30,15 @@ public:
virtual void atomAdded(const Atom &file) = 0;
/// @brief give platform a chance to change each atom's scope
virtual void adjustScope(const Atom &atom) = 0;
virtual void adjustScope(const DefinedAtom &atom) = 0;
/// @brief if specified atom needs alternate names, return AliasAtom(s)
virtual bool getAliasAtoms(const Atom &atom,
std::vector<const Atom *>&) = 0;
std::vector<const DefinedAtom *>&) = 0;
/// @brief give platform a chance to resolve platform-specific undefs
virtual bool getPlatformAtoms(llvm::StringRef undefined,
std::vector<const Atom *>&) = 0;
std::vector<const DefinedAtom *>&) = 0;
/// @brief resolver should remove unreferenced atoms
virtual bool deadCodeStripping() = 0;
@ -46,7 +47,7 @@ public:
virtual bool isDeadStripRoot(const Atom &atom) = 0;
/// @brief if target must have some atoms, denote here
virtual bool getImplicitDeadStripRoots(std::vector<const Atom *>&) = 0;
virtual bool getImplicitDeadStripRoots(std::vector<const DefinedAtom *>&) = 0;
/// @brief return entry point for output file (e.g. "main") or NULL
virtual llvm::StringRef entryPointName() = 0;

View File

@ -1,44 +0,0 @@
//===- Core/Atom.cpp - The Fundimental Unit of Linking --------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/Atom.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
namespace lld {
Atom::~Atom() {}
llvm::StringRef Atom::name() const {
return llvm::StringRef();
}
llvm::StringRef Atom::customSectionName() const {
return llvm::StringRef();
}
llvm::ArrayRef<uint8_t> Atom::rawContent() const {
return llvm::ArrayRef<uint8_t>();
}
Atom::ContentPermissions Atom::permissions() const {
return perm___;
}
Reference::iterator Atom::referencesBegin() const {
return 0;
}
Reference::iterator Atom::referencesEnd() const{
return 0;
}
} // namespace lld

View File

@ -1,5 +1,4 @@
add_lld_library(lldCore
Atom.cpp
File.cpp
Resolver.cpp
SymbolTable.cpp

View File

@ -19,17 +19,35 @@
#include <algorithm>
#include <cassert>
#include <vector>
namespace lld {
/// This is used as a filter function to std::remove_if to dead strip atoms.
class NotLive {
public:
NotLive(const llvm::DenseSet<const Atom*>& la) : _liveAtoms(la) { }
bool operator()(const Atom *atom) const {
return !(atom->live() || !atom->deadStrip());
// don't remove if live
if ( _liveAtoms.count(atom) )
return false;
// don't remove if marked never-dead-strip
if ( const DefinedAtom* defAtom = atom->definedAtom() ) {
if ( defAtom->deadStrip() == DefinedAtom::deadStripNever )
return false;
}
// do remove this atom
return true;
}
private:
const llvm::DenseSet<const Atom*> _liveAtoms;
};
/// This is used as a filter function to std::remove_if to coalesced atoms.
class AtomCoalescedAway {
public:
AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}
@ -43,6 +61,9 @@ private:
SymbolTable &_symbolTable;
};
void Resolver::initializeState() {
_platform.initialize();
}
@ -68,24 +89,34 @@ void Resolver::doFile(const File &file) {
_platform.fileAdded(file);
}
void Resolver::doUndefinedAtom(const class UndefinedAtom& atom) {
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
_symbolTable.add(atom);
}
// called on each atom when a file is added
void Resolver::doAtom(const Atom &atom) {
void Resolver::doDefinedAtom(const DefinedAtom &atom) {
// notify platform
_platform.atomAdded(atom);
// add to list of known atoms
_atoms.push_back(&atom);
// adjust scope (e.g. force some globals to be hidden)
_platform.adjustScope(atom);
// non-static atoms need extra handling
if (atom.scope() != Atom::scopeTranslationUnit) {
if (atom.scope() != DefinedAtom::scopeTranslationUnit) {
// tell symbol table about non-static atoms
_symbolTable.add(atom);
// platform can add aliases for any symbol
std::vector<const Atom *> aliases;
std::vector<const DefinedAtom *> aliases;
if (_platform.getAliasAtoms(atom, aliases))
this->addAtoms(aliases);
}
@ -104,10 +135,10 @@ void Resolver::doAtom(const Atom &atom) {
}
// utility to add a vector of atoms
void Resolver::addAtoms(const std::vector<const Atom *> &newAtoms) {
for (std::vector<const Atom *>::const_iterator it = newAtoms.begin();
void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) {
for (std::vector<const DefinedAtom *>::const_iterator it = newAtoms.begin();
it != newAtoms.end(); ++it) {
this->doAtom(**it);
this->doDefinedAtom(**it);
}
}
@ -135,7 +166,7 @@ void Resolver::resolveUndefines() {
// give platform a chance to instantiate platform
// specific atoms (e.g. section boundary)
if (!_symbolTable.isDefined(undefName)) {
std::vector<const Atom *> platAtoms;
std::vector<const DefinedAtom *> platAtoms;
if (_platform.getPlatformAtoms(undefName, platAtoms))
this->addAtoms(platAtoms);
}
@ -146,9 +177,10 @@ void Resolver::resolveUndefines() {
std::vector<const Atom *> tents;
for (std::vector<const Atom *>::iterator ait = _atoms.begin();
ait != _atoms.end(); ++ait) {
const Atom *atom = *ait;
if (atom->definition() == Atom::definitionTentative)
tents.push_back(atom);
if ( const DefinedAtom* defAtom = (*ait)->definedAtom() ) {
if ( defAtom->merge() == DefinedAtom::mergeAsTentative )
tents.push_back(defAtom);
}
}
for (std::vector<const Atom *>::iterator dit = tents.begin();
dit != tents.end(); ++dit) {
@ -157,9 +189,10 @@ void Resolver::resolveUndefines() {
llvm::StringRef tentName = (*dit)->name();
const Atom *curAtom = _symbolTable.findByName(tentName);
assert(curAtom != NULL);
if (curAtom->definition() == Atom::definitionTentative) {
_inputFiles.searchLibraries(tentName, searchDylibs, true, true,
*this);
if ( const DefinedAtom* curDefAtom = curAtom->definedAtom() ) {
if (curDefAtom->merge() == DefinedAtom::mergeAsTentative )
_inputFiles.searchLibraries(tentName, searchDylibs,
true, true, *this);
}
}
}
@ -171,10 +204,11 @@ void Resolver::resolveUndefines() {
void Resolver::updateReferences() {
for (std::vector<const Atom *>::iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
const Atom *atom = *it;
for (Reference::iterator rit = atom->referencesBegin(),
end = atom->referencesEnd(); rit != end; ++rit) {
rit->target = _symbolTable.replacement(rit->target);
if ( const DefinedAtom* defAtom = (*it)->definedAtom() ) {
for (Reference::iterator rit = defAtom->referencesBegin(),
end = defAtom->referencesEnd(); rit != end; ++rit) {
rit->target = _symbolTable.replacement(rit->target);
}
}
}
}
@ -195,19 +229,21 @@ void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) {
}
// if already marked live, then done (stop recursion)
if (atom.live())
if ( _liveAtoms.count(&atom) )
return;
// mark this atom is live
const_cast<Atom *>(&atom)->setLive(true);
_liveAtoms.insert(&atom);
// mark all atoms it references as live
WhyLiveBackChain thisChain;
thisChain.previous = previous;
thisChain.referer = &atom;
for (Reference::iterator rit = atom.referencesBegin(),
end = atom.referencesEnd(); rit != end; ++rit) {
this->markLive(*(rit->target), &thisChain);
if ( const DefinedAtom* defAtom = atom.definedAtom() ) {
for (Reference::iterator rit = defAtom->referencesBegin(),
end = defAtom->referencesEnd(); rit != end; ++rit) {
this->markLive(*(rit->target), &thisChain);
}
}
}
@ -218,11 +254,7 @@ void Resolver::deadStripOptimize() {
return;
// clear liveness on all atoms
for (std::vector<const Atom *>::iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
const Atom *atom = *it;
const_cast<Atom *>(atom)->setLive(0);
}
_liveAtoms.clear();
// add entry point (main) to live roots
const Atom *entry = this->entryPoint();
@ -239,7 +271,7 @@ void Resolver::deadStripOptimize() {
}
// add platform specific helper atoms
std::vector<const Atom *> platRootAtoms;
std::vector<const DefinedAtom *> platRootAtoms;
if (_platform.getImplicitDeadStripRoots(platRootAtoms))
this->addAtoms(platRootAtoms);
@ -254,7 +286,7 @@ void Resolver::deadStripOptimize() {
// now remove all non-live atoms from _atoms
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
NotLive()), _atoms.end());
NotLive(_liveAtoms)), _atoms.end());
}
// error out if some undefines remain
@ -270,7 +302,7 @@ void Resolver::checkUndefines(bool final) {
// when dead code stripping we don't care if dead atoms are undefined
undefinedAtoms.erase(std::remove_if(
undefinedAtoms.begin(), undefinedAtoms.end(),
NotLive()), undefinedAtoms.end());
NotLive(_liveAtoms)), undefinedAtoms.end());
}
// let platform make error message about missing symbols
@ -289,15 +321,16 @@ void Resolver::removeCoalescedAwayAtoms() {
void Resolver::checkDylibSymbolCollisions() {
for (std::vector<const Atom *>::const_iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
const Atom *atom = *it;
if (atom->scope() == Atom::scopeGlobal) {
if (atom->definition() == Atom::definitionTentative) {
// See if any shared library also has symbol which
// collides with the tentative definition.
// SymbolTable will warn if needed.
_inputFiles.searchLibraries(atom->name(), true, false, false, *this);
}
}
const DefinedAtom* defAtom = (*it)->definedAtom();
if ( defAtom == NULL )
continue;
if ( defAtom->merge() != DefinedAtom::mergeAsTentative )
continue;
assert(defAtom->scope() != DefinedAtom::scopeTranslationUnit);
// See if any shared library also has symbol which
// collides with the tentative definition.
// SymbolTable will warn if needed.
_inputFiles.searchLibraries(defAtom->name(), true, false, false, *this);
}
}

View File

@ -9,6 +9,8 @@
#include "lld/Core/SymbolTable.h"
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/InputFiles.h"
#include "lld/Core/Resolver.h"
@ -30,12 +32,16 @@ SymbolTable::SymbolTable(Platform& plat)
: _platform(plat) {
}
void SymbolTable::add(const Atom &atom) {
assert(atom.scope() != Atom::scopeTranslationUnit);
void SymbolTable::add(const UndefinedAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const DefinedAtom &atom) {
assert(atom.scope() != DefinedAtom::scopeTranslationUnit);
if ( !atom.internalName() ) {
this->addByName(atom);
}
else if ( atom.mergeDuplicates() ) {
else {
this->addByContent(atom);
}
}
@ -43,37 +49,27 @@ void SymbolTable::add(const Atom &atom) {
enum NameCollisionResolution {
NCR_First,
NCR_Second,
NCR_Weak,
NCR_Larger,
NCR_Dup,
NCR_Error
};
static NameCollisionResolution cases[6][6] = {
//regular weak tentative absolute undef sharedLib
static NameCollisionResolution cases[4][4] = {
//regular absolute undef sharedLib
{
// first is regular
NCR_Dup, NCR_First, NCR_First, NCR_Error, NCR_First, NCR_First
},
{
// first is weak
NCR_Second, NCR_Weak, NCR_Larger, NCR_Error, NCR_First, NCR_First
},
{
// first is tentative
NCR_Second, NCR_Second, NCR_Larger, NCR_Error, NCR_First, NCR_First
NCR_Dup, NCR_Error, NCR_First, NCR_First
},
{
// first is absolute
NCR_Error, NCR_Error, NCR_Error, NCR_Error, NCR_First, NCR_First
NCR_Error, NCR_Error, NCR_First, NCR_First
},
{
// first is undef
NCR_Second, NCR_Second, NCR_Second, NCR_Second, NCR_First, NCR_Second
NCR_Second, NCR_Second, NCR_First, NCR_Second
},
{
// first is sharedLib
NCR_Second, NCR_Second, NCR_Second, NCR_Second, NCR_First, NCR_First
NCR_Second, NCR_Second, NCR_First, NCR_First
}
};
@ -82,6 +78,40 @@ static NameCollisionResolution collide(Atom::Definition first,
return cases[first][second];
}
enum MergeResolution {
MCR_First,
MCR_Second,
MCR_Largest,
MCR_Error
};
static MergeResolution mergeCases[4][4] = {
// no tentative weak weakAddressUsed
{
// first is no
MCR_Error, MCR_First, MCR_First, MCR_First
},
{
// first is tentative
MCR_Second, MCR_Largest, MCR_Second, MCR_Second
},
{
// first is weak
MCR_Second, MCR_First, MCR_First, MCR_Second
},
{
// first is weakAddressUsed
MCR_Second, MCR_First, MCR_First, MCR_First
}
};
static MergeResolution mergeSelect(DefinedAtom::Merge first,
DefinedAtom::Merge second) {
return mergeCases[first][second];
}
void SymbolTable::addByName(const Atom & newAtom) {
llvm::StringRef name = newAtom.name();
const Atom *existing = this->findByName(name);
@ -93,31 +123,33 @@ void SymbolTable::addByName(const Atom & newAtom) {
// Name is already in symbol table and associated with another atom.
bool useNew = true;
switch (collide(existing->definition(), newAtom.definition())) {
case NCR_First:
useNew = false;
break;
case NCR_Second:
useNew = true;
break;
case NCR_Dup:
if ( existing->mergeDuplicates() && newAtom.mergeDuplicates() ) {
// Both mergeable. Use auto-hide bit as tie breaker
if ( existing->autoHide() != newAtom.autoHide() ) {
// They have different autoHide values, keep non-autohide one
useNew = existing->autoHide();
case NCR_First:
useNew = false;
break;
case NCR_Second:
useNew = true;
break;
case NCR_Dup:
assert(existing->definition() == Atom::definitionRegular);
assert(newAtom.definition() == Atom::definitionRegular);
switch ( mergeSelect(((DefinedAtom*)existing)->merge(),
((DefinedAtom*)(&newAtom))->merge()) ) {
case MCR_First:
useNew = false;
break;
case MCR_Second:
useNew = true;
break;
case MCR_Largest:
useNew = true;
break;
case MCR_Error:
llvm::report_fatal_error("duplicate symbol error");
break;
}
else {
// They have same autoHide, so just keep using existing
useNew = false;
}
}
else {
const Atom& use = _platform.handleMultipleDefinitions(*existing, newAtom);
useNew = ( &use != existing );
}
break;
default:
llvm::report_fatal_error("SymbolTable::addByName(): unhandled switch clause");
break;
default:
llvm::report_fatal_error("SymbolTable::addByName(): unhandled switch clause");
}
if ( useNew ) {
// Update name table to use new atom.
@ -133,9 +165,9 @@ void SymbolTable::addByName(const Atom & newAtom) {
}
unsigned SymbolTable::MyMappingInfo::getHashValue(const Atom * const atom) {
unsigned SymbolTable::MyMappingInfo::getHashValue(const DefinedAtom * const atom) {
unsigned hash = atom->size();
if ( atom->contentType() != Atom::typeZeroFill ) {
if ( atom->contentType() != DefinedAtom::typeZeroFill ) {
llvm::ArrayRef<uint8_t> content = atom->rawContent();
for (unsigned int i=0; i < content.size(); ++i) {
hash = hash * 33 + content[i];
@ -148,8 +180,8 @@ unsigned SymbolTable::MyMappingInfo::getHashValue(const Atom * const atom) {
}
bool SymbolTable::MyMappingInfo::isEqual(const Atom * const l,
const Atom * const r) {
bool SymbolTable::MyMappingInfo::isEqual(const DefinedAtom * const l,
const DefinedAtom * const r) {
if ( l == r )
return true;
if ( l == getEmptyKey() )
@ -171,7 +203,7 @@ bool SymbolTable::MyMappingInfo::isEqual(const Atom * const l,
}
void SymbolTable::addByContent(const Atom & newAtom) {
void SymbolTable::addByContent(const DefinedAtom & newAtom) {
AtomContentSet::iterator pos = _contentTable.find(&newAtom);
if ( pos == _contentTable.end() ) {
_contentTable.insert(&newAtom);

View File

@ -18,61 +18,33 @@ namespace yaml {
const char* const KeyValues::nameKeyword = "name";
const char* const KeyValues::scopeKeyword = "scope";
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::mergeDuplicatesKeyword = "merge-duplicates";
const char* const KeyValues::autoHideKeyword = "auto-hide";
const char* const KeyValues::interposableKeyword = "interposable";
const char* const KeyValues::mergeKeyword = "merge";
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::sizeKeyword = "size";
const char* const KeyValues::permissionsKeyword = "permissions";
const Atom::Scope KeyValues::scopeDefault = Atom::scopeTranslationUnit;
const Atom::Definition KeyValues::definitionDefault = Atom::definitionRegular;
const Atom::ContentType KeyValues::contentTypeDefault = Atom::typeData;
const Atom::DeadStripKind KeyValues::deadStripKindDefault = Atom::deadStripNormal;
const Atom::SectionChoice KeyValues::sectionChoiceDefault = Atom::sectionBasedOnContent;
const bool KeyValues::internalNameDefault = false;
const bool KeyValues::mergeDuplicatesDefault = false;
const bool KeyValues::autoHideDefault = false;
const bool KeyValues::isThumbDefault = false;
const bool KeyValues::isAliasDefault = false;
struct ScopeMapping {
const char* string;
Atom::Scope value;
};
static const ScopeMapping scopeMappings[] = {
{ "global", Atom::scopeGlobal },
{ "hidden", Atom::scopeLinkageUnit },
{ "static", Atom::scopeTranslationUnit },
{ NULL, Atom::scopeGlobal }
};
Atom::Scope KeyValues::scope(const char* s)
{
for (const ScopeMapping* p = scopeMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
return p->value;
}
llvm::report_fatal_error("bad scope value");
}
const char* KeyValues::scope(Atom::Scope s) {
for (const ScopeMapping* p = scopeMappings; p->string != NULL; ++p) {
if ( p->value == s )
return p->string;
}
llvm::report_fatal_error("bad scope value");
}
const DefinedAtom::Definition KeyValues::definitionDefault = Atom::definitionRegular;
const DefinedAtom::Scope KeyValues::scopeDefault = DefinedAtom::scopeTranslationUnit;
const DefinedAtom::ContentType KeyValues::contentTypeDefault = DefinedAtom::typeData;
const DefinedAtom::DeadStripKind KeyValues::deadStripKindDefault = DefinedAtom::deadStripNormal;
const DefinedAtom::SectionChoice KeyValues::sectionChoiceDefault = DefinedAtom::sectionBasedOnContent;
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;
@ -85,8 +57,6 @@ struct DefinitionMapping {
static const DefinitionMapping defMappings[] = {
{ "regular", Atom::definitionRegular },
{ "weak", Atom::definitionWeak },
{ "tentative", Atom::definitionTentative },
{ "absolute", Atom::definitionAbsolute },
{ "undefined", Atom::definitionUndefined },
{ "shared-library", Atom::definitionSharedLibrary },
@ -114,40 +84,76 @@ const char* KeyValues::definition(Atom::Definition s) {
struct ScopeMapping {
const char* string;
DefinedAtom::Scope value;
};
static const ScopeMapping scopeMappings[] = {
{ "global", DefinedAtom::scopeGlobal },
{ "hidden", DefinedAtom::scopeLinkageUnit },
{ "static", DefinedAtom::scopeTranslationUnit },
{ NULL, DefinedAtom::scopeGlobal }
};
DefinedAtom::Scope KeyValues::scope(const char* s)
{
for (const ScopeMapping* p = scopeMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
return p->value;
}
llvm::report_fatal_error("bad scope value");
}
const char* KeyValues::scope(DefinedAtom::Scope s) {
for (const ScopeMapping* p = scopeMappings; p->string != NULL; ++p) {
if ( p->value == s )
return p->string;
}
llvm::report_fatal_error("bad scope value");
}
struct ContentTypeMapping {
const char* string;
Atom::ContentType value;
DefinedAtom::ContentType value;
};
static const ContentTypeMapping typeMappings[] = {
{ "unknown", Atom::typeUnknown },
{ "code", Atom::typeCode },
{ "resolver", Atom::typeResolver },
{ "constant", Atom::typeConstant },
{ "c-string", Atom::typeCString },
{ "utf16-string", Atom::typeUTF16String },
{ "CFI", Atom::typeCFI },
{ "LSDA", Atom::typeLSDA },
{ "literal-4", Atom::typeLiteral4 },
{ "literal-8", Atom::typeLiteral8 },
{ "literal-16", Atom::typeLiteral16 },
{ "data", Atom::typeData },
{ "zero-fill", Atom::typeZeroFill },
{ "cf-string", Atom::typeCFString },
{ "initializer-ptr",Atom::typeInitializerPtr },
{ "terminator-ptr", Atom::typeTerminatorPtr },
{ "c-string-ptr", Atom::typeCStringPtr },
{ "objc1-class", Atom::typeObjC1Class },
{ "objc1-class-ptr",Atom::typeObjCClassPtr },
{ "objc2-cat-ptr", Atom::typeObjC2CategoryList },
{ "tlv-thunk", Atom::typeThunkTLV },
{ "tlv-data", Atom::typeTLVInitialData },
{ "tlv-zero-fill", Atom::typeTLVInitialZeroFill },
{ "tlv-init-ptr", Atom::typeTLVInitializerPtr },
{ NULL, Atom::typeUnknown }
{ "unknown", DefinedAtom::typeUnknown },
{ "code", DefinedAtom::typeCode },
{ "resolver", DefinedAtom::typeResolver },
{ "constant", DefinedAtom::typeConstant },
{ "c-string", DefinedAtom::typeCString },
{ "utf16-string", DefinedAtom::typeUTF16String },
{ "CFI", DefinedAtom::typeCFI },
{ "LSDA", DefinedAtom::typeLSDA },
{ "literal-4", DefinedAtom::typeLiteral4 },
{ "literal-8", DefinedAtom::typeLiteral8 },
{ "literal-16", DefinedAtom::typeLiteral16 },
{ "data", DefinedAtom::typeData },
{ "zero-fill", DefinedAtom::typeZeroFill },
{ "cf-string", DefinedAtom::typeCFString },
{ "initializer-ptr",DefinedAtom::typeInitializerPtr },
{ "terminator-ptr", DefinedAtom::typeTerminatorPtr },
{ "c-string-ptr", DefinedAtom::typeCStringPtr },
{ "objc1-class", DefinedAtom::typeObjC1Class },
{ "objc1-class-ptr",DefinedAtom::typeObjCClassPtr },
{ "objc2-cat-ptr", DefinedAtom::typeObjC2CategoryList },
{ "tlv-thunk", DefinedAtom::typeThunkTLV },
{ "tlv-data", DefinedAtom::typeTLVInitialData },
{ "tlv-zero-fill", DefinedAtom::typeTLVInitialZeroFill },
{ "tlv-init-ptr", DefinedAtom::typeTLVInitializerPtr },
{ NULL, DefinedAtom::typeUnknown }
};
Atom::ContentType KeyValues::contentType(const char* s)
DefinedAtom::ContentType KeyValues::contentType(const char* s)
{
for (const ContentTypeMapping* p = typeMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
@ -156,7 +162,7 @@ Atom::ContentType KeyValues::contentType(const char* s)
llvm::report_fatal_error("bad content type value");
}
const char* KeyValues::contentType(Atom::ContentType s) {
const char* KeyValues::contentType(DefinedAtom::ContentType s) {
for (const ContentTypeMapping* p = typeMappings; p->string != NULL; ++p) {
if ( p->value == s )
return p->string;
@ -172,17 +178,17 @@ const char* KeyValues::contentType(Atom::ContentType s) {
struct DeadStripMapping {
const char* string;
Atom::DeadStripKind value;
DefinedAtom::DeadStripKind value;
};
static const DeadStripMapping deadStripMappings[] = {
{ "normal", Atom::deadStripNormal },
{ "never", Atom::deadStripNever },
{ "always", Atom::deadStripAlways },
{ NULL, Atom::deadStripNormal }
{ "normal", DefinedAtom::deadStripNormal },
{ "never", DefinedAtom::deadStripNever },
{ "always", DefinedAtom::deadStripAlways },
{ NULL, DefinedAtom::deadStripNormal }
};
Atom::DeadStripKind KeyValues::deadStripKind(const char* s)
DefinedAtom::DeadStripKind KeyValues::deadStripKind(const char* s)
{
for (const DeadStripMapping* p = deadStripMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
@ -191,7 +197,7 @@ Atom::DeadStripKind KeyValues::deadStripKind(const char* s)
llvm::report_fatal_error("bad dead strip value");
}
const char* KeyValues::deadStripKind(Atom::DeadStripKind dsk) {
const char* KeyValues::deadStripKind(DefinedAtom::DeadStripKind dsk) {
for (const DeadStripMapping* p = deadStripMappings; p->string != NULL; ++p) {
if ( p->value == dsk )
return p->string;
@ -203,20 +209,88 @@ const char* KeyValues::deadStripKind(Atom::DeadStripKind dsk) {
struct InterposableMapping {
const char* string;
DefinedAtom::Interposable value;
};
static const InterposableMapping interMappings[] = {
{ "no", DefinedAtom::interposeNo },
{ "yes", DefinedAtom::interposeYes },
{ "yesAndWeak", DefinedAtom::interposeYesAndRuntimeWeak },
{ NULL, DefinedAtom::interposeNo }
};
DefinedAtom::Interposable KeyValues::interposable(const char* s)
{
for (const InterposableMapping* p = interMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
return p->value;
}
llvm::report_fatal_error("bad interposable value");
}
const char* KeyValues::interposable(DefinedAtom::Interposable in) {
for (const InterposableMapping* p = interMappings; p->string != NULL; ++p) {
if ( p->value == in )
return p->string;
}
llvm::report_fatal_error("bad interposable value");
}
struct MergeMapping {
const char* string;
DefinedAtom::Merge value;
};
static const MergeMapping mergeMappings[] = {
{ "no", DefinedAtom::mergeNo },
{ "asTentative", DefinedAtom::mergeAsTentative },
{ "asWeak", DefinedAtom::mergeAsWeak },
{ "asAddressedWeak",DefinedAtom::mergeAsWeakAndAddressUsed },
{ NULL, DefinedAtom::mergeNo }
};
DefinedAtom::Merge KeyValues::merge(const char* s)
{
for (const MergeMapping* p = mergeMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
return p->value;
}
llvm::report_fatal_error("bad merge value");
}
const char* KeyValues::merge(DefinedAtom::Merge in) {
for (const MergeMapping* p = mergeMappings; p->string != NULL; ++p) {
if ( p->value == in )
return p->string;
}
llvm::report_fatal_error("bad merge value");
}
struct SectionChoiceMapping {
const char* string;
Atom::SectionChoice value;
const char* string;
DefinedAtom::SectionChoice value;
};
static const SectionChoiceMapping sectMappings[] = {
{ "content", Atom::sectionBasedOnContent },
{ "custom", Atom::sectionCustomPreferred },
{ "custom-required", Atom::sectionCustomRequired },
{ NULL, Atom::sectionBasedOnContent }
{ "content", DefinedAtom::sectionBasedOnContent },
{ "custom", DefinedAtom::sectionCustomPreferred },
{ "custom-required", DefinedAtom::sectionCustomRequired },
{ NULL, DefinedAtom::sectionBasedOnContent }
};
Atom::SectionChoice KeyValues::sectionChoice(const char* s)
DefinedAtom::SectionChoice KeyValues::sectionChoice(const char* s)
{
for (const SectionChoiceMapping* p = sectMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
@ -225,7 +299,7 @@ Atom::SectionChoice KeyValues::sectionChoice(const char* s)
llvm::report_fatal_error("bad dead strip value");
}
const char* KeyValues::sectionChoice(Atom::SectionChoice s) {
const char* KeyValues::sectionChoice(DefinedAtom::SectionChoice s) {
for (const SectionChoiceMapping* p = sectMappings; p->string != NULL; ++p) {
if ( p->value == s )
return p->string;
@ -239,6 +313,43 @@ const char* KeyValues::sectionChoice(Atom::SectionChoice s) {
struct PermissionsMapping {
const char* string;
DefinedAtom::ContentPermissions value;
};
static const PermissionsMapping permMappings[] = {
{ "content", DefinedAtom::perm___ },
{ "custom", DefinedAtom::permR__ },
{ "custom-required", DefinedAtom::permR_X },
{ "custom-required", DefinedAtom::permRW_ },
{ "custom-required", DefinedAtom::permRW_L },
{ NULL, DefinedAtom::perm___ }
};
DefinedAtom::ContentPermissions KeyValues::permissions(const char* s)
{
for (const PermissionsMapping* p = permMappings; p->string != NULL; ++p) {
if ( strcmp(p->string, s) == 0 )
return p->value;
}
llvm::report_fatal_error("bad permissions value");
}
const char* KeyValues::permissions(DefinedAtom::ContentPermissions s) {
for (const PermissionsMapping* p = permMappings; p->string != NULL; ++p) {
if ( p->value == s )
return p->string;
}
llvm::report_fatal_error("bad permissions value");
}
bool KeyValues::internalName(const char* s)
{
if ( strcmp(s, "true") == 0 )
@ -255,43 +366,6 @@ const char* KeyValues::internalName(bool b) {
bool KeyValues::mergeDuplicates(const char* s)
{
if ( strcmp(s, "true") == 0 )
return true;
else if ( strcmp(s, "false") == 0 )
return false;
llvm::report_fatal_error("bad merge-duplicates value");
}
const char* KeyValues::mergeDuplicates(bool b) {
return b ? "true" : "false";
}
bool KeyValues::autoHide(const char* s)
{
if ( strcmp(s, "true") == 0 )
return true;
else if ( strcmp(s, "false") == 0 )
return false;
llvm::report_fatal_error("bad auto-hide value");
}
const char* KeyValues::autoHide(bool b) {
return b ? "true" : "false";
}
bool KeyValues::isThumb(const char* s)
{
if ( strcmp(s, "true") == 0 )

View File

@ -11,6 +11,7 @@
#define LLD_CORE_YAML_KEY_VALUES_H_
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
namespace lld {
@ -18,61 +19,65 @@ namespace yaml {
class KeyValues {
public:
static const char* const nameKeyword;
static const char* const sectionNameKeyword;
static const char* const contentKeyword;
static const char* const sizeKeyword;
static const char* const nameKeyword;
static const char* const sectionNameKeyword;
static const char* const contentKeyword;
static const char* const sizeKeyword;
static const char* const definitionKeyword;
static const Atom::Definition definitionDefault;
static Atom::Definition definition(const char*);
static const char* definition(Atom::Definition);
static const char* const scopeKeyword;
static const Atom::Scope scopeDefault;
static Atom::Scope scope(const char*);
static const char* scope(Atom::Scope);
static const char* const scopeKeyword;
static const DefinedAtom::Scope scopeDefault;
static DefinedAtom::Scope scope(const char*);
static const char* scope(DefinedAtom::Scope);
static const char* const definitionKeyword;
static const Atom::Definition definitionDefault;
static Atom::Definition definition(const char*);
static const char* definition(Atom::Definition);
static const char* const contentTypeKeyword;
static const DefinedAtom::ContentType contentTypeDefault;
static DefinedAtom::ContentType contentType(const char*);
static const char* contentType(DefinedAtom::ContentType);
static const char* const contentTypeKeyword;
static const Atom::ContentType contentTypeDefault;
static Atom::ContentType contentType(const char*);
static const char* contentType(Atom::ContentType);
static const char* const deadStripKindKeyword;
static const DefinedAtom::DeadStripKind deadStripKindDefault;
static DefinedAtom::DeadStripKind deadStripKind(const char*);
static const char* deadStripKind(DefinedAtom::DeadStripKind);
static const char* const deadStripKindKeyword;
static const Atom::DeadStripKind deadStripKindDefault;
static Atom::DeadStripKind deadStripKind(const char*);
static const char* deadStripKind(Atom::DeadStripKind);
static const char* const sectionChoiceKeyword;
static const DefinedAtom::SectionChoice sectionChoiceDefault;
static DefinedAtom::SectionChoice sectionChoice(const char*);
static const char* sectionChoice(DefinedAtom::SectionChoice);
static const char* const sectionChoiceKeyword;
static const Atom::SectionChoice sectionChoiceDefault;
static Atom::SectionChoice sectionChoice(const char*);
static const char* sectionChoice(Atom::SectionChoice);
static const char* const interposableKeyword;
static const DefinedAtom::Interposable interposableDefault;
static DefinedAtom::Interposable interposable(const char*);
static const char* interposable(DefinedAtom::Interposable);
static const char* const internalNameKeyword;
static const bool internalNameDefault;
static bool internalName(const char*);
static const char* internalName(bool);
static const char* const mergeKeyword;
static const DefinedAtom::Merge mergeDefault;
static DefinedAtom::Merge merge(const char*);
static const char* merge(DefinedAtom::Merge);
static const char* const mergeDuplicatesKeyword;
static const bool mergeDuplicatesDefault;
static bool mergeDuplicates(const char*);
static const char* mergeDuplicates(bool);
static const char* const permissionsKeyword;
static const DefinedAtom::ContentPermissions permissionsDefault;
static DefinedAtom::ContentPermissions permissions(const char*);
static const char* permissions(DefinedAtom::ContentPermissions);
static const char* const autoHideKeyword;
static const bool autoHideDefault;
static bool autoHide(const char*);
static const char* autoHide(bool);
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*);
static const char* isThumb(bool);
static const char* const isThumbKeyword;
static const bool isThumbDefault;
static bool isThumb(const char*);
static const char* isThumb(bool);
static const char* const isAliasKeyword;
static const bool isAliasDefault;
static bool isAlias(const char*);
static const char* isAlias(bool);
static const char* const isAliasKeyword;
static const bool isAliasDefault;
static bool isAlias(const char*);
static const char* isAlias(bool);
};

View File

@ -289,16 +289,17 @@ public:
virtual bool justInTimeforEachAtom(llvm::StringRef name,
File::AtomHandler &) const;
std::vector<Atom *> _atoms;
std::vector<DefinedAtom*> _definedAtoms;
std::vector<UndefinedAtom*> _undefinedAtoms;
std::vector<Reference> _references;
unsigned int _lastRefIndex;
};
bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
handler.doFile(*this);
for (std::vector<Atom *>::const_iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
handler.doAtom(**it);
for (std::vector<DefinedAtom *>::const_iterator it = _definedAtoms.begin();
it != _definedAtoms.end(); ++it) {
handler.doDefinedAtom(**it);
}
return true;
}
@ -309,90 +310,153 @@ bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
}
class YAMLAtom : public Atom {
class YAMLDefinedAtom : public DefinedAtom {
public:
YAMLAtom( uint64_t ord
, Definition d
, Scope s
, ContentType ct
, SectionChoice sc
, bool intn
, bool md
, bool ah
, DeadStripKind dsk
, bool tb
, bool al
, Alignment a
, YAMLFile& f
, const char *n
, const char* sn
, uint64_t sz
, std::vector<uint8_t>* c)
: Atom(ord, d, s, ct, sc, intn, md, ah, dsk, tb, al, a)
, _file(f)
, _name(n)
, _sectionName(sn)
, _content(c)
, _size(sz)
, _refStartIndex(f._lastRefIndex)
, _refEndIndex(f._references.size()) {
f._lastRefIndex = _refEndIndex;
YAMLDefinedAtom( uint32_t ord
, YAMLFile& file
, DefinedAtom::Scope scope
, DefinedAtom::ContentType type
, DefinedAtom::SectionChoice sectionChoice
, DefinedAtom::Interposable interpose
, DefinedAtom::Merge merge
, DefinedAtom::DeadStripKind deadStrip
, DefinedAtom::ContentPermissions perms
, bool internalName
, bool isThumb
, bool isAlias
, DefinedAtom::Alignment alignment
, const char* name
, const char* sectionName
, uint64_t size
, std::vector<uint8_t>* content)
: _file(file)
, _name(name)
, _sectionName(sectionName)
, _size(size)
, _ord(ord)
, _content(content)
, _alignment(alignment)
, _scope(scope)
, _type(type)
, _sectionChoice(sectionChoice)
, _interpose(interpose)
, _merge(merge)
, _deadStrip(deadStrip)
, _permissions(perms)
, _internalName(internalName)
, _isThumb(isThumb)
, _isAlias(isAlias)
, _refStartIndex(file._lastRefIndex)
, _refEndIndex(file._references.size()) {
file._lastRefIndex = _refEndIndex;
}
virtual const class File& file() const {
return _file;
}
virtual bool translationUnitSource(const char* *dir, const char* *name) const{
return false;
}
virtual llvm::StringRef name() const {
return _name;
}
virtual bool internalName() const {
return _internalName;
}
virtual llvm::StringRef customSectionName() const {
return (_sectionName ? _sectionName : llvm::StringRef());
}
virtual uint64_t objectAddress() const {
return 0;
}
virtual uint64_t size() const {
virtual uint64_t size() const {
return (_content ? _content->size() : _size);
}
llvm::ArrayRef<uint8_t> rawContent() const {
virtual DefinedAtom::Scope scope() const {
return _scope;
}
virtual DefinedAtom::Interposable interposable() const {
return _interpose;
}
virtual DefinedAtom::Merge merge() const {
return _merge;
}
virtual DefinedAtom::ContentType contentType() const {
return _type;
}
virtual DefinedAtom::Alignment alignment() const {
return _alignment;
}
virtual DefinedAtom::SectionChoice sectionChoice() const {
return _sectionChoice;
}
virtual llvm::StringRef customSectionName() const {
return _sectionName;
}
virtual DefinedAtom::DeadStripKind deadStrip() const {
return _deadStrip;
}
virtual DefinedAtom::ContentPermissions permissions() const {
return _permissions;
}
virtual bool isThumb() const {
return _isThumb;
}
virtual bool isAlias() const {
return _isAlias;
}
llvm::ArrayRef<uint8_t> rawContent() const {
if ( _content != NULL )
return llvm::ArrayRef<uint8_t>(*_content);
else
return llvm::ArrayRef<uint8_t>();
}
virtual uint64_t ordinal() const {
return _ord;
}
virtual Reference::iterator referencesBegin() const {
if (_file._references.size() < _refStartIndex)
return (Reference::iterator)&_file._references[_refStartIndex];
return 0;
}
virtual Reference::iterator referencesEnd() const {
if (_file._references.size() < _refEndIndex)
return (Reference::iterator)&_file._references[_refEndIndex];
return 0;
}
virtual Reference::iterator referencesBegin() const;
virtual Reference::iterator referencesEnd() const;
private:
YAMLFile& _file;
const char * _name;
const char * _sectionName;
std::vector<uint8_t>* _content;
unsigned long _size;
unsigned int _refStartIndex;
unsigned int _refEndIndex;
YAMLFile& _file;
const char * _name;
const char * _sectionName;
unsigned long _size;
uint32_t _ord;
std::vector<uint8_t>* _content;
DefinedAtom::Alignment _alignment;
DefinedAtom::Scope _scope;
DefinedAtom::ContentType _type;
DefinedAtom::SectionChoice _sectionChoice;
DefinedAtom::Interposable _interpose;
DefinedAtom::Merge _merge;
DefinedAtom::DeadStripKind _deadStrip;
DefinedAtom::ContentPermissions _permissions;
bool _internalName;
bool _isThumb;
bool _isAlias;
unsigned int _refStartIndex;
unsigned int _refEndIndex;
};
Reference::iterator YAMLAtom::referencesBegin() const {
if (_file._references.size() < _refStartIndex)
return (Reference::iterator)&_file._references[_refStartIndex];
return 0;
}
Reference::iterator YAMLAtom::referencesEnd() const {
if (_file._references.size() < _refEndIndex)
return (Reference::iterator)&_file._references[_refEndIndex];
return 0;
}
class YAMLAtomState {
public:
@ -408,42 +472,46 @@ public:
void makeAtom(YAMLFile&);
uint64_t _ordinal;
long long _size;
const char *_name;
Atom::Alignment _align;
Atom::ContentType _type;
Atom::Scope _scope;
Atom::Definition _def;
Atom::SectionChoice _sectionChoice;
bool _internalName;
bool _mergeDuplicates;
Atom::DeadStripKind _deadStrip;
bool _thumb;
bool _alias;
bool _autoHide;
const char *_sectionName;
std::vector<uint8_t>* _content;
Reference _ref;
const char * _name;
const char * _sectionName;
unsigned long long _size;
uint32_t _ordinal;
std::vector<uint8_t>* _content;
DefinedAtom::Alignment _alignment;
Atom::Definition _definition;
DefinedAtom::Scope _scope;
DefinedAtom::ContentType _type;
DefinedAtom::SectionChoice _sectionChoice;
DefinedAtom::Interposable _interpose;
DefinedAtom::Merge _merge;
DefinedAtom::DeadStripKind _deadStrip;
DefinedAtom::ContentPermissions _permissions;
bool _internalName;
bool _isThumb;
bool _isAlias;
Reference _ref;
};
YAMLAtomState::YAMLAtomState()
: _ordinal(0)
, _size(0)
, _name(NULL)
, _align(0, 0)
, _type(KeyValues::contentTypeDefault)
, _scope(KeyValues::scopeDefault)
, _def(KeyValues::definitionDefault)
, _sectionChoice(KeyValues::sectionChoiceDefault)
, _internalName(KeyValues::internalNameDefault)
, _mergeDuplicates(KeyValues::mergeDuplicatesDefault)
, _deadStrip(KeyValues::deadStripKindDefault)
, _thumb(KeyValues::isThumbDefault)
, _alias(KeyValues::isAliasDefault)
, _autoHide(KeyValues::autoHideDefault)
: _name(NULL)
, _sectionName(NULL)
, _content(NULL) {
, _size(0)
, _ordinal(0)
, _content(NULL)
, _alignment(0, 0)
, _definition(KeyValues::definitionDefault)
, _scope(KeyValues::scopeDefault)
, _type(KeyValues::contentTypeDefault)
, _sectionChoice(KeyValues::sectionChoiceDefault)
, _interpose(KeyValues::interposableDefault)
, _merge(KeyValues::mergeDefault)
, _deadStrip(KeyValues::deadStripKindDefault)
, _permissions(KeyValues::permissionsDefault)
, _internalName(KeyValues::internalNameDefault)
, _isThumb(KeyValues::isThumbDefault)
, _isAlias(KeyValues::isAliasDefault)
{
_ref.target = NULL;
_ref.addend = 0;
_ref.offsetInAtom = 0;
@ -451,31 +519,36 @@ YAMLAtomState::YAMLAtomState()
_ref.flags = 0;
}
void YAMLAtomState::makeAtom(YAMLFile& f) {
Atom *a = new YAMLAtom(_ordinal, _def, _scope, _type, _sectionChoice,
_internalName, _mergeDuplicates, _autoHide,
_deadStrip, _thumb, _alias, _align, f,
_name, _sectionName, _size, _content);
f._atoms.push_back(a);
++_ordinal;
void YAMLAtomState::makeAtom(YAMLFile& f) {
if ( _definition == Atom::definitionRegular ) {
DefinedAtom *a = new YAMLDefinedAtom(_ordinal, f, _scope, _type,
_sectionChoice, _interpose, _merge, _deadStrip,
_permissions, _internalName, _isThumb, _isAlias,
_alignment, _name, _sectionName, _size, _content);
f._definedAtoms.push_back(a);
++_ordinal;
}
// reset state for next atom
_name = NULL;
_align.powerOf2 = 0;
_align.modulus = 0;
_type = KeyValues::contentTypeDefault;
_scope = KeyValues::scopeDefault;
_def = KeyValues::definitionDefault;
_sectionChoice = KeyValues::sectionChoiceDefault;
_internalName = KeyValues::internalNameDefault;
_mergeDuplicates = KeyValues::mergeDuplicatesDefault;
_deadStrip = KeyValues::deadStripKindDefault;
_thumb = KeyValues::isThumbDefault;
_alias = KeyValues::isAliasDefault;
_autoHide = KeyValues::autoHideDefault;
_sectionName = NULL;
_size = 0;
_ordinal = 0;
_content = NULL;
_alignment.powerOf2= 0;
_alignment.modulus = 0;
_definition = KeyValues::definitionDefault;
_scope = KeyValues::scopeDefault;
_type = KeyValues::contentTypeDefault;
_sectionChoice = KeyValues::sectionChoiceDefault;
_interpose = KeyValues::interposableDefault;
_merge = KeyValues::mergeDefault;
_deadStrip = KeyValues::deadStripKindDefault;
_permissions = KeyValues::permissionsDefault;
_isThumb = KeyValues::isThumbDefault;
_isAlias = KeyValues::isAliasDefault;
_ref.target = NULL;
_ref.addend = 0;
_ref.offsetInAtom = 0;
@ -492,7 +565,7 @@ void YAMLAtomState::setAlign2(const char *s) {
llvm::StringRef str(s);
uint32_t res;
str.getAsInteger(10, res);
_align.powerOf2 = static_cast<uint16_t>(res);
_alignment.powerOf2 = static_cast<uint16_t>(res);
}
@ -590,7 +663,7 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::definitionKeyword) == 0) {
atomState._def = KeyValues::definition(entry->value);
atomState._definition = KeyValues::definition(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::scopeKeyword) == 0) {
@ -609,20 +682,20 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
atomState._sectionChoice = KeyValues::sectionChoice(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::mergeDuplicatesKeyword) == 0) {
atomState._mergeDuplicates = KeyValues::mergeDuplicates(entry->value);
else if (strcmp(entry->key, KeyValues::mergeKeyword) == 0) {
atomState._merge = KeyValues::merge(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::autoHideKeyword) == 0) {
atomState._autoHide = KeyValues::autoHide(entry->value);
else if (strcmp(entry->key, KeyValues::interposableKeyword) == 0) {
atomState._interpose = KeyValues::interposable(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::isThumbKeyword) == 0) {
atomState._thumb = KeyValues::isThumb(entry->value);
atomState._isThumb = KeyValues::isThumb(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::isAliasKeyword) == 0) {
atomState._alias = KeyValues::isAlias(entry->value);
atomState._isAlias = KeyValues::isAlias(entry->value);
haveAtom = true;
}
else if (strcmp(entry->key, KeyValues::sectionNameKeyword) == 0) {

View File

@ -32,7 +32,7 @@ public:
virtual void doFile(const class File &) { _firstAtom = true; }
virtual void doAtom(const class Atom &atom) {
virtual void doDefinedAtom(const class DefinedAtom &atom) {
// add blank line between atoms for readability
if ( !_firstAtom )
_out << "\n";
@ -72,6 +72,24 @@ public:
<< "\n";
}
if ( atom.interposable() != KeyValues::interposableDefault ) {
_out << " "
<< KeyValues::interposableKeyword
<< ":"
<< spacePadding(KeyValues::interposableKeyword)
<< KeyValues::interposable(atom.interposable())
<< "\n";
}
if ( atom.merge() != KeyValues::mergeDefault ) {
_out << " "
<< KeyValues::mergeKeyword
<< ":"
<< spacePadding(KeyValues::mergeKeyword)
<< KeyValues::merge(atom.merge())
<< "\n";
}
if ( atom.contentType() != KeyValues::contentTypeDefault ) {
_out << " "
<< KeyValues::contentTypeKeyword
@ -106,25 +124,7 @@ public:
<< "\n";
}
if ( atom.mergeDuplicates() != KeyValues::mergeDuplicatesDefault ) {
_out << " "
<< KeyValues::mergeDuplicatesKeyword
<< ":"
<< spacePadding(KeyValues::mergeDuplicatesKeyword)
<< KeyValues::mergeDuplicates(atom.mergeDuplicates())
<< "\n";
}
if ( atom.autoHide() != KeyValues::autoHideDefault ) {
_out << " "
<< KeyValues::autoHideKeyword
<< ":"
<< spacePadding(KeyValues::autoHideKeyword)
<< KeyValues::autoHide(atom.autoHide())
<< "\n";
}
if ( atom.isThumb() != KeyValues::isThumbDefault ) {
if ( atom.isThumb() != KeyValues::isThumbDefault ) {
_out << " "
<< KeyValues::isThumbKeyword
<< ":"
@ -142,8 +142,7 @@ public:
<< "\n";
}
if ( atom.contentType() != Atom::typeZeroFill ) {
if ( atom.contentType() != DefinedAtom::typeZeroFill ) {
_out << " "
<< KeyValues::contentKeyword
<< ":"
@ -172,6 +171,11 @@ public:
}
virtual void doUndefinedAtom(const class UndefinedAtom &atom) {
}
private:
// return a string of the correct number of spaces to align value
const char* spacePadding(const char* key) {

View File

@ -10,67 +10,59 @@ atoms:
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: true
merge: asWeak
- name: _inlineFunc2
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: true
merge: asWeak
- name: _inlineFunc3
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: false
merge: asAddressedWeak
- name: _inlineFunc4
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: false
merge: asAddressedWeak
---
atoms:
- name: _inlineFunc1
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: true
merge: asWeak
- name: _inlineFunc2
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: false
merge: asAddressedWeak
- name: _inlineFunc3
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: true
merge: asWeak
- name: _inlineFunc4
scope: global
definition: regular
type: code
merge-duplicates: true
auto-hide: false
merge: asAddressedWeak
...
# CHECK: name: _inlineFunc1
# CHECK: auto-hide: true
# CHECK: merge: asWeak
# CHECK: name: _inlineFunc3
# CHECK-NOT: auto-hide: true
# CHECK: merge: asAddressedWeak
# CHECK: name: _inlineFunc4
# CHECK-NOT: auto-hide: true
# CHECK: merge: asAddressedWeak
# CHECK: name: _inlineFunc2
# CHECK-NOT: auto-hide: true
# CHECK: merge: asAddressedWeak
# CHECK: ...

View File

@ -10,14 +10,12 @@ atoms:
internal-name: true
scope: hidden
type: c-string
merge-duplicates: true
content: [ 68, 65, 6c, 6c, 6f, 00 ]
- name: L1
internal-name: true
scope: hidden
type: c-string
merge-duplicates: true
content: [ 74, 68, 65, 72, 65, 00 ]
---
atoms:
@ -25,7 +23,6 @@ atoms:
internal-name: true
scope: hidden
type: c-string
merge-duplicates: true
content: [ 68, 65, 6c, 6c, 6f, 00 ]
---
atoms:
@ -33,7 +30,6 @@ atoms:
internal-name: true
scope: hidden
type: c-string
merge-duplicates: true
content: [ 74, 68, 65, 72, 65, 00 ]
...

View File

@ -10,25 +10,25 @@ atoms:
scope: global
definition: regular
type: code
merge-duplicates: true
merge: asWeak
---
atoms:
- name: _inlineFunc
scope: global
definition: regular
type: code
merge-duplicates: true
merge: asWeak
---
atoms:
- name: _inlineFunc
scope: global
definition: regular
type: code
merge-duplicates: true
merge: asWeak
...
# CHECK: name: _inlineFunc
# CHECK: merge-duplicates: true
# CHECK: merge: asWeak
# CHECK-NOT: name: _inlineFunc
# CHECK: ...

View File

@ -1,4 +1,4 @@
# RUN: lld-core %s 2>&1 | grep "multiply defined"
# RUN: lld-core %s 2>&1 | grep "duplicate symbol"
#
# Test that multiple definitions cause an error

View File

@ -8,7 +8,8 @@
---
atoms:
- name: _foo
definition: tentative
definition: regular
merge: asTentative
scope: global
type: zero-fill
size: 4
@ -23,4 +24,4 @@ atoms:
# CHECK: name: _foo
# CHECK-NOT: definition: tentative
# CHECK-NOT: merge: asTentative

View File

@ -7,7 +7,8 @@
---
atoms:
- name: _foo
definition: weak
definition: regular
merge: asWeak
scope: global
type: data
---
@ -19,13 +20,14 @@ atoms:
---
atoms:
- name: _foo
definition: weak
definition: regular
merge: asWeak
scope: global
type: data
...
# CHECK: name: _foo
# CHECK-NOT: definition: weak
# CHECK-NOT: merge: asWeak
# CHECK-NOT: name: _foo
# CHECK: ...

View File

@ -9,6 +9,8 @@
#include "lld/Core/InputFiles.h"
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/YamlReader.h"
#include "lld/Core/YamlWriter.h"
@ -58,17 +60,17 @@ public:
virtual void atomAdded(const Atom &file) { }
// give platform a chance to change each atom's scope
virtual void adjustScope(const Atom &atom) { }
virtual void adjustScope(const DefinedAtom &atom) { }
// if specified atom needs alternate names, return AliasAtom(s)
virtual bool getAliasAtoms(const Atom &atom,
std::vector<const Atom *>&) {
std::vector<const DefinedAtom *>&) {
return false;
}
// give platform a chance to resolve platform-specific undefs
virtual bool getPlatformAtoms(llvm::StringRef undefined,
std::vector<const Atom *>&) {
std::vector<const DefinedAtom *>&) {
return false;
}
@ -83,7 +85,7 @@ public:
}
// if target must have some atoms, denote here
virtual bool getImplicitDeadStripRoots(std::vector<const Atom *>&) {
virtual bool getImplicitDeadStripRoots(std::vector<const DefinedAtom *>&) {
return false;
}
@ -164,7 +166,18 @@ public:
handler.doFile(*this);
for (std::vector<const Atom *>::iterator it = _atoms.begin();
it != _atoms.end(); ++it) {
handler.doAtom(**it);
const Atom* atom = *it;
switch ( atom->definition() ) {
case Atom::definitionRegular:
handler.doDefinedAtom(*(DefinedAtom*)atom);
break;
case Atom::definitionUndefined:
handler.doUndefinedAtom(*(UndefinedAtom*)atom);
break;
default:
// TO DO
break;
}
}
return true;
}