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