Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 1 | //===- MCSymbol.h - Machine Code Symbols ------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file contains the declaration of the MCSymbol class. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_MC_MCSYMBOL_H |
| 15 | #define LLVM_MC_MCSYMBOL_H |
| 16 | |
| 17 | #include "llvm/ADT/PointerIntPair.h" |
| 18 | #include "llvm/ADT/StringMap.h" |
| 19 | #include "llvm/ADT/StringRef.h" |
| 20 | #include "llvm/MC/MCFragment.h" |
| 21 | #include "llvm/Support/ErrorHandling.h" |
| 22 | #include "llvm/Support/MathExtras.h" |
| 23 | #include <cassert> |
| 24 | #include <cstddef> |
| 25 | #include <cstdint> |
| 26 | |
| 27 | namespace llvm { |
| 28 | |
| 29 | class MCAsmInfo; |
| 30 | class MCContext; |
| 31 | class MCExpr; |
| 32 | class MCSection; |
| 33 | class raw_ostream; |
| 34 | |
| 35 | /// MCSymbol - Instances of this class represent a symbol name in the MC file, |
| 36 | /// and MCSymbols are created and uniqued by the MCContext class. MCSymbols |
| 37 | /// should only be constructed with valid names for the object file. |
| 38 | /// |
| 39 | /// If the symbol is defined/emitted into the current translation unit, the |
| 40 | /// Section member is set to indicate what section it lives in. Otherwise, if |
| 41 | /// it is a reference to an external entity, it has a null section. |
| 42 | class MCSymbol { |
| 43 | protected: |
| 44 | /// The kind of the symbol. If it is any value other than unset then this |
| 45 | /// class is actually one of the appropriate subclasses of MCSymbol. |
| 46 | enum SymbolKind { |
| 47 | SymbolKindUnset, |
| 48 | SymbolKindCOFF, |
| 49 | SymbolKindELF, |
| 50 | SymbolKindMachO, |
| 51 | SymbolKindWasm, |
| 52 | }; |
| 53 | |
| 54 | /// A symbol can contain an Offset, or Value, or be Common, but never more |
| 55 | /// than one of these. |
| 56 | enum Contents : uint8_t { |
| 57 | SymContentsUnset, |
| 58 | SymContentsOffset, |
| 59 | SymContentsVariable, |
| 60 | SymContentsCommon, |
| 61 | }; |
| 62 | |
| 63 | // Special sentinal value for the absolute pseudo fragment. |
| 64 | static MCFragment *AbsolutePseudoFragment; |
| 65 | |
| 66 | /// If a symbol has a Fragment, the section is implied, so we only need |
| 67 | /// one pointer. |
| 68 | /// The special AbsolutePseudoFragment value is for absolute symbols. |
| 69 | /// If this is a variable symbol, this caches the variable value's fragment. |
| 70 | /// FIXME: We might be able to simplify this by having the asm streamer create |
| 71 | /// dummy fragments. |
| 72 | /// If this is a section, then it gives the symbol is defined in. This is null |
| 73 | /// for undefined symbols. |
| 74 | /// |
| 75 | /// If this is a fragment, then it gives the fragment this symbol's value is |
| 76 | /// relative to, if any. |
| 77 | /// |
| 78 | /// For the 'HasName' integer, this is true if this symbol is named. |
| 79 | /// A named symbol will have a pointer to the name allocated in the bytes |
| 80 | /// immediately prior to the MCSymbol. |
| 81 | mutable PointerIntPair<MCFragment *, 1> FragmentAndHasName; |
| 82 | |
| 83 | /// IsTemporary - True if this is an assembler temporary label, which |
| 84 | /// typically does not survive in the .o file's symbol table. Usually |
| 85 | /// "Lfoo" or ".foo". |
| 86 | unsigned IsTemporary : 1; |
| 87 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 88 | /// True if this symbol can be redefined. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 89 | unsigned IsRedefinable : 1; |
| 90 | |
| 91 | /// IsUsed - True if this symbol has been used. |
| 92 | mutable unsigned IsUsed : 1; |
| 93 | |
| 94 | mutable unsigned IsRegistered : 1; |
| 95 | |
| 96 | /// This symbol is visible outside this translation unit. |
| 97 | mutable unsigned IsExternal : 1; |
| 98 | |
| 99 | /// This symbol is private extern. |
| 100 | mutable unsigned IsPrivateExtern : 1; |
| 101 | |
| 102 | /// LLVM RTTI discriminator. This is actually a SymbolKind enumerator, but is |
| 103 | /// unsigned to avoid sign extension and achieve better bitpacking with MSVC. |
| 104 | unsigned Kind : 3; |
| 105 | |
| 106 | /// True if we have created a relocation that uses this symbol. |
| 107 | mutable unsigned IsUsedInReloc : 1; |
| 108 | |
| 109 | /// This is actually a Contents enumerator, but is unsigned to avoid sign |
| 110 | /// extension and achieve better bitpacking with MSVC. |
| 111 | unsigned SymbolContents : 2; |
| 112 | |
| 113 | /// The alignment of the symbol, if it is 'common', or -1. |
| 114 | /// |
| 115 | /// The alignment is stored as log2(align) + 1. This allows all values from |
| 116 | /// 0 to 2^31 to be stored which is every power of 2 representable by an |
| 117 | /// unsigned. |
| 118 | enum : unsigned { NumCommonAlignmentBits = 5 }; |
| 119 | unsigned CommonAlignLog2 : NumCommonAlignmentBits; |
| 120 | |
| 121 | /// The Flags field is used by object file implementations to store |
| 122 | /// additional per symbol information which is not easily classified. |
| 123 | enum : unsigned { NumFlagsBits = 16 }; |
| 124 | mutable uint32_t Flags : NumFlagsBits; |
| 125 | |
| 126 | /// Index field, for use by the object file implementation. |
| 127 | mutable uint32_t Index = 0; |
| 128 | |
| 129 | union { |
| 130 | /// The offset to apply to the fragment address to form this symbol's value. |
| 131 | uint64_t Offset; |
| 132 | |
| 133 | /// The size of the symbol, if it is 'common'. |
| 134 | uint64_t CommonSize; |
| 135 | |
| 136 | /// If non-null, the value for a variable symbol. |
| 137 | const MCExpr *Value; |
| 138 | }; |
| 139 | |
| 140 | // MCContext creates and uniques these. |
| 141 | friend class MCExpr; |
| 142 | friend class MCContext; |
| 143 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 144 | /// The name for a symbol. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 145 | /// MCSymbol contains a uint64_t so is probably aligned to 8. On a 32-bit |
| 146 | /// system, the name is a pointer so isn't going to satisfy the 8 byte |
| 147 | /// alignment of uint64_t. Account for that here. |
| 148 | using NameEntryStorageTy = union { |
| 149 | const StringMapEntry<bool> *NameEntry; |
| 150 | uint64_t AlignmentPadding; |
| 151 | }; |
| 152 | |
| 153 | MCSymbol(SymbolKind Kind, const StringMapEntry<bool> *Name, bool isTemporary) |
| 154 | : IsTemporary(isTemporary), IsRedefinable(false), IsUsed(false), |
| 155 | IsRegistered(false), IsExternal(false), IsPrivateExtern(false), |
| 156 | Kind(Kind), IsUsedInReloc(false), SymbolContents(SymContentsUnset), |
| 157 | CommonAlignLog2(0), Flags(0) { |
| 158 | Offset = 0; |
| 159 | FragmentAndHasName.setInt(!!Name); |
| 160 | if (Name) |
| 161 | getNameEntryPtr() = Name; |
| 162 | } |
| 163 | |
| 164 | // Provide custom new/delete as we will only allocate space for a name |
| 165 | // if we need one. |
| 166 | void *operator new(size_t s, const StringMapEntry<bool> *Name, |
| 167 | MCContext &Ctx); |
| 168 | |
| 169 | private: |
| 170 | void operator delete(void *); |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 171 | /// Placement delete - required by std, but never called. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 172 | void operator delete(void*, unsigned) { |
| 173 | llvm_unreachable("Constructor throws?"); |
| 174 | } |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 175 | /// Placement delete - required by std, but never called. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 176 | void operator delete(void*, unsigned, bool) { |
| 177 | llvm_unreachable("Constructor throws?"); |
| 178 | } |
| 179 | |
| 180 | MCSection *getSectionPtr() const { |
| 181 | if (MCFragment *F = getFragment()) { |
| 182 | assert(F != AbsolutePseudoFragment); |
| 183 | return F->getParent(); |
| 184 | } |
| 185 | return nullptr; |
| 186 | } |
| 187 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 188 | /// Get a reference to the name field. Requires that we have a name |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 189 | const StringMapEntry<bool> *&getNameEntryPtr() { |
| 190 | assert(FragmentAndHasName.getInt() && "Name is required"); |
| 191 | NameEntryStorageTy *Name = reinterpret_cast<NameEntryStorageTy *>(this); |
| 192 | return (*(Name - 1)).NameEntry; |
| 193 | } |
| 194 | const StringMapEntry<bool> *&getNameEntryPtr() const { |
| 195 | return const_cast<MCSymbol*>(this)->getNameEntryPtr(); |
| 196 | } |
| 197 | |
| 198 | public: |
| 199 | MCSymbol(const MCSymbol &) = delete; |
| 200 | MCSymbol &operator=(const MCSymbol &) = delete; |
| 201 | |
| 202 | /// getName - Get the symbol name. |
| 203 | StringRef getName() const { |
| 204 | if (!FragmentAndHasName.getInt()) |
| 205 | return StringRef(); |
| 206 | |
| 207 | return getNameEntryPtr()->first(); |
| 208 | } |
| 209 | |
| 210 | bool isRegistered() const { return IsRegistered; } |
| 211 | void setIsRegistered(bool Value) const { IsRegistered = Value; } |
| 212 | |
| 213 | void setUsedInReloc() const { IsUsedInReloc = true; } |
| 214 | bool isUsedInReloc() const { return IsUsedInReloc; } |
| 215 | |
| 216 | /// \name Accessors |
| 217 | /// @{ |
| 218 | |
| 219 | /// isTemporary - Check if this is an assembler temporary symbol. |
| 220 | bool isTemporary() const { return IsTemporary; } |
| 221 | |
| 222 | /// isUsed - Check if this is used. |
| 223 | bool isUsed() const { return IsUsed; } |
| 224 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 225 | /// Check if this symbol is redefinable. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 226 | bool isRedefinable() const { return IsRedefinable; } |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 227 | /// Mark this symbol as redefinable. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 228 | void setRedefinable(bool Value) { IsRedefinable = Value; } |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 229 | /// Prepare this symbol to be redefined. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 230 | void redefineIfPossible() { |
| 231 | if (IsRedefinable) { |
| 232 | if (SymbolContents == SymContentsVariable) { |
| 233 | Value = nullptr; |
| 234 | SymbolContents = SymContentsUnset; |
| 235 | } |
| 236 | setUndefined(); |
| 237 | IsRedefinable = false; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | /// @} |
| 242 | /// \name Associated Sections |
| 243 | /// @{ |
| 244 | |
| 245 | /// isDefined - Check if this symbol is defined (i.e., it has an address). |
| 246 | /// |
| 247 | /// Defined symbols are either absolute or in some section. |
| 248 | bool isDefined() const { return !isUndefined(); } |
| 249 | |
| 250 | /// isInSection - Check if this symbol is defined in some section (i.e., it |
| 251 | /// is defined but not absolute). |
| 252 | bool isInSection() const { |
| 253 | return isDefined() && !isAbsolute(); |
| 254 | } |
| 255 | |
| 256 | /// isUndefined - Check if this symbol undefined (i.e., implicitly defined). |
| 257 | bool isUndefined(bool SetUsed = true) const { |
| 258 | return getFragment(SetUsed) == nullptr; |
| 259 | } |
| 260 | |
| 261 | /// isAbsolute - Check if this is an absolute symbol. |
| 262 | bool isAbsolute() const { |
| 263 | return getFragment() == AbsolutePseudoFragment; |
| 264 | } |
| 265 | |
| 266 | /// Get the section associated with a defined, non-absolute symbol. |
| 267 | MCSection &getSection() const { |
| 268 | assert(isInSection() && "Invalid accessor!"); |
| 269 | return *getSectionPtr(); |
| 270 | } |
| 271 | |
| 272 | /// Mark the symbol as defined in the fragment \p F. |
| 273 | void setFragment(MCFragment *F) const { |
| 274 | assert(!isVariable() && "Cannot set fragment of variable"); |
| 275 | FragmentAndHasName.setPointer(F); |
| 276 | } |
| 277 | |
| 278 | /// Mark the symbol as undefined. |
| 279 | void setUndefined() { FragmentAndHasName.setPointer(nullptr); } |
| 280 | |
| 281 | bool isELF() const { return Kind == SymbolKindELF; } |
| 282 | |
| 283 | bool isCOFF() const { return Kind == SymbolKindCOFF; } |
| 284 | |
| 285 | bool isMachO() const { return Kind == SymbolKindMachO; } |
| 286 | |
| 287 | bool isWasm() const { return Kind == SymbolKindWasm; } |
| 288 | |
| 289 | /// @} |
| 290 | /// \name Variable Symbols |
| 291 | /// @{ |
| 292 | |
| 293 | /// isVariable - Check if this is a variable symbol. |
| 294 | bool isVariable() const { |
| 295 | return SymbolContents == SymContentsVariable; |
| 296 | } |
| 297 | |
| 298 | /// getVariableValue - Get the value for variable symbols. |
| 299 | const MCExpr *getVariableValue(bool SetUsed = true) const { |
| 300 | assert(isVariable() && "Invalid accessor!"); |
| 301 | IsUsed |= SetUsed; |
| 302 | return Value; |
| 303 | } |
| 304 | |
| 305 | void setVariableValue(const MCExpr *Value); |
| 306 | |
| 307 | /// @} |
| 308 | |
| 309 | /// Get the (implementation defined) index. |
| 310 | uint32_t getIndex() const { |
| 311 | return Index; |
| 312 | } |
| 313 | |
| 314 | /// Set the (implementation defined) index. |
| 315 | void setIndex(uint32_t Value) const { |
| 316 | Index = Value; |
| 317 | } |
| 318 | |
Andrew Scull | cdfcccc | 2018-10-05 20:58:37 +0100 | [diff] [blame^] | 319 | bool isUnset() const { return SymbolContents == SymContentsUnset; } |
| 320 | |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 321 | uint64_t getOffset() const { |
| 322 | assert((SymbolContents == SymContentsUnset || |
| 323 | SymbolContents == SymContentsOffset) && |
| 324 | "Cannot get offset for a common/variable symbol"); |
| 325 | return Offset; |
| 326 | } |
| 327 | void setOffset(uint64_t Value) { |
| 328 | assert((SymbolContents == SymContentsUnset || |
| 329 | SymbolContents == SymContentsOffset) && |
| 330 | "Cannot set offset for a common/variable symbol"); |
| 331 | Offset = Value; |
| 332 | SymbolContents = SymContentsOffset; |
| 333 | } |
| 334 | |
| 335 | /// Return the size of a 'common' symbol. |
| 336 | uint64_t getCommonSize() const { |
| 337 | assert(isCommon() && "Not a 'common' symbol!"); |
| 338 | return CommonSize; |
| 339 | } |
| 340 | |
| 341 | /// Mark this symbol as being 'common'. |
| 342 | /// |
| 343 | /// \param Size - The size of the symbol. |
| 344 | /// \param Align - The alignment of the symbol. |
| 345 | void setCommon(uint64_t Size, unsigned Align) { |
| 346 | assert(getOffset() == 0); |
| 347 | CommonSize = Size; |
| 348 | SymbolContents = SymContentsCommon; |
| 349 | |
| 350 | assert((!Align || isPowerOf2_32(Align)) && |
| 351 | "Alignment must be a power of 2"); |
| 352 | unsigned Log2Align = Log2_32(Align) + 1; |
| 353 | assert(Log2Align < (1U << NumCommonAlignmentBits) && |
| 354 | "Out of range alignment"); |
| 355 | CommonAlignLog2 = Log2Align; |
| 356 | } |
| 357 | |
| 358 | /// Return the alignment of a 'common' symbol. |
| 359 | unsigned getCommonAlignment() const { |
| 360 | assert(isCommon() && "Not a 'common' symbol!"); |
| 361 | return CommonAlignLog2 ? (1U << (CommonAlignLog2 - 1)) : 0; |
| 362 | } |
| 363 | |
| 364 | /// Declare this symbol as being 'common'. |
| 365 | /// |
| 366 | /// \param Size - The size of the symbol. |
| 367 | /// \param Align - The alignment of the symbol. |
| 368 | /// \return True if symbol was already declared as a different type |
| 369 | bool declareCommon(uint64_t Size, unsigned Align) { |
| 370 | assert(isCommon() || getOffset() == 0); |
| 371 | if(isCommon()) { |
| 372 | if(CommonSize != Size || getCommonAlignment() != Align) |
| 373 | return true; |
| 374 | } else |
| 375 | setCommon(Size, Align); |
| 376 | return false; |
| 377 | } |
| 378 | |
| 379 | /// Is this a 'common' symbol. |
| 380 | bool isCommon() const { |
| 381 | return SymbolContents == SymContentsCommon; |
| 382 | } |
| 383 | |
| 384 | MCFragment *getFragment(bool SetUsed = true) const { |
| 385 | MCFragment *Fragment = FragmentAndHasName.getPointer(); |
| 386 | if (Fragment || !isVariable()) |
| 387 | return Fragment; |
| 388 | Fragment = getVariableValue(SetUsed)->findAssociatedFragment(); |
| 389 | FragmentAndHasName.setPointer(Fragment); |
| 390 | return Fragment; |
| 391 | } |
| 392 | |
| 393 | bool isExternal() const { return IsExternal; } |
| 394 | void setExternal(bool Value) const { IsExternal = Value; } |
| 395 | |
| 396 | bool isPrivateExtern() const { return IsPrivateExtern; } |
| 397 | void setPrivateExtern(bool Value) { IsPrivateExtern = Value; } |
| 398 | |
| 399 | /// print - Print the value to the stream \p OS. |
| 400 | void print(raw_ostream &OS, const MCAsmInfo *MAI) const; |
| 401 | |
| 402 | /// dump - Print the value to stderr. |
| 403 | void dump() const; |
| 404 | |
| 405 | protected: |
| 406 | /// Get the (implementation defined) symbol flags. |
| 407 | uint32_t getFlags() const { return Flags; } |
| 408 | |
| 409 | /// Set the (implementation defined) symbol flags. |
| 410 | void setFlags(uint32_t Value) const { |
| 411 | assert(Value < (1U << NumFlagsBits) && "Out of range flags"); |
| 412 | Flags = Value; |
| 413 | } |
| 414 | |
| 415 | /// Modify the flags via a mask |
| 416 | void modifyFlags(uint32_t Value, uint32_t Mask) const { |
| 417 | assert(Value < (1U << NumFlagsBits) && "Out of range flags"); |
| 418 | Flags = (Flags & ~Mask) | Value; |
| 419 | } |
| 420 | }; |
| 421 | |
| 422 | inline raw_ostream &operator<<(raw_ostream &OS, const MCSymbol &Sym) { |
| 423 | Sym.print(OS, nullptr); |
| 424 | return OS; |
| 425 | } |
| 426 | |
| 427 | } // end namespace llvm |
| 428 | |
| 429 | #endif // LLVM_MC_MCSYMBOL_H |