diff options
-rw-r--r-- | lld/include/lld/Core/Atom.h | 352 | ||||
-rw-r--r-- | lld/include/lld/Core/DefinedAtom.h | 287 | ||||
-rw-r--r-- | lld/include/lld/Core/File.h | 6 | ||||
-rw-r--r-- | lld/include/lld/Core/Resolver.h | 10 | ||||
-rw-r--r-- | lld/include/lld/Core/SymbolTable.h | 20 | ||||
-rw-r--r-- | lld/include/lld/Core/UndefinedAtom.h | 31 | ||||
-rw-r--r-- | lld/include/lld/Platform/Platform.h | 9 | ||||
-rw-r--r-- | lld/lib/Core/Atom.cpp | 44 | ||||
-rw-r--r-- | lld/lib/Core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/Core/Resolver.cpp | 115 | ||||
-rw-r--r-- | lld/lib/Core/SymbolTable.cpp | 128 | ||||
-rw-r--r-- | lld/lib/Core/YamlKeyValues.cpp | 304 | ||||
-rw-r--r-- | lld/lib/Core/YamlKeyValues.h | 111 | ||||
-rw-r--r-- | lld/lib/Core/YamlReader.cpp | 307 | ||||
-rw-r--r-- | lld/lib/Core/YamlWriter.cpp | 48 | ||||
-rw-r--r-- | lld/test/auto-hide-coalesce.objtxt | 32 | ||||
-rw-r--r-- | lld/test/cstring-coalesce.objtxt | 4 | ||||
-rw-r--r-- | lld/test/inline-coalesce.objtxt | 8 | ||||
-rw-r--r-- | lld/test/multiple-def-error.objtxt | 2 | ||||
-rw-r--r-- | lld/test/tent-merge.objtxt | 5 | ||||
-rw-r--r-- | lld/test/weak-coalesce.objtxt | 8 | ||||
-rw-r--r-- | lld/tools/lld-core/lld-core.cpp | 23 |
22 files changed, 1001 insertions, 854 deletions
diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h index b413cdd2714..df5efeedbd8 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 @@ 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; - } - - /// 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; - } - - /// 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; - } + /// symbol. + virtual Definition definition() const = 0; - /// setSectionOffset - assigns an offset within a section in the final - /// linked image. - void setFinalAddress(uint64_t addr) { - assert(_mode == modeSectionOffset); - _address = addr; - _mode = modeFinalAddress; - } + /// definedAtom - like dynamic_cast, if atom is definitionRegular + /// returns atom cast to DefinedAtom*, else returns NULL; + virtual const DefinedAtom* definedAtom() const { return NULL; } - /// 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 00000000000..c151325cdcf --- /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 0eaa34cc7f1..b2f360149b4 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 @@ 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; }; diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h index 33a54799601..1bb2abea522 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 @@ 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; diff --git a/lld/include/lld/Core/SymbolTable.h b/lld/include/lld/Core/SymbolTable.h index 9888fa4414c..54202b7c87d 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 @@ 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; diff --git a/lld/include/lld/Core/UndefinedAtom.h b/lld/include/lld/Core/UndefinedAtom.h index 8924d768d5a..11817b380db 100644 --- a/lld/include/lld/Core/UndefinedAtom.h +++ b/lld/include/lld/Core/UndefinedAtom.h @@ -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 diff --git a/lld/include/lld/Platform/Platform.h b/lld/include/lld/Platform/Platform.h index c95c936ad52..2f3634b4b69 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 @@ 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; diff --git a/lld/lib/Core/Atom.cpp b/lld/lib/Core/Atom.cpp deleted file mode 100644 index 29aa1c805fa..00000000000 --- 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 aa08637db0f..eca024cf231 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 c3b83756e1b..51f6a481a65 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 @@ 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); } } diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp index 740773843cd..f964fd8acf9 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 @@ 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(); - } - else { - // They have same autoHide, so just keep using existing - useNew = false; + 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 { - 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); diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp index 47729d684d8..4158e6d4e51 100644 --- a/lld/lib/Core/YamlKeyValues.cpp +++ b/lld/lib/Core/YamlKeyValues.cpp @@ -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,34 +209,33 @@ const char* KeyValues::deadStripKind(Atom::DeadStripKind dsk) { - -struct SectionChoiceMapping { +struct InterposableMapping { const char* string; - Atom::SectionChoice value; + DefinedAtom::Interposable value; }; -static const SectionChoiceMapping sectMappings[] = { - { "content", Atom::sectionBasedOnContent }, - { "custom", Atom::sectionCustomPreferred }, - { "custom-required", Atom::sectionCustomRequired }, - { NULL, Atom::sectionBasedOnContent } +static const InterposableMapping interMappings[] = { + { "no", DefinedAtom::interposeNo }, + { "yes", DefinedAtom::interposeYes }, + { "yesAndWeak", DefinedAtom::interposeYesAndRuntimeWeak }, + { NULL, DefinedAtom::interposeNo } }; -Atom::SectionChoice KeyValues::sectionChoice(const char* s) +DefinedAtom::Interposable KeyValues::interposable(const char* s) { - for (const SectionChoiceMapping* p = sectMappings; p->string != NULL; ++p) { + for (const InterposableMapping* p = interMappings; p->string != NULL; ++p) { if ( strcmp(p->string, s) == 0 ) return p->value; } - llvm::report_fatal_error("bad dead strip value"); + llvm::report_fatal_error("bad interposable value"); } -const char* KeyValues::sectionChoice(Atom::SectionChoice s) { - for (const SectionChoiceMapping* p = sectMappings; p->string != NULL; ++p) { - if ( p->value == s ) +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 dead strip value"); + llvm::report_fatal_error("bad interposable value"); } @@ -238,18 +243,34 @@ const char* KeyValues::sectionChoice(Atom::SectionChoice s) { +struct MergeMapping { + const char* string; + DefinedAtom::Merge value; +}; -bool KeyValues::internalName(const char* s) +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) { - if ( strcmp(s, "true") == 0 ) - return true; - else if ( strcmp(s, "false") == 0 ) - return false; - llvm::report_fatal_error("bad internal-name value"); + 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::internalName(bool b) { - return b ? "true" : "false"; +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"); } @@ -257,17 +278,33 @@ const char* KeyValues::internalName(bool b) { -bool KeyValues::mergeDuplicates(const char* s) +struct SectionChoiceMapping { + const char* string; + DefinedAtom::SectionChoice value; +}; + +static const SectionChoiceMapping sectMappings[] = { + { "content", DefinedAtom::sectionBasedOnContent }, + { "custom", DefinedAtom::sectionCustomPreferred }, + { "custom-required", DefinedAtom::sectionCustomRequired }, + { NULL, DefinedAtom::sectionBasedOnContent } +}; + +DefinedAtom::SectionChoice KeyValues::sectionChoice(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"); + for (const SectionChoiceMapping* p = sectMappings; p->string != NULL; ++p) { + if ( strcmp(p->string, s) == 0 ) + return p->value; + } + llvm::report_fatal_error("bad dead strip value"); } -const char* KeyValues::mergeDuplicates(bool b) { - return b ? "true" : "false"; +const char* KeyValues::sectionChoice(DefinedAtom::SectionChoice s) { + for (const SectionChoiceMapping* p = sectMappings; p->string != NULL; ++p) { + if ( p->value == s ) + return p->string; + } + llvm::report_fatal_error("bad dead strip value"); } @@ -275,23 +312,60 @@ const char* KeyValues::mergeDuplicates(bool b) { -bool KeyValues::autoHide(const char* 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 ) return true; else if ( strcmp(s, "false") == 0 ) return false; - llvm::report_fatal_error("bad auto-hide value"); + llvm::report_fatal_error("bad internal-name value"); } -const char* KeyValues::autoHide(bool b) { +const char* KeyValues::internalName(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 c8890bd8f1e..b38a26cfaf3 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 @@ 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 scopeKeyword; - static const Atom::Scope scopeDefault; - static Atom::Scope scope(const char*); - static const char* scope(Atom::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 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 Atom::ContentType contentTypeDefault; - static Atom::ContentType contentType(const char*); - static const char* contentType(Atom::ContentType); - - 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 Atom::SectionChoice sectionChoiceDefault; - static Atom::SectionChoice sectionChoice(const char*); - static const char* sectionChoice(Atom::SectionChoice); - - static const char* const internalNameKeyword; - static const bool internalNameDefault; - static bool internalName(const char*); - static const char* internalName(bool); - - static const char* const mergeDuplicatesKeyword; - static const bool mergeDuplicatesDefault; - static bool mergeDuplicates(const char*); - static const char* mergeDuplicates(bool); - - static const char* const autoHideKeyword; - static const bool autoHideDefault; - static bool autoHide(const char*); - static const char* autoHide(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 contentTypeKeyword; + static const DefinedAtom::ContentType contentTypeDefault; + static DefinedAtom::ContentType contentType(const char*); + static const char* contentType(DefinedAtom::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 sectionChoiceKeyword; + static const DefinedAtom::SectionChoice sectionChoiceDefault; + static DefinedAtom::SectionChoice sectionChoice(const char*); + static const char* sectionChoice(DefinedAtom::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 mergeKeyword; + static const DefinedAtom::Merge mergeDefault; + static DefinedAtom::Merge merge(const char*); + static const char* merge(DefinedAtom::Merge); + + 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 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 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 8fe7d507c6b..5ca8fbc8103 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/Core/YamlReader.cpp @@ -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 size() const { + return (_content ? _content->size() : _size); } - virtual uint64_t objectAddress() const { - return 0; + virtual DefinedAtom::Scope scope() const { + return _scope; + } + + virtual DefinedAtom::Interposable interposable() const { + return _interpose; + } + + virtual DefinedAtom::Merge merge() const { + return _merge; } - virtual uint64_t size() const { - return (_content ? _content->size() : _size); + virtual DefinedAtom::ContentType contentType() const { + return _type; + } + + virtual DefinedAtom::Alignment alignment() const { + return _alignment; + } + + virtual DefinedAtom::SectionChoice sectionChoice() const { + return _sectionChoice; } - llvm::ArrayRef<uint8_t> rawContent() const { + 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) + : _name(NULL) + , _sectionName(NULL) , _size(0) - , _name(NULL) - , _align(0, 0) - , _type(KeyValues::contentTypeDefault) + , _ordinal(0) + , _content(NULL) + , _alignment(0, 0) + , _definition(KeyValues::definitionDefault) , _scope(KeyValues::scopeDefault) - , _def(KeyValues::definitionDefault) + , _type(KeyValues::contentTypeDefault) , _sectionChoice(KeyValues::sectionChoiceDefault) - , _internalName(KeyValues::internalNameDefault) - , _mergeDuplicates(KeyValues::mergeDuplicatesDefault) + , _interpose(KeyValues::interposableDefault) + , _merge(KeyValues::mergeDefault) , _deadStrip(KeyValues::deadStripKindDefault) - , _thumb(KeyValues::isThumbDefault) - , _alias(KeyValues::isAliasDefault) - , _autoHide(KeyValues::autoHideDefault) - , _sectionName(NULL) - , _content(NULL) { + , _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; + _sectionName = NULL; + _size = 0; + _ordinal = 0; + _content = NULL; + _alignment.powerOf2= 0; + _alignment.modulus = 0; + _definition = KeyValues::definitionDefault; _scope = KeyValues::scopeDefault; - _def = KeyValues::definitionDefault; + _type = KeyValues::contentTypeDefault; _sectionChoice = KeyValues::sectionChoiceDefault; - _internalName = KeyValues::internalNameDefault; - _mergeDuplicates = KeyValues::mergeDuplicatesDefault; + _interpose = KeyValues::interposableDefault; + _merge = KeyValues::mergeDefault; _deadStrip = KeyValues::deadStripKindDefault; - _thumb = KeyValues::isThumbDefault; - _alias = KeyValues::isAliasDefault; - _autoHide = KeyValues::autoHideDefault; - _sectionName = NULL; - _content = NULL; + _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) { diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp index 5b015825d11..3e30c0a4260 100644 --- a/lld/lib/Core/YamlWriter.cpp +++ b/lld/lib/Core/YamlWriter.cpp @@ -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) { diff --git a/lld/test/auto-hide-coalesce.objtxt b/lld/test/auto-hide-coalesce.objtxt index 7ee563867cc..5471809491b 100644 --- a/lld/test/auto-hide-coalesce.objtxt +++ b/lld/test/auto-hide-coalesce.objtxt @@ -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: ... diff --git a/lld/test/cstring-coalesce.objtxt b/lld/test/cstring-coalesce.objtxt index 70ee8830868..205af3721e9 100644 --- a/lld/test/cstring-coalesce.objtxt +++ b/lld/test/cstring-coalesce.objtxt @@ -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 ] ... diff --git a/lld/test/inline-coalesce.objtxt b/lld/test/inline-coalesce.objtxt index 3974198077c..edd7f471f42 100644 --- a/lld/test/inline-coalesce.objtxt +++ b/lld/test/inline-coalesce.objtxt @@ -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: ... diff --git a/lld/test/multiple-def-error.objtxt b/lld/test/multiple-def-error.objtxt index e57a017f163..068e257cdd2 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 bb8573e6b6d..4872b163ee6 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 @@ atoms: # 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 f3640cee90c..48f088c2670 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: --- 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 921bab913e4..3bd35c2538f 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 @@ 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; } |