diff options
| -rw-r--r-- | lld/include/lld/Core/Atom.h | 194 | ||||
| -rw-r--r-- | lld/include/lld/Core/File.h | 3 | ||||
| -rw-r--r-- | lld/include/lld/Core/UndefinedAtom.h | 16 | ||||
| -rw-r--r-- | lld/lib/Core/Atom.cpp | 11 | ||||
| -rw-r--r-- | lld/lib/Core/File.cpp | 5 | ||||
| -rw-r--r-- | lld/lib/Core/Resolver.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/Core/YamlReader.cpp | 46 |
7 files changed, 203 insertions, 76 deletions
diff --git a/lld/include/lld/Core/Atom.h b/lld/include/lld/Core/Atom.h index 50f39ec7fea..a3fb3216c66 100644 --- a/lld/include/lld/Core/Atom.h +++ b/lld/include/lld/Core/Atom.h @@ -10,6 +10,8 @@ #ifndef LLD_CORE_ATOM_H_ #define LLD_CORE_ATOM_H_ +#include <assert.h> + #include "lld/Core/Reference.h" namespace llvm { @@ -27,21 +29,85 @@ class File; /// 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, mergeDups=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, +/// mergeDups=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, mergeDups=true +/// +/// literal c-string: "hello" <br> +/// name=L0, internalName=true, type=cstring, perm=r__, +/// scope=linkageUnit, mergeDups=true +/// +/// literal double: 1.234 <br> +/// name=L0, internalName=true, type=literal8, perm=r__, +/// scope=linkageUnit, mergeDups=true +/// +/// constant: { 1,2,3 } <br> +/// name=L0, internalName=true, type=constant, perm=r__, +/// scope=linkageUnit, mergeDups=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 +/// class Atom { public: + /// The scope in which this atom is acessible to other atoms. enum Scope { - scopeTranslationUnit, // static, private to translation unit - scopeLinkageUnit, // hidden, accessible to just atoms being linked - scopeGlobal // default + 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, // usual C/C++ function or global variable - definitionWeak, // can be silently overridden by regular definition - 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 + 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 { @@ -113,13 +179,8 @@ public: uint16_t modulus; }; - // MacOSX specific compact unwind info - struct UnwindInfo { - uint32_t startOffset; - uint32_t unwindInfo; - - typedef UnwindInfo *iterator; - }; + /// file - returns the File that produced/owns this Atom + virtual const class File& file() const = 0; /// name - The name of the atom. For a function atom, it is the (mangled) /// name of the function. @@ -193,29 +254,84 @@ public: } /// permissions - Returns the OS memory protections required for this atom's - /// content at runtime. A function atom is R_X and a global variable is RW_. + /// 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; - - /// - virtual void copyRawContent(uint8_t buffer[]) 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. + 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; - bool isThumb() const { return _thumb; } - bool isAlias() const { return _alias; } - + /// 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; } - virtual const class File *file() const = 0; - virtual bool translationUnitSource(llvm::StringRef &path) const; - virtual uint64_t objectAddress() const = 0; - virtual Reference::iterator referencesBegin() const; - virtual Reference::iterator referencesEnd() const; - virtual UnwindInfo::iterator beginUnwind() const; - virtual UnwindInfo::iterator endUnwind() const; + /// 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; + } - Atom( Definition d + /// 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 @@ -224,20 +340,31 @@ public: , bool IsThumb , bool IsAlias , Alignment a) - : _alignmentModulus(a.modulus) + : _address(ord) + , _alignmentModulus(a.modulus) , _alignmentPowerOf2(a.powerOf2) , _definition(d) , _internalName(internalName) , _deadStrip(ds) + , _mode(modeOrdinal) , _thumb(IsThumb) , _alias(IsAlias) , _contentType(ct) , _scope(s) , _sectionChoice(sc) {} - virtual ~Atom(); protected: + /// 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; @@ -246,6 +373,7 @@ protected: SectionChoice _sectionChoice: 2; bool _internalName : 1; DeadStripKind _deadStrip : 2; + AddressMode _mode : 2; bool _mergeDuplicates : 1; bool _thumb : 1; bool _autoHide : 1; diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index 03d788792f2..0eaa34cc7f1 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -34,6 +34,9 @@ public: virtual bool justInTimeforEachAtom( llvm::StringRef name , AtomHandler &) const = 0; + virtual bool translationUnitSource(llvm::StringRef &path) const; + + private: llvm::StringRef _path; }; diff --git a/lld/include/lld/Core/UndefinedAtom.h b/lld/include/lld/Core/UndefinedAtom.h index 36463acb8bb..72a3edc4661 100644 --- a/lld/include/lld/Core/UndefinedAtom.h +++ b/lld/include/lld/Core/UndefinedAtom.h @@ -20,8 +20,9 @@ namespace lld { /// It exists as a place holder for a future atom. class UndefinedAtom : public Atom { public: - UndefinedAtom(llvm::StringRef nm) - : Atom( Atom::definitionUndefined + UndefinedAtom(llvm::StringRef nm, const File& f) + : Atom( 0, + Atom::definitionUndefined , Atom::scopeLinkageUnit , Atom::typeUnknown , Atom::sectionBasedOnContent @@ -30,15 +31,11 @@ public: , false , false , Atom::Alignment(0)) - , _name(nm) {} + , _name(nm), _file(f) {} // overrides of Atom - virtual const File *file() const { - return 0; - } - - virtual bool translationUnitSource(llvm::StringRef path) const { - return false; + virtual const File& file() const { + return _file; } virtual llvm::StringRef name() const { @@ -58,6 +55,7 @@ protected: virtual ~UndefinedAtom() {} llvm::StringRef _name; + const File& _file; }; } // namespace lld diff --git a/lld/lib/Core/Atom.cpp b/lld/lib/Core/Atom.cpp index 889ec096e32..29aa1c805fa 100644 --- a/lld/lib/Core/Atom.cpp +++ b/lld/lib/Core/Atom.cpp @@ -16,10 +16,6 @@ namespace lld { Atom::~Atom() {} - bool Atom::translationUnitSource(llvm::StringRef &path) const { - return false; - } - llvm::StringRef Atom::name() const { return llvm::StringRef(); } @@ -44,12 +40,5 @@ namespace lld { return 0; } - Atom::UnwindInfo::iterator Atom::beginUnwind() const{ - return 0; - } - - Atom::UnwindInfo::iterator Atom::endUnwind() const{ - return 0; - } } // namespace lld diff --git a/lld/lib/Core/File.cpp b/lld/lib/Core/File.cpp index e123d5ec192..09c3f8aba7b 100644 --- a/lld/lib/Core/File.cpp +++ b/lld/lib/Core/File.cpp @@ -13,4 +13,9 @@ namespace lld { File::~File() {} +bool File::translationUnitSource(llvm::StringRef &path) const { + return false; +} + + } diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index b3be26bf188..c3b83756e1b 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -183,14 +183,14 @@ void Resolver::updateReferences() { void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) { // if -why_live cares about this symbol, then dump chain if ((previous->referer != NULL) && _platform.printWhyLive(atom.name())) { - llvm::errs() << atom.name() << " from " << atom.file()->path() << "\n"; + llvm::errs() << atom.name() << " from " << atom.file().path() << "\n"; int depth = 1; for (WhyLiveBackChain *p = previous; p != NULL; p = p->previous, ++depth) { for (int i = depth; i > 0; --i) llvm::errs() << " "; llvm::errs() << p->referer->name() << " from " - << p->referer->file()->path() << "\n"; + << p->referer->file().path() << "\n"; } } diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp index c95e061931c..6250939b8a7 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/Core/YamlReader.cpp @@ -238,7 +238,8 @@ bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name, class YAMLAtom : public Atom { public: - YAMLAtom( Definition d + YAMLAtom( uint64_t ord + , Definition d , Scope s , ContentType ct , SectionChoice sc @@ -247,18 +248,18 @@ public: , bool tb , bool al , Alignment a - , YAMLFile *f + , YAMLFile& f , const char *n) - : Atom(d, s, ct, sc, intn, dsk, tb, al, a) + : Atom(ord, d, s, ct, sc, intn, dsk, tb, al, a) , _file(f) , _name(n) , _size(0) - , _refStartIndex(f->_lastRefIndex) - , _refEndIndex(f->_references.size()) { - f->_lastRefIndex = _refEndIndex; + , _refStartIndex(f._lastRefIndex) + , _refEndIndex(f._references.size()) { + f._lastRefIndex = _refEndIndex; } - virtual const class File *file() const { + virtual const class File& file() const { return _file; } @@ -282,7 +283,7 @@ public: virtual Reference::iterator referencesBegin() const; virtual Reference::iterator referencesEnd() const; private: - YAMLFile *_file; + YAMLFile& _file; const char *_name; unsigned long _size; unsigned int _refStartIndex; @@ -290,14 +291,14 @@ private: }; Reference::iterator YAMLAtom::referencesBegin() const { - if (_file->_references.size() < _refStartIndex) - return (Reference::iterator)&_file->_references[_refStartIndex]; + 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]; + if (_file._references.size() < _refEndIndex) + return (Reference::iterator)&_file._references[_refEndIndex]; return 0; } @@ -316,9 +317,10 @@ public: void setFixupTarget(const char *n); void addFixup(YAMLFile *f); - void makeAtom(YAMLFile *); + void makeAtom(YAMLFile&); private: + uint64_t _ordinal; const char *_name; Atom::Alignment _align; Atom::ContentType _type; @@ -334,7 +336,8 @@ private: }; YAMLAtomState::YAMLAtomState() - : _name(NULL) + : _ordinal(0) + , _name(NULL) , _align(0, 0) , _type(Atom::typeData) , _scope(Atom::scopeGlobal) @@ -349,13 +352,14 @@ YAMLAtomState::YAMLAtomState() _ref.flags = 0; } -void YAMLAtomState::makeAtom(YAMLFile *f) { - Atom *a = new YAMLAtom(_def, _scope, _type, _sectionChoice, +void YAMLAtomState::makeAtom(YAMLFile& f) { + Atom *a = new YAMLAtom(_ordinal, _def, _scope, _type, _sectionChoice, _internalName, _dontDeadStrip, _thumb, _alias, _align, f, _name); - f->_atoms.push_back(a); - + f._atoms.push_back(a); + ++_ordinal; + // reset state for next atom _name = NULL; _align.powerOf2 = 0; @@ -472,7 +476,7 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb if (entry->beginDocument) { if (file != NULL) { if (haveAtom) { - atomState.makeAtom(file); + atomState.makeAtom(*file); haveAtom = false; } result.push_back(file); @@ -502,7 +506,7 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb if (depthForAtoms == entry->depth) { if (entry->beginSequence) { if (haveAtom) { - atomState.makeAtom(file); + atomState.makeAtom(*file); haveAtom = false; } } @@ -546,7 +550,7 @@ llvm::error_code parseObjectText( llvm::MemoryBuffer *mb lastDepth = entry->depth; } if (haveAtom) { - atomState.makeAtom(file); + atomState.makeAtom(*file); } result.push_back(file); |

