1 //===- SymbolTable.cpp ----------------------------------------------------===// 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 // Symbol table is a bag of all known symbols. We put all symbols of 10 // all input files to the symbol table. The symbol table is basically 11 // a hash table with the logic to resolve symbol name conflicts using 12 // the symbol types. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "SymbolTable.h" 17 #include "Config.h" 18 #include "LinkerScript.h" 19 #include "Symbols.h" 20 #include "SyntheticSections.h" 21 #include "lld/Common/ErrorHandler.h" 22 #include "lld/Common/Memory.h" 23 #include "lld/Common/Strings.h" 24 #include "llvm/ADT/STLExtras.h" 25 26 using namespace llvm; 27 using namespace llvm::object; 28 using namespace llvm::ELF; 29 30 using namespace lld; 31 using namespace lld::elf; 32 33 SymbolTable *elf::Symtab; 34 35 // This function is where all the optimizations of link-time 36 // optimization happens. When LTO is in use, some input files are 37 // not in native object file format but in the LLVM bitcode format. 38 // This function compiles bitcode files into a few big native files 39 // using LLVM functions and replaces bitcode symbols with the results. 40 // Because all bitcode files that the program consists of are passed 41 // to the compiler at once, it can do whole-program optimization. 42 template <class ELFT> void SymbolTable::addCombinedLTOObject() { 43 // Compile bitcode files and replace bitcode symbols. 44 LTO.reset(new BitcodeCompiler); 45 for (BitcodeFile *F : BitcodeFiles) 46 LTO->add(*F); 47 48 for (InputFile *File : LTO->compile()) { 49 DenseSet<CachedHashStringRef> DummyGroups; 50 auto *Obj = cast<ObjFile<ELFT>>(File); 51 Obj->parse(DummyGroups); 52 for (Symbol *Sym : Obj->getGlobalSymbols()) 53 Sym->parseSymbolVersion(); 54 ObjectFiles.push_back(File); 55 } 56 } 57 58 // Set a flag for --trace-symbol so that we can print out a log message 59 // if a new symbol with the same name is inserted into the symbol table. 60 void SymbolTable::trace(StringRef Name) { 61 SymMap.insert({CachedHashStringRef(Name), -1}); 62 } 63 64 void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) { 65 // Swap symbols as instructed by -wrap. 66 int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())]; 67 int &Idx2 = SymMap[CachedHashStringRef(Real->getName())]; 68 int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())]; 69 70 Idx2 = Idx1; 71 Idx1 = Idx3; 72 73 // Now renaming is complete. No one refers Real symbol. We could leave 74 // Real as-is, but if Real is written to the symbol table, that may 75 // contain irrelevant values. So, we copy all values from Sym to Real. 76 StringRef S = Real->getName(); 77 memcpy(Real, Sym, sizeof(SymbolUnion)); 78 Real->setName(S); 79 } 80 81 static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { 82 if (VA == STV_DEFAULT) 83 return VB; 84 if (VB == STV_DEFAULT) 85 return VA; 86 return std::min(VA, VB); 87 } 88 89 // Find an existing symbol or create and insert a new one. 90 std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) { 91 // <name>@@<version> means the symbol is the default version. In that 92 // case <name>@@<version> will be used to resolve references to <name>. 93 // 94 // Since this is a hot path, the following string search code is 95 // optimized for speed. StringRef::find(char) is much faster than 96 // StringRef::find(StringRef). 97 size_t Pos = Name.find('@'); 98 if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@') 99 Name = Name.take_front(Pos); 100 101 auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); 102 int &SymIndex = P.first->second; 103 bool IsNew = P.second; 104 bool Traced = false; 105 106 if (SymIndex == -1) { 107 SymIndex = SymVector.size(); 108 IsNew = true; 109 Traced = true; 110 } 111 112 if (!IsNew) 113 return {SymVector[SymIndex], false}; 114 115 auto *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); 116 Sym->SymbolKind = Symbol::PlaceholderKind; 117 Sym->Visibility = STV_DEFAULT; 118 Sym->IsUsedInRegularObj = false; 119 Sym->ExportDynamic = false; 120 Sym->CanInline = true; 121 Sym->Traced = Traced; 122 Sym->VersionId = Config->DefaultSymbolVersion; 123 SymVector.push_back(Sym); 124 return {Sym, true}; 125 } 126 127 // Find an existing symbol or create and insert a new one, then apply the given 128 // attributes. 129 std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, 130 uint8_t Visibility, 131 bool CanOmitFromDynSym, 132 InputFile *File) { 133 Symbol *S; 134 bool WasInserted; 135 std::tie(S, WasInserted) = insertName(Name); 136 137 // Merge in the new symbol's visibility. 138 S->Visibility = getMinVisibility(S->Visibility, Visibility); 139 140 if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) 141 S->ExportDynamic = true; 142 143 if (!File || File->kind() == InputFile::ObjKind) 144 S->IsUsedInRegularObj = true; 145 146 return {S, WasInserted}; 147 } 148 149 static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } 150 151 template <class ELFT> 152 Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, 153 uint8_t StOther, uint8_t Type, 154 bool CanOmitFromDynSym, InputFile *File) { 155 Symbol *S; 156 bool WasInserted; 157 uint8_t Visibility = getVisibility(StOther); 158 std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File); 159 160 // An undefined symbol with non default visibility must be satisfied 161 // in the same DSO. 162 if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) { 163 replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type); 164 return S; 165 } 166 167 if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) 168 S->Binding = Binding; 169 170 if (S->isLazy()) { 171 // An undefined weak will not fetch archive members. See comment on Lazy in 172 // Symbols.h for the details. 173 if (Binding == STB_WEAK) { 174 S->Type = Type; 175 return S; 176 } 177 178 // Do extra check for --warn-backrefs. 179 // 180 // --warn-backrefs is an option to prevent an undefined reference from 181 // fetching an archive member written earlier in the command line. It can be 182 // used to keep compatibility with GNU linkers to some degree. 183 // I'll explain the feature and why you may find it useful in this comment. 184 // 185 // lld's symbol resolution semantics is more relaxed than traditional Unix 186 // linkers. For example, 187 // 188 // ld.lld foo.a bar.o 189 // 190 // succeeds even if bar.o contains an undefined symbol that has to be 191 // resolved by some object file in foo.a. Traditional Unix linkers don't 192 // allow this kind of backward reference, as they visit each file only once 193 // from left to right in the command line while resolving all undefined 194 // symbols at the moment of visiting. 195 // 196 // In the above case, since there's no undefined symbol when a linker visits 197 // foo.a, no files are pulled out from foo.a, and because the linker forgets 198 // about foo.a after visiting, it can't resolve undefined symbols in bar.o 199 // that could have been resolved otherwise. 200 // 201 // That lld accepts more relaxed form means that (besides it'd make more 202 // sense) you can accidentally write a command line or a build file that 203 // works only with lld, even if you have a plan to distribute it to wider 204 // users who may be using GNU linkers. With --warn-backrefs, you can detect 205 // a library order that doesn't work with other Unix linkers. 206 // 207 // The option is also useful to detect cyclic dependencies between static 208 // archives. Again, lld accepts 209 // 210 // ld.lld foo.a bar.a 211 // 212 // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is 213 // handled as an error. 214 // 215 // Here is how the option works. We assign a group ID to each file. A file 216 // with a smaller group ID can pull out object files from an archive file 217 // with an equal or greater group ID. Otherwise, it is a reverse dependency 218 // and an error. 219 // 220 // A file outside --{start,end}-group gets a fresh ID when instantiated. All 221 // files within the same --{start,end}-group get the same group ID. E.g. 222 // 223 // ld.lld A B --start-group C D --end-group E 224 // 225 // A forms group 0. B form group 1. C and D (including their member object 226 // files) form group 2. E forms group 3. I think that you can see how this 227 // group assignment rule simulates the traditional linker's semantics. 228 bool Backref = 229 Config->WarnBackrefs && File && S->File->GroupId < File->GroupId; 230 fetchLazy<ELFT>(S); 231 232 // We don't report backward references to weak symbols as they can be 233 // overridden later. 234 if (Backref && !S->isWeak()) 235 warn("backward reference detected: " + Name + " in " + toString(File) + 236 " refers to " + toString(S->File)); 237 } 238 return S; 239 } 240 241 // Using .symver foo,foo@@VER unfortunately creates two symbols: foo and 242 // foo@@VER. We want to effectively ignore foo, so give precedence to 243 // foo@@VER. 244 // FIXME: If users can transition to using 245 // .symver foo,foo@@@VER 246 // we can delete this hack. 247 static int compareVersion(Symbol *S, StringRef Name) { 248 bool A = Name.contains("@@"); 249 bool B = S->getName().contains("@@"); 250 if (A && !B) 251 return 1; 252 if (!A && B) 253 return -1; 254 return 0; 255 } 256 257 // We have a new defined symbol with the specified binding. Return 1 if the new 258 // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are 259 // strong defined symbols. 260 static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, 261 StringRef Name) { 262 if (WasInserted) 263 return 1; 264 if (!S->isDefined()) 265 return 1; 266 if (int R = compareVersion(S, Name)) 267 return R; 268 if (Binding == STB_WEAK) 269 return -1; 270 if (S->isWeak()) 271 return 1; 272 return 0; 273 } 274 275 // We have a new non-common defined symbol with the specified binding. Return 1 276 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there 277 // is a conflict. If the new symbol wins, also update the binding. 278 static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, 279 bool IsAbsolute, uint64_t Value, 280 StringRef Name) { 281 if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) 282 return Cmp; 283 if (auto *R = dyn_cast<Defined>(S)) { 284 if (R->Section && isa<BssSection>(R->Section)) { 285 // Non-common symbols take precedence over common symbols. 286 if (Config->WarnCommon) 287 warn("common " + S->getName() + " is overridden"); 288 return 1; 289 } 290 if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && 291 R->Value == Value) 292 return -1; 293 } 294 return 0; 295 } 296 297 Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, 298 uint8_t Binding, uint8_t StOther, uint8_t Type, 299 InputFile &File) { 300 Symbol *S; 301 bool WasInserted; 302 std::tie(S, WasInserted) = insert(N, getVisibility(StOther), 303 /*CanOmitFromDynSym*/ false, &File); 304 305 int Cmp = compareDefined(S, WasInserted, Binding, N); 306 if (Cmp < 0) 307 return S; 308 309 if (Cmp > 0) { 310 auto *Bss = make<BssSection>("COMMON", Size, Alignment); 311 Bss->File = &File; 312 Bss->Live = !Config->GcSections; 313 InputSections.push_back(Bss); 314 315 replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss); 316 return S; 317 } 318 319 auto *D = cast<Defined>(S); 320 auto *Bss = dyn_cast_or_null<BssSection>(D->Section); 321 if (!Bss) { 322 // Non-common symbols take precedence over common symbols. 323 if (Config->WarnCommon) 324 warn("common " + S->getName() + " is overridden"); 325 return S; 326 } 327 328 if (Config->WarnCommon) 329 warn("multiple common of " + D->getName()); 330 331 Bss->Alignment = std::max(Bss->Alignment, Alignment); 332 if (Size > Bss->Size) { 333 D->File = Bss->File = &File; 334 D->Size = Bss->Size = Size; 335 } 336 return S; 337 } 338 339 static void reportDuplicate(Symbol *Sym, InputFile *NewFile, 340 InputSectionBase *ErrSec, uint64_t ErrOffset) { 341 if (Config->AllowMultipleDefinition) 342 return; 343 344 Defined *D = cast<Defined>(Sym); 345 if (!D->Section || !ErrSec) { 346 error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + 347 toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); 348 return; 349 } 350 351 // Construct and print an error message in the form of: 352 // 353 // ld.lld: error: duplicate symbol: foo 354 // >>> defined at bar.c:30 355 // >>> bar.o (/home/alice/src/bar.o) 356 // >>> defined at baz.c:563 357 // >>> baz.o in archive libbaz.a 358 auto *Sec1 = cast<InputSectionBase>(D->Section); 359 std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value); 360 std::string Obj1 = Sec1->getObjMsg(D->Value); 361 std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset); 362 std::string Obj2 = ErrSec->getObjMsg(ErrOffset); 363 364 std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; 365 if (!Src1.empty()) 366 Msg += Src1 + "\n>>> "; 367 Msg += Obj1 + "\n>>> defined at "; 368 if (!Src2.empty()) 369 Msg += Src2 + "\n>>> "; 370 Msg += Obj2; 371 error(Msg); 372 } 373 374 Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type, 375 uint64_t Value, uint64_t Size, uint8_t Binding, 376 SectionBase *Section, InputFile *File) { 377 Symbol *S; 378 bool WasInserted; 379 std::tie(S, WasInserted) = insert(Name, getVisibility(StOther), 380 /*CanOmitFromDynSym*/ false, File); 381 int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr, 382 Value, Name); 383 if (Cmp > 0) 384 replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, 385 Section); 386 else if (Cmp == 0) 387 reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section), 388 Value); 389 return cast<Defined>(S); 390 } 391 392 void SymbolTable::addShared(StringRef Name, uint8_t Binding, uint8_t StOther, 393 uint8_t Type, uint64_t Value, uint64_t Size, 394 uint32_t Alignment, uint32_t VerdefIndex, 395 InputFile *File) { 396 // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT 397 // as the visibility, which will leave the visibility in the symbol table 398 // unchanged. 399 Symbol *S; 400 bool WasInserted; 401 std::tie(S, WasInserted) = insert(Name, STV_DEFAULT, 402 /*CanOmitFromDynSym*/ true, File); 403 // Make sure we preempt DSO symbols with default visibility. 404 if (getVisibility(StOther) == STV_DEFAULT) 405 S->ExportDynamic = true; 406 407 // An undefined symbol with non default visibility must be satisfied 408 // in the same DSO. 409 auto Replace = [&](uint8_t Binding) { 410 replaceSymbol<SharedSymbol>(S, *File, Name, Binding, StOther, Type, Value, 411 Size, Alignment, VerdefIndex); 412 }; 413 414 if (WasInserted) 415 Replace(Binding); 416 else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy())) 417 Replace(S->Binding); 418 } 419 420 Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, 421 uint8_t StOther, uint8_t Type, 422 bool CanOmitFromDynSym, BitcodeFile &F) { 423 Symbol *S; 424 bool WasInserted; 425 std::tie(S, WasInserted) = 426 insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F); 427 int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, 428 /*IsAbs*/ false, /*Value*/ 0, Name); 429 if (Cmp > 0) 430 replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr); 431 else if (Cmp == 0) 432 reportDuplicate(S, &F, nullptr, 0); 433 return S; 434 } 435 436 Symbol *SymbolTable::find(StringRef Name) { 437 auto It = SymMap.find(CachedHashStringRef(Name)); 438 if (It == SymMap.end()) 439 return nullptr; 440 if (It->second == -1) 441 return nullptr; 442 return SymVector[It->second]; 443 } 444 445 template <class ELFT> 446 void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File, 447 const object::Archive::Symbol Sym) { 448 Symbol *S; 449 bool WasInserted; 450 std::tie(S, WasInserted) = insertName(Name); 451 if (WasInserted) { 452 replaceSymbol<LazyArchive>(S, File, STT_NOTYPE, Sym); 453 return; 454 } 455 if (!S->isUndefined()) 456 return; 457 458 // An undefined weak will not fetch archive members. See comment on Lazy in 459 // Symbols.h for the details. 460 if (S->isWeak()) { 461 replaceSymbol<LazyArchive>(S, File, S->Type, Sym); 462 S->Binding = STB_WEAK; 463 return; 464 } 465 466 if (InputFile *F = File.fetch(Sym)) 467 parseFile<ELFT>(F); 468 } 469 470 template <class ELFT> 471 void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) { 472 Symbol *S; 473 bool WasInserted; 474 std::tie(S, WasInserted) = insertName(Name); 475 if (WasInserted) { 476 replaceSymbol<LazyObject>(S, File, STT_NOTYPE, Name); 477 return; 478 } 479 if (!S->isUndefined()) 480 return; 481 482 // An undefined weak will not fetch archive members. See comment on Lazy in 483 // Symbols.h for the details. 484 if (S->isWeak()) { 485 replaceSymbol<LazyObject>(S, File, S->Type, Name); 486 S->Binding = STB_WEAK; 487 return; 488 } 489 490 if (InputFile *F = File.fetch()) 491 parseFile<ELFT>(F); 492 } 493 494 template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) { 495 if (auto *S = dyn_cast<LazyArchive>(Sym)) { 496 if (InputFile *File = S->fetch()) 497 parseFile<ELFT>(File); 498 return; 499 } 500 501 auto *S = cast<LazyObject>(Sym); 502 if (InputFile *File = cast<LazyObjFile>(S->File)->fetch()) 503 parseFile<ELFT>(File); 504 } 505 506 // Initialize DemangledSyms with a map from demangled symbols to symbol 507 // objects. Used to handle "extern C++" directive in version scripts. 508 // 509 // The map will contain all demangled symbols. That can be very large, 510 // and in LLD we generally want to avoid do anything for each symbol. 511 // Then, why are we doing this? Here's why. 512 // 513 // Users can use "extern C++ {}" directive to match against demangled 514 // C++ symbols. For example, you can write a pattern such as 515 // "llvm::*::foo(int, ?)". Obviously, there's no way to handle this 516 // other than trying to match a pattern against all demangled symbols. 517 // So, if "extern C++" feature is used, we need to demangle all known 518 // symbols. 519 StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() { 520 if (!DemangledSyms) { 521 DemangledSyms.emplace(); 522 for (Symbol *Sym : SymVector) { 523 if (!Sym->isDefined()) 524 continue; 525 if (Optional<std::string> S = demangleItanium(Sym->getName())) 526 (*DemangledSyms)[*S].push_back(Sym); 527 else 528 (*DemangledSyms)[Sym->getName()].push_back(Sym); 529 } 530 } 531 return *DemangledSyms; 532 } 533 534 std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion Ver) { 535 if (Ver.IsExternCpp) 536 return getDemangledSyms().lookup(Ver.Name); 537 if (Symbol *B = find(Ver.Name)) 538 if (B->isDefined()) 539 return {B}; 540 return {}; 541 } 542 543 std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion Ver) { 544 std::vector<Symbol *> Res; 545 StringMatcher M(Ver.Name); 546 547 if (Ver.IsExternCpp) { 548 for (auto &P : getDemangledSyms()) 549 if (M.match(P.first())) 550 Res.insert(Res.end(), P.second.begin(), P.second.end()); 551 return Res; 552 } 553 554 for (Symbol *Sym : SymVector) 555 if (Sym->isDefined() && M.match(Sym->getName())) 556 Res.push_back(Sym); 557 return Res; 558 } 559 560 // If there's only one anonymous version definition in a version 561 // script file, the script does not actually define any symbol version, 562 // but just specifies symbols visibilities. 563 void SymbolTable::handleAnonymousVersion() { 564 for (SymbolVersion &Ver : Config->VersionScriptGlobals) 565 assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); 566 for (SymbolVersion &Ver : Config->VersionScriptGlobals) 567 assignWildcardVersion(Ver, VER_NDX_GLOBAL); 568 for (SymbolVersion &Ver : Config->VersionScriptLocals) 569 assignExactVersion(Ver, VER_NDX_LOCAL, "local"); 570 for (SymbolVersion &Ver : Config->VersionScriptLocals) 571 assignWildcardVersion(Ver, VER_NDX_LOCAL); 572 } 573 574 // Handles -dynamic-list. 575 void SymbolTable::handleDynamicList() { 576 for (SymbolVersion &Ver : Config->DynamicList) { 577 std::vector<Symbol *> Syms; 578 if (Ver.HasWildcard) 579 Syms = findAllByVersion(Ver); 580 else 581 Syms = findByVersion(Ver); 582 583 for (Symbol *B : Syms) { 584 if (!Config->Shared) 585 B->ExportDynamic = true; 586 else if (B->includeInDynsym()) 587 B->IsPreemptible = true; 588 } 589 } 590 } 591 592 // Set symbol versions to symbols. This function handles patterns 593 // containing no wildcard characters. 594 void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, 595 StringRef VersionName) { 596 if (Ver.HasWildcard) 597 return; 598 599 // Get a list of symbols which we need to assign the version to. 600 std::vector<Symbol *> Syms = findByVersion(Ver); 601 if (Syms.empty()) { 602 if (!Config->UndefinedVersion) 603 error("version script assignment of '" + VersionName + "' to symbol '" + 604 Ver.Name + "' failed: symbol not defined"); 605 return; 606 } 607 608 // Assign the version. 609 for (Symbol *Sym : Syms) { 610 // Skip symbols containing version info because symbol versions 611 // specified by symbol names take precedence over version scripts. 612 // See parseSymbolVersion(). 613 if (Sym->getName().contains('@')) 614 continue; 615 616 if (Sym->VersionId != Config->DefaultSymbolVersion && 617 Sym->VersionId != VersionId) 618 error("duplicate symbol '" + Ver.Name + "' in version script"); 619 Sym->VersionId = VersionId; 620 } 621 } 622 623 void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { 624 if (!Ver.HasWildcard) 625 return; 626 627 // Exact matching takes precendence over fuzzy matching, 628 // so we set a version to a symbol only if no version has been assigned 629 // to the symbol. This behavior is compatible with GNU. 630 for (Symbol *B : findAllByVersion(Ver)) 631 if (B->VersionId == Config->DefaultSymbolVersion) 632 B->VersionId = VersionId; 633 } 634 635 // This function processes version scripts by updating VersionId 636 // member of symbols. 637 void SymbolTable::scanVersionScript() { 638 // Handle edge cases first. 639 handleAnonymousVersion(); 640 handleDynamicList(); 641 642 // Now we have version definitions, so we need to set version ids to symbols. 643 // Each version definition has a glob pattern, and all symbols that match 644 // with the pattern get that version. 645 646 // First, we assign versions to exact matching symbols, 647 // i.e. version definitions not containing any glob meta-characters. 648 for (VersionDefinition &V : Config->VersionDefinitions) 649 for (SymbolVersion &Ver : V.Globals) 650 assignExactVersion(Ver, V.Id, V.Name); 651 652 // Next, we assign versions to fuzzy matching symbols, 653 // i.e. version definitions containing glob meta-characters. 654 // Note that because the last match takes precedence over previous matches, 655 // we iterate over the definitions in the reverse order. 656 for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) 657 for (SymbolVersion &Ver : V.Globals) 658 assignWildcardVersion(Ver, V.Id); 659 660 // Symbol themselves might know their versions because symbols 661 // can contain versions in the form of <name>@<version>. 662 // Let them parse and update their names to exclude version suffix. 663 for (Symbol *Sym : SymVector) 664 Sym->parseSymbolVersion(); 665 } 666 667 template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t, 668 uint8_t, bool, InputFile *); 669 template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t, 670 uint8_t, bool, InputFile *); 671 template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, uint8_t, uint8_t, 672 uint8_t, bool, InputFile *); 673 template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, uint8_t, uint8_t, 674 uint8_t, bool, InputFile *); 675 676 template void SymbolTable::addCombinedLTOObject<ELF32LE>(); 677 template void SymbolTable::addCombinedLTOObject<ELF32BE>(); 678 template void SymbolTable::addCombinedLTOObject<ELF64LE>(); 679 template void SymbolTable::addCombinedLTOObject<ELF64BE>(); 680 681 template void 682 SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &, 683 const object::Archive::Symbol); 684 template void 685 SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &, 686 const object::Archive::Symbol); 687 template void 688 SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &, 689 const object::Archive::Symbol); 690 template void 691 SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &, 692 const object::Archive::Symbol); 693 694 template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &); 695 template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); 696 template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); 697 template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); 698 699 template void SymbolTable::fetchLazy<ELF32LE>(Symbol *); 700 template void SymbolTable::fetchLazy<ELF32BE>(Symbol *); 701 template void SymbolTable::fetchLazy<ELF64LE>(Symbol *); 702 template void SymbolTable::fetchLazy<ELF64BE>(Symbol *); 703