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
diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h
index b413cdd..df5efee 100644
--- a/lld/include/lld/Core/Atom.h
+++ b/lld/include/lld/Core/Atom.h
@@ -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 @@
/// 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
diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h
new file mode 100644
index 0000000..c151325
--- /dev/null
+++ b/lld/include/lld/Core/DefinedAtom.h
@@ -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_
diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h
index 0eaa34c..b2f3601 100644
--- a/lld/include/lld/Core/File.h
+++ b/lld/include/lld/Core/File.h
@@ -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 @@
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;
};
diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h
index 33a5479..1bb2abe 100644
--- a/lld/include/lld/Core/Resolver.h
+++ b/lld/include/lld/Core/Resolver.h
@@ -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 @@
, _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 @@
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 @@
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;
diff --git a/lld/include/lld/Core/SymbolTable.h b/lld/include/lld/Core/SymbolTable.h
index 9888fa4..54202b7 100644
--- a/lld/include/lld/Core/SymbolTable.h
+++ b/lld/include/lld/Core/SymbolTable.h
@@ -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 @@
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 @@
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;
diff --git a/lld/include/lld/Core/UndefinedAtom.h b/lld/include/lld/Core/UndefinedAtom.h
index 8924d76..11817b3 100644
--- a/lld/include/lld/Core/UndefinedAtom.h
+++ b/lld/include/lld/Core/UndefinedAtom.h
@@ -20,22 +20,9 @@
/// 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 @@
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
diff --git a/lld/include/lld/Platform/Platform.h b/lld/include/lld/Platform/Platform.h
index c95c936..2f3634b 100644
--- a/lld/include/lld/Platform/Platform.h
+++ b/lld/include/lld/Platform/Platform.h
@@ -14,6 +14,7 @@
namespace lld {
class Atom;
+class DefinedAtom;
/// The Platform class encapsulated plaform specific linking knowledge.
///
@@ -29,15 +30,15 @@
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 @@
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;
diff --git a/lld/lib/Core/Atom.cpp b/lld/lib/Core/Atom.cpp
deleted file mode 100644
index 29aa1c8..0000000
--- a/lld/lib/Core/Atom.cpp
+++ /dev/null
@@ -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
diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt
index aa08637..eca024c 100644
--- a/lld/lib/Core/CMakeLists.txt
+++ b/lld/lib/Core/CMakeLists.txt
@@ -1,5 +1,4 @@
add_lld_library(lldCore
- Atom.cpp
File.cpp
Resolver.cpp
SymbolTable.cpp
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
index c3b8375..51f6a48 100644
--- a/lld/lib/Core/Resolver.cpp
+++ b/lld/lib/Core/Resolver.cpp
@@ -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 @@
SymbolTable &_symbolTable;
};
+
+
+
void Resolver::initializeState() {
_platform.initialize();
}
@@ -68,24 +89,34 @@
_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 @@
}
// 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 @@
// 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 @@
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 @@
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::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 @@
}
// 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 @@
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 @@
}
// 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 @@
// 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 @@
// 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::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);
}
}
diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp
index 7407738..f964fd8 100644
--- a/lld/lib/Core/SymbolTable.cpp
+++ b/lld/lib/Core/SymbolTable.cpp
@@ -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 @@
: _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 @@
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 @@
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 @@
// 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 @@
}
-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 @@
}
-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 @@
}
-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);
diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp
index 47729d6..4158e6d 100644
--- a/lld/lib/Core/YamlKeyValues.cpp
+++ b/lld/lib/Core/YamlKeyValues.cpp
@@ -18,61 +18,33 @@
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 @@
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 @@
+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 @@
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 @@
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 @@
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 @@
+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 @@
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 @@
+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 @@
-
-
-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 )
diff --git a/lld/lib/Core/YamlKeyValues.h b/lld/lib/Core/YamlKeyValues.h
index c8890bd..b38a26c 100644
--- a/lld/lib/Core/YamlKeyValues.h
+++ b/lld/lib/Core/YamlKeyValues.h
@@ -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 @@
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);
};
diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp
index 8fe7d50..5ca8fbc 100644
--- a/lld/lib/Core/YamlReader.cpp
+++ b/lld/lib/Core/YamlReader.cpp
@@ -289,16 +289,17 @@
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 @@
}
-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;
- virtual Reference::iterator referencesEnd() const;
+ 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;
+ }
+
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 @@
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 @@
_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 @@
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 @@
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 @@
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) {
diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp
index 5b01582..3e30c0a 100644
--- a/lld/lib/Core/YamlWriter.cpp
+++ b/lld/lib/Core/YamlWriter.cpp
@@ -32,7 +32,7 @@
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 @@
<< "\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 @@
<< "\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 @@
<< "\n";
}
-
- if ( atom.contentType() != Atom::typeZeroFill ) {
+ if ( atom.contentType() != DefinedAtom::typeZeroFill ) {
_out << " "
<< KeyValues::contentKeyword
<< ":"
@@ -172,6 +171,11 @@
}
+ 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) {
diff --git a/lld/test/auto-hide-coalesce.objtxt b/lld/test/auto-hide-coalesce.objtxt
index 7ee5638..5471809 100644
--- a/lld/test/auto-hide-coalesce.objtxt
+++ b/lld/test/auto-hide-coalesce.objtxt
@@ -10,67 +10,59 @@
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: ...
diff --git a/lld/test/cstring-coalesce.objtxt b/lld/test/cstring-coalesce.objtxt
index 70ee883..205af37 100644
--- a/lld/test/cstring-coalesce.objtxt
+++ b/lld/test/cstring-coalesce.objtxt
@@ -10,14 +10,12 @@
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 @@
internal-name: true
scope: hidden
type: c-string
- merge-duplicates: true
content: [ 68, 65, 6c, 6c, 6f, 00 ]
---
atoms:
@@ -33,7 +30,6 @@
internal-name: true
scope: hidden
type: c-string
- merge-duplicates: true
content: [ 74, 68, 65, 72, 65, 00 ]
...
diff --git a/lld/test/inline-coalesce.objtxt b/lld/test/inline-coalesce.objtxt
index 3974198..edd7f47 100644
--- a/lld/test/inline-coalesce.objtxt
+++ b/lld/test/inline-coalesce.objtxt
@@ -10,25 +10,25 @@
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: ...
diff --git a/lld/test/multiple-def-error.objtxt b/lld/test/multiple-def-error.objtxt
index e57a017..068e257 100644
--- a/lld/test/multiple-def-error.objtxt
+++ b/lld/test/multiple-def-error.objtxt
@@ -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
diff --git a/lld/test/tent-merge.objtxt b/lld/test/tent-merge.objtxt
index bb8573e..4872b16 100644
--- a/lld/test/tent-merge.objtxt
+++ b/lld/test/tent-merge.objtxt
@@ -8,7 +8,8 @@
---
atoms:
- name: _foo
- definition: tentative
+ definition: regular
+ merge: asTentative
scope: global
type: zero-fill
size: 4
@@ -23,4 +24,4 @@
# CHECK: name: _foo
-# CHECK-NOT: definition: tentative
+# CHECK-NOT: merge: asTentative
diff --git a/lld/test/weak-coalesce.objtxt b/lld/test/weak-coalesce.objtxt
index f3640ce..48f088c 100644
--- a/lld/test/weak-coalesce.objtxt
+++ b/lld/test/weak-coalesce.objtxt
@@ -7,7 +7,8 @@
---
atoms:
- name: _foo
- definition: weak
+ definition: regular
+ merge: asWeak
scope: global
type: data
---
@@ -19,13 +20,14 @@
---
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: ...
diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp
index 921bab9..3bd35c2 100644
--- a/lld/tools/lld-core/lld-core.cpp
+++ b/lld/tools/lld-core/lld-core.cpp
@@ -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 @@
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 @@
}
// 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 @@
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;
}