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