| //===- MCSymbol.h - Machine Code Symbols ------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains the declaration of the MCSymbol class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_MC_MCSYMBOL_H |
| #define LLVM_MC_MCSYMBOL_H |
| |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/ADT/StringMapEntry.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/MC/MCExpr.h" |
| #include "llvm/MC/MCFragment.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/MathExtras.h" |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| |
| namespace llvm { |
| |
| class MCAsmInfo; |
| class MCContext; |
| class MCSection; |
| class raw_ostream; |
| |
| /// MCSymbol - Instances of this class represent a symbol name in the MC file, |
| /// and MCSymbols are created and uniqued by the MCContext class. MCSymbols |
| /// should only be constructed with valid names for the object file. |
| /// |
| /// If the symbol is defined/emitted into the current translation unit, the |
| /// Section member is set to indicate what section it lives in. Otherwise, if |
| /// it is a reference to an external entity, it has a null section. |
| class MCSymbol { |
| protected: |
| /// The kind of the symbol. If it is any value other than unset then this |
| /// class is actually one of the appropriate subclasses of MCSymbol. |
| enum SymbolKind { |
| SymbolKindUnset, |
| SymbolKindCOFF, |
| SymbolKindELF, |
| SymbolKindGOFF, |
| SymbolKindMachO, |
| SymbolKindWasm, |
| SymbolKindXCOFF, |
| }; |
| |
| /// A symbol can contain an Offset, or Value, or be Common, but never more |
| /// than one of these. |
| enum Contents : uint8_t { |
| SymContentsUnset, |
| SymContentsOffset, |
| SymContentsVariable, |
| SymContentsCommon, |
| SymContentsTargetCommon, // Index stores the section index |
| }; |
| |
| // Special sentinal value for the absolute pseudo fragment. |
| static MCFragment *AbsolutePseudoFragment; |
| |
| /// If a symbol has a Fragment, the section is implied, so we only need |
| /// one pointer. |
| /// The special AbsolutePseudoFragment value is for absolute symbols. |
| /// If this is a variable symbol, this caches the variable value's fragment. |
| /// FIXME: We might be able to simplify this by having the asm streamer create |
| /// dummy fragments. |
| /// If this is a section, then it gives the symbol is defined in. This is null |
| /// for undefined symbols. |
| /// |
| /// If this is a fragment, then it gives the fragment this symbol's value is |
| /// relative to, if any. |
| /// |
| /// For the 'HasName' integer, this is true if this symbol is named. |
| /// A named symbol will have a pointer to the name allocated in the bytes |
| /// immediately prior to the MCSymbol. |
| mutable PointerIntPair<MCFragment *, 1> FragmentAndHasName; |
| |
| /// IsTemporary - True if this is an assembler temporary label, which |
| /// typically does not survive in the .o file's symbol table. Usually |
| /// "Lfoo" or ".foo". |
| unsigned IsTemporary : 1; |
| |
| /// True if this symbol can be redefined. |
| unsigned IsRedefinable : 1; |
| |
| /// IsUsed - True if this symbol has been used. |
| mutable unsigned IsUsed : 1; |
| |
| mutable unsigned IsRegistered : 1; |
| |
| /// True if this symbol is visible outside this translation unit. Note: ELF |
| /// uses binding instead of this bit. |
| mutable unsigned IsExternal : 1; |
| |
| /// This symbol is private extern. |
| mutable unsigned IsPrivateExtern : 1; |
| |
| /// LLVM RTTI discriminator. This is actually a SymbolKind enumerator, but is |
| /// unsigned to avoid sign extension and achieve better bitpacking with MSVC. |
| unsigned Kind : 3; |
| |
| /// True if we have created a relocation that uses this symbol. |
| mutable unsigned IsUsedInReloc : 1; |
| |
| /// This is actually a Contents enumerator, but is unsigned to avoid sign |
| /// extension and achieve better bitpacking with MSVC. |
| unsigned SymbolContents : 3; |
| |
| /// The alignment of the symbol if it is 'common'. |
| /// |
| /// Internally, this is stored as log2(align) + 1. |
| /// We reserve 5 bits to encode this value which allows the following values |
| /// 0b00000 -> unset |
| /// 0b00001 -> 1ULL << 0 = 1 |
| /// 0b00010 -> 1ULL << 1 = 2 |
| /// 0b00011 -> 1ULL << 2 = 4 |
| /// ... |
| /// 0b11111 -> 1ULL << 30 = 1 GiB |
| enum : unsigned { NumCommonAlignmentBits = 5 }; |
| unsigned CommonAlignLog2 : NumCommonAlignmentBits; |
| |
| /// The Flags field is used by object file implementations to store |
| /// additional per symbol information which is not easily classified. |
| enum : unsigned { NumFlagsBits = 16 }; |
| mutable uint32_t Flags : NumFlagsBits; |
| |
| /// Index field, for use by the object file implementation. |
| mutable uint32_t Index = 0; |
| |
| union { |
| /// The offset to apply to the fragment address to form this symbol's value. |
| uint64_t Offset; |
| |
| /// The size of the symbol, if it is 'common'. |
| uint64_t CommonSize; |
| |
| /// If non-null, the value for a variable symbol. |
| const MCExpr *Value; |
| }; |
| |
| // MCContext creates and uniques these. |
| friend class MCExpr; |
| friend class MCContext; |
| |
| /// The name for a symbol. |
| /// MCSymbol contains a uint64_t so is probably aligned to 8. On a 32-bit |
| /// system, the name is a pointer so isn't going to satisfy the 8 byte |
| /// alignment of uint64_t. Account for that here. |
| using NameEntryStorageTy = union { |
| const StringMapEntry<bool> *NameEntry; |
| uint64_t AlignmentPadding; |
| }; |
| |
| MCSymbol(SymbolKind Kind, const StringMapEntry<bool> *Name, bool isTemporary) |
| : IsTemporary(isTemporary), IsRedefinable(false), IsUsed(false), |
| IsRegistered(false), IsExternal(false), IsPrivateExtern(false), |
| Kind(Kind), IsUsedInReloc(false), SymbolContents(SymContentsUnset), |
| CommonAlignLog2(0), Flags(0) { |
| Offset = 0; |
| FragmentAndHasName.setInt(!!Name); |
| if (Name) |
| getNameEntryPtr() = Name; |
| } |
| |
| // Provide custom new/delete as we will only allocate space for a name |
| // if we need one. |
| void *operator new(size_t s, const StringMapEntry<bool> *Name, |
| MCContext &Ctx); |
| |
| private: |
| void operator delete(void *); |
| /// Placement delete - required by std, but never called. |
| void operator delete(void*, unsigned) { |
| llvm_unreachable("Constructor throws?"); |
| } |
| /// Placement delete - required by std, but never called. |
| void operator delete(void*, unsigned, bool) { |
| llvm_unreachable("Constructor throws?"); |
| } |
| |
| /// Get a reference to the name field. Requires that we have a name |
| const StringMapEntry<bool> *&getNameEntryPtr() { |
| assert(FragmentAndHasName.getInt() && "Name is required"); |
| NameEntryStorageTy *Name = reinterpret_cast<NameEntryStorageTy *>(this); |
| return (*(Name - 1)).NameEntry; |
| } |
| const StringMapEntry<bool> *&getNameEntryPtr() const { |
| return const_cast<MCSymbol*>(this)->getNameEntryPtr(); |
| } |
| |
| public: |
| MCSymbol(const MCSymbol &) = delete; |
| MCSymbol &operator=(const MCSymbol &) = delete; |
| |
| /// getName - Get the symbol name. |
| StringRef getName() const { |
| if (!FragmentAndHasName.getInt()) |
| return StringRef(); |
| |
| return getNameEntryPtr()->first(); |
| } |
| |
| bool isRegistered() const { return IsRegistered; } |
| void setIsRegistered(bool Value) const { IsRegistered = Value; } |
| |
| void setUsedInReloc() const { IsUsedInReloc = true; } |
| bool isUsedInReloc() const { return IsUsedInReloc; } |
| |
| /// \name Accessors |
| /// @{ |
| |
| /// isTemporary - Check if this is an assembler temporary symbol. |
| bool isTemporary() const { return IsTemporary; } |
| |
| /// isUsed - Check if this is used. |
| bool isUsed() const { return IsUsed; } |
| |
| /// Check if this symbol is redefinable. |
| bool isRedefinable() const { return IsRedefinable; } |
| /// Mark this symbol as redefinable. |
| void setRedefinable(bool Value) { IsRedefinable = Value; } |
| /// Prepare this symbol to be redefined. |
| void redefineIfPossible() { |
| if (IsRedefinable) { |
| if (SymbolContents == SymContentsVariable) { |
| Value = nullptr; |
| SymbolContents = SymContentsUnset; |
| } |
| setUndefined(); |
| IsRedefinable = false; |
| } |
| } |
| |
| /// @} |
| /// \name Associated Sections |
| /// @{ |
| |
| /// isDefined - Check if this symbol is defined (i.e., it has an address). |
| /// |
| /// Defined symbols are either absolute or in some section. |
| bool isDefined() const { return !isUndefined(); } |
| |
| /// isInSection - Check if this symbol is defined in some section (i.e., it |
| /// is defined but not absolute). |
| bool isInSection() const { |
| return isDefined() && !isAbsolute(); |
| } |
| |
| /// isUndefined - Check if this symbol undefined (i.e., implicitly defined). |
| bool isUndefined(bool SetUsed = true) const { |
| return getFragment(SetUsed) == nullptr; |
| } |
| |
| /// isAbsolute - Check if this is an absolute symbol. |
| bool isAbsolute() const { |
| return getFragment() == AbsolutePseudoFragment; |
| } |
| |
| /// Get the section associated with a defined, non-absolute symbol. |
| MCSection &getSection() const { |
| assert(isInSection() && "Invalid accessor!"); |
| return *getFragment()->getParent(); |
| } |
| |
| /// Mark the symbol as defined in the fragment \p F. |
| void setFragment(MCFragment *F) const { |
| assert(!isVariable() && "Cannot set fragment of variable"); |
| FragmentAndHasName.setPointer(F); |
| } |
| |
| /// Mark the symbol as undefined. |
| void setUndefined() { FragmentAndHasName.setPointer(nullptr); } |
| |
| bool isELF() const { return Kind == SymbolKindELF; } |
| |
| bool isCOFF() const { return Kind == SymbolKindCOFF; } |
| |
| bool isGOFF() const { return Kind == SymbolKindGOFF; } |
| |
| bool isMachO() const { return Kind == SymbolKindMachO; } |
| |
| bool isWasm() const { return Kind == SymbolKindWasm; } |
| |
| bool isXCOFF() const { return Kind == SymbolKindXCOFF; } |
| |
| /// @} |
| /// \name Variable Symbols |
| /// @{ |
| |
| /// isVariable - Check if this is a variable symbol. |
| bool isVariable() const { |
| return SymbolContents == SymContentsVariable; |
| } |
| |
| /// getVariableValue - Get the value for variable symbols. |
| const MCExpr *getVariableValue(bool SetUsed = true) const { |
| assert(isVariable() && "Invalid accessor!"); |
| IsUsed |= SetUsed; |
| return Value; |
| } |
| |
| void setVariableValue(const MCExpr *Value); |
| |
| /// @} |
| |
| /// Get the (implementation defined) index. |
| uint32_t getIndex() const { |
| return Index; |
| } |
| |
| /// Set the (implementation defined) index. |
| void setIndex(uint32_t Value) const { |
| Index = Value; |
| } |
| |
| bool isUnset() const { return SymbolContents == SymContentsUnset; } |
| |
| uint64_t getOffset() const { |
| assert((SymbolContents == SymContentsUnset || |
| SymbolContents == SymContentsOffset) && |
| "Cannot get offset for a common/variable symbol"); |
| return Offset; |
| } |
| void setOffset(uint64_t Value) { |
| assert((SymbolContents == SymContentsUnset || |
| SymbolContents == SymContentsOffset) && |
| "Cannot set offset for a common/variable symbol"); |
| Offset = Value; |
| SymbolContents = SymContentsOffset; |
| } |
| |
| /// Return the size of a 'common' symbol. |
| uint64_t getCommonSize() const { |
| assert(isCommon() && "Not a 'common' symbol!"); |
| return CommonSize; |
| } |
| |
| /// Mark this symbol as being 'common'. |
| /// |
| /// \param Size - The size of the symbol. |
| /// \param Alignment - The alignment of the symbol. |
| /// \param Target - Is the symbol a target-specific common-like symbol. |
| void setCommon(uint64_t Size, Align Alignment, bool Target = false) { |
| assert(getOffset() == 0); |
| CommonSize = Size; |
| SymbolContents = Target ? SymContentsTargetCommon : SymContentsCommon; |
| |
| unsigned Log2Align = encode(Alignment); |
| assert(Log2Align < (1U << NumCommonAlignmentBits) && |
| "Out of range alignment"); |
| CommonAlignLog2 = Log2Align; |
| } |
| |
| /// Return the alignment of a 'common' symbol. |
| MaybeAlign getCommonAlignment() const { |
| assert(isCommon() && "Not a 'common' symbol!"); |
| return decodeMaybeAlign(CommonAlignLog2); |
| } |
| |
| /// Declare this symbol as being 'common'. |
| /// |
| /// \param Size - The size of the symbol. |
| /// \param Alignment - The alignment of the symbol. |
| /// \param Target - Is the symbol a target-specific common-like symbol. |
| /// \return True if symbol was already declared as a different type |
| bool declareCommon(uint64_t Size, Align Alignment, bool Target = false) { |
| assert(isCommon() || getOffset() == 0); |
| if(isCommon()) { |
| if (CommonSize != Size || getCommonAlignment() != Alignment || |
| isTargetCommon() != Target) |
| return true; |
| } else |
| setCommon(Size, Alignment, Target); |
| return false; |
| } |
| |
| /// Is this a 'common' symbol. |
| bool isCommon() const { |
| return SymbolContents == SymContentsCommon || |
| SymbolContents == SymContentsTargetCommon; |
| } |
| |
| /// Is this a target-specific common-like symbol. |
| bool isTargetCommon() const { |
| return SymbolContents == SymContentsTargetCommon; |
| } |
| |
| MCFragment *getFragment(bool SetUsed = true) const { |
| MCFragment *Fragment = FragmentAndHasName.getPointer(); |
| if (Fragment || !isVariable()) |
| return Fragment; |
| Fragment = getVariableValue(SetUsed)->findAssociatedFragment(); |
| FragmentAndHasName.setPointer(Fragment); |
| return Fragment; |
| } |
| |
| bool isExternal() const { return IsExternal; } |
| void setExternal(bool Value) const { IsExternal = Value; } |
| |
| bool isPrivateExtern() const { return IsPrivateExtern; } |
| void setPrivateExtern(bool Value) { IsPrivateExtern = Value; } |
| |
| /// print - Print the value to the stream \p OS. |
| void print(raw_ostream &OS, const MCAsmInfo *MAI) const; |
| |
| /// dump - Print the value to stderr. |
| void dump() const; |
| |
| protected: |
| /// Get the (implementation defined) symbol flags. |
| uint32_t getFlags() const { return Flags; } |
| |
| /// Set the (implementation defined) symbol flags. |
| void setFlags(uint32_t Value) const { |
| assert(Value < (1U << NumFlagsBits) && "Out of range flags"); |
| Flags = Value; |
| } |
| |
| /// Modify the flags via a mask |
| void modifyFlags(uint32_t Value, uint32_t Mask) const { |
| assert(Value < (1U << NumFlagsBits) && "Out of range flags"); |
| Flags = (Flags & ~Mask) | Value; |
| } |
| }; |
| |
| inline raw_ostream &operator<<(raw_ostream &OS, const MCSymbol &Sym) { |
| Sym.print(OS, nullptr); |
| return OS; |
| } |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_MC_MCSYMBOL_H |