687 lines · cpp
1//===- Symbols.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "Symbols.h"10#include "Driver.h"11#include "InputFiles.h"12#include "InputSection.h"13#include "OutputSections.h"14#include "SymbolTable.h"15#include "SyntheticSections.h"16#include "Target.h"17#include "Writer.h"18#include "llvm/Demangle/Demangle.h"19#include "llvm/Support/Compiler.h"20#include <cstring>21 22using namespace llvm;23using namespace llvm::object;24using namespace llvm::ELF;25using namespace lld;26using namespace lld::elf;27 28static_assert(sizeof(SymbolUnion) <= 64, "SymbolUnion too large");29 30template <typename T> struct AssertSymbol {31 static_assert(std::is_trivially_destructible<T>(),32 "Symbol types must be trivially destructible");33 static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");34 static_assert(alignof(T) <= alignof(SymbolUnion),35 "SymbolUnion not aligned enough");36};37 38[[maybe_unused]] static inline void assertSymbols() {39 AssertSymbol<Defined>();40 AssertSymbol<CommonSymbol>();41 AssertSymbol<Undefined>();42 AssertSymbol<SharedSymbol>();43 AssertSymbol<LazySymbol>();44}45 46// Returns a symbol for an error message.47static std::string maybeDemangleSymbol(Ctx &ctx, StringRef symName) {48 return ctx.arg.demangle ? demangle(symName.str()) : symName.str();49}50 51std::string elf::toStr(Ctx &ctx, const elf::Symbol &sym) {52 StringRef name = sym.getName();53 std::string ret = maybeDemangleSymbol(ctx, name);54 55 const char *suffix = sym.getVersionSuffix();56 if (*suffix == '@')57 ret += suffix;58 return ret;59}60 61const ELFSyncStream &elf::operator<<(const ELFSyncStream &s,62 const Symbol *sym) {63 return s << toStr(s.ctx, *sym);64}65 66static uint64_t getSymVA(Ctx &ctx, const Symbol &sym, int64_t addend) {67 switch (sym.kind()) {68 case Symbol::DefinedKind: {69 auto &d = cast<Defined>(sym);70 SectionBase *isec = d.section;71 72 // This is an absolute symbol.73 if (!isec)74 return d.value;75 76 assert(isec != &InputSection::discarded);77 78 uint64_t offset = d.value;79 80 // An object in an SHF_MERGE section might be referenced via a81 // section symbol (as a hack for reducing the number of local82 // symbols).83 // Depending on the addend, the reference via a section symbol84 // refers to a different object in the merge section.85 // Since the objects in the merge section are not necessarily86 // contiguous in the output, the addend can thus affect the final87 // VA in a non-linear way.88 // To make this work, we incorporate the addend into the section89 // offset (and zero out the addend for later processing) so that90 // we find the right object in the section.91 if (d.isSection())92 offset += addend;93 94 // In the typical case, this is actually very simple and boils95 // down to adding together 3 numbers:96 // 1. The address of the output section.97 // 2. The offset of the input section within the output section.98 // 3. The offset within the input section (this addition happens99 // inside InputSection::getOffset).100 //101 // If you understand the data structures involved with this next102 // line (and how they get built), then you have a pretty good103 // understanding of the linker.104 uint64_t va = isec->getVA(offset);105 if (d.isSection())106 va -= addend;107 108 // MIPS relocatable files can mix regular and microMIPS code.109 // Linker needs to distinguish such code. To do so microMIPS110 // symbols has the `STO_MIPS_MICROMIPS` flag in the `st_other`111 // field. Unfortunately, the `MIPS::relocate()` method has112 // a symbol value only. To pass type of the symbol (regular/microMIPS)113 // to that routine as well as other places where we write114 // a symbol value as-is (.dynamic section, `Elf_Ehdr::e_entry`115 // field etc) do the same trick as compiler uses to mark microMIPS116 // for CPU - set the less-significant bit.117 if (ctx.arg.emachine == EM_MIPS && isMicroMips(ctx) &&118 ((sym.stOther & STO_MIPS_MICROMIPS) || sym.hasFlag(NEEDS_COPY)))119 va |= 1;120 121 if (d.isTls() && !ctx.arg.relocatable) {122 // Use the address of the TLS segment's first section rather than the123 // segment's address, because segment addresses aren't initialized until124 // after sections are finalized. (e.g. Measuring the size of .rela.dyn125 // for Android relocation packing requires knowing TLS symbol addresses126 // during section finalization.)127 if (!ctx.tlsPhdr || !ctx.tlsPhdr->firstSec) {128 Err(ctx) << d.file129 << " has an STT_TLS symbol but doesn't have a PT_TLS segment";130 return 0;131 }132 return va - ctx.tlsPhdr->firstSec->addr;133 }134 return va;135 }136 case Symbol::SharedKind:137 case Symbol::UndefinedKind:138 return 0;139 case Symbol::LazyKind:140 llvm_unreachable("lazy symbol reached writer");141 case Symbol::CommonKind:142 llvm_unreachable("common symbol reached writer");143 case Symbol::PlaceholderKind:144 llvm_unreachable("placeholder symbol reached writer");145 }146 llvm_unreachable("invalid symbol kind");147}148 149uint64_t Symbol::getVA(Ctx &ctx, int64_t addend) const {150 return getSymVA(ctx, *this, addend) + addend;151}152 153uint64_t Symbol::getGotVA(Ctx &ctx) const {154 if (gotInIgot)155 return ctx.in.igotPlt->getVA() + getGotPltOffset(ctx);156 return ctx.in.got->getVA() + getGotOffset(ctx);157}158 159uint64_t Symbol::getGotOffset(Ctx &ctx) const {160 return getGotIdx(ctx) * ctx.target->gotEntrySize;161}162 163uint64_t Symbol::getGotPltVA(Ctx &ctx) const {164 if (isInIplt)165 return ctx.in.igotPlt->getVA() + getGotPltOffset(ctx);166 return ctx.in.gotPlt->getVA() + getGotPltOffset(ctx);167}168 169uint64_t Symbol::getGotPltOffset(Ctx &ctx) const {170 if (isInIplt)171 return getPltIdx(ctx) * ctx.target->gotEntrySize;172 return (getPltIdx(ctx) + ctx.target->gotPltHeaderEntriesNum) *173 ctx.target->gotEntrySize;174}175 176uint64_t Symbol::getPltVA(Ctx &ctx) const {177 uint64_t outVA = isInIplt ? ctx.in.iplt->getVA() +178 getPltIdx(ctx) * ctx.target->ipltEntrySize179 : ctx.in.plt->getVA() + ctx.in.plt->headerSize +180 getPltIdx(ctx) * ctx.target->pltEntrySize;181 182 // While linking microMIPS code PLT code are always microMIPS183 // code. Set the less-significant bit to track that fact.184 // See detailed comment in the `getSymVA` function.185 if (ctx.arg.emachine == EM_MIPS && isMicroMips(ctx))186 outVA |= 1;187 return outVA;188}189 190uint64_t Symbol::getSize() const {191 if (const auto *dr = dyn_cast<Defined>(this))192 return dr->size;193 return cast<SharedSymbol>(this)->size;194}195 196OutputSection *Symbol::getOutputSection() const {197 if (auto *s = dyn_cast<Defined>(this)) {198 if (auto *sec = s->section)199 return sec->getOutputSection();200 return nullptr;201 }202 return nullptr;203}204 205// If a symbol name contains '@', the characters after that is206// a symbol version name. This function parses that.207void Symbol::parseSymbolVersion(Ctx &ctx) {208 // Return if localized by a local: pattern in a version script.209 if (versionId == VER_NDX_LOCAL)210 return;211 StringRef s = getName();212 size_t pos = s.find('@');213 if (pos == StringRef::npos)214 return;215 StringRef verstr = s.substr(pos + 1);216 217 // Truncate the symbol name so that it doesn't include the version string.218 nameSize = pos;219 220 if (verstr.empty())221 return;222 223 // If this is not in this DSO, it is not a definition.224 if (!isDefined())225 return;226 227 // '@@' in a symbol name means the default version.228 // It is usually the most recent one.229 bool isDefault = (verstr[0] == '@');230 if (isDefault)231 verstr = verstr.substr(1);232 233 for (const VersionDefinition &ver : namedVersionDefs(ctx)) {234 if (ver.name != verstr)235 continue;236 237 if (isDefault)238 versionId = ver.id;239 else240 versionId = ver.id | VERSYM_HIDDEN;241 return;242 }243 244 // It is an error if the specified version is not defined.245 // Usually version script is not provided when linking executable,246 // but we may still want to override a versioned symbol from DSO,247 // so we do not report error in this case. We also do not error248 // if the symbol has a local version as it won't be in the dynamic249 // symbol table.250 if (ctx.arg.shared && versionId != VER_NDX_LOCAL)251 ErrAlways(ctx) << file << ": symbol " << s << " has undefined version "252 << verstr;253}254 255void Symbol::extract(Ctx &ctx) const {256 assert(file->lazy);257 file->lazy = false;258 parseFile(ctx, file);259}260 261uint8_t Symbol::computeBinding(Ctx &ctx) const {262 auto v = visibility();263 if ((v != STV_DEFAULT && v != STV_PROTECTED) || versionId == VER_NDX_LOCAL)264 return STB_LOCAL;265 if (binding == STB_GNU_UNIQUE && !ctx.arg.gnuUnique)266 return STB_GLOBAL;267 return binding;268}269 270// Print out a log message for --trace-symbol.271void elf::printTraceSymbol(const Symbol &sym, StringRef name) {272 std::string s;273 if (sym.isUndefined())274 s = ": reference to ";275 else if (sym.isLazy())276 s = ": lazy definition of ";277 else if (sym.isShared())278 s = ": shared definition of ";279 else if (sym.isCommon())280 s = ": common definition of ";281 else282 s = ": definition of ";283 284 Msg(sym.file->ctx) << sym.file << s << name;285}286 287static void recordWhyExtract(Ctx &ctx, const InputFile *reference,288 const InputFile &extracted, const Symbol &sym) {289 ctx.whyExtractRecords.emplace_back(toStr(ctx, reference), &extracted, sym);290}291 292void elf::maybeWarnUnorderableSymbol(Ctx &ctx, const Symbol *sym) {293 if (!ctx.arg.warnSymbolOrdering)294 return;295 296 // If UnresolvedPolicy::Ignore is used, no "undefined symbol" error/warning is297 // emitted. It makes sense to not warn on undefined symbols (excluding those298 // demoted by demoteSymbols).299 //300 // Note, ld.bfd --symbol-ordering-file= does not warn on undefined symbols,301 // but we don't have to be compatible here.302 if (sym->isUndefined() && !cast<Undefined>(sym)->discardedSecIdx &&303 ctx.arg.unresolvedSymbols == UnresolvedPolicy::Ignore)304 return;305 306 const InputFile *file = sym->file;307 auto *d = dyn_cast<Defined>(sym);308 309 auto report = [&](StringRef s) { Warn(ctx) << file << s << sym->getName(); };310 311 if (sym->isUndefined()) {312 if (cast<Undefined>(sym)->discardedSecIdx)313 report(": unable to order discarded symbol: ");314 else315 report(": unable to order undefined symbol: ");316 } else if (sym->isShared())317 report(": unable to order shared symbol: ");318 else if (d && !d->section)319 report(": unable to order absolute symbol: ");320 else if (d && isa<OutputSection>(d->section))321 report(": unable to order synthetic symbol: ");322 else if (d && !d->section->isLive())323 report(": unable to order discarded symbol: ");324}325 326// Returns true if a symbol can be replaced at load-time by a symbol327// with the same name defined in other ELF executable or DSO.328bool elf::computeIsPreemptible(Ctx &ctx, const Symbol &sym) {329 assert(!sym.isLocal() || sym.isPlaceholder());330 331 // Only symbols with default visibility that appear in dynsym can be332 // preempted. Symbols with protected visibility cannot be preempted.333 if (sym.visibility() != STV_DEFAULT)334 return false;335 336 // At this point copy relocations have not been created yet.337 // Shared symbols are preemptible. Undefined symbols are preemptible338 // when zDynamicUndefined (default in dynamic linking). Weakness is not339 // checked, though undefined non-weak would typically trigger relocation340 // errors unless options like -z undefs are used.341 if (!sym.isDefined())342 return !sym.isUndefined() || ctx.arg.zDynamicUndefined;343 344 if (!ctx.arg.shared)345 return false;346 347 // If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is348 // specified and the symbol is STT_FUNC, the symbol is preemptible iff it is349 // in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of350 // -Bsymbolic-functions.351 if (ctx.arg.symbolic ||352 (ctx.arg.bsymbolic == BsymbolicKind::NonWeak &&353 sym.binding != STB_WEAK) ||354 (ctx.arg.bsymbolic == BsymbolicKind::Functions && sym.isFunc()) ||355 (ctx.arg.bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() &&356 sym.binding != STB_WEAK))357 return sym.inDynamicList;358 return true;359}360 361void elf::parseVersionAndComputeIsPreemptible(Ctx &ctx) {362 // Symbol themselves might know their versions because symbols363 // can contain versions in the form of <name>@<version>.364 // Let them parse and update their names to exclude version suffix.365 // In addition, compute isExported and isPreemptible.366 for (Symbol *sym : ctx.symtab->getSymbols()) {367 if (sym->hasVersionSuffix)368 sym->parseSymbolVersion(ctx);369 if (sym->computeBinding(ctx) == STB_LOCAL) {370 sym->isExported = false;371 continue;372 }373 if (!sym->isDefined() && !sym->isCommon()) {374 sym->isPreemptible = computeIsPreemptible(ctx, *sym);375 } else if (ctx.arg.exportDynamic &&376 (sym->isUsedInRegularObj || !sym->ltoCanOmit)) {377 sym->isExported = true;378 sym->isPreemptible = computeIsPreemptible(ctx, *sym);379 }380 }381}382 383// Merge symbol properties.384//385// When we have many symbols of the same name, we choose one of them,386// and that's the result of symbol resolution. However, symbols that387// were not chosen still affect some symbol properties.388void Symbol::mergeProperties(const Symbol &other) {389 // DSO symbols do not affect visibility in the output.390 if (!other.isShared() && other.visibility() != STV_DEFAULT) {391 uint8_t v = visibility(), ov = other.visibility();392 setVisibility(v == STV_DEFAULT ? ov : std::min(v, ov));393 }394}395 396void Symbol::resolve(Ctx &ctx, const Undefined &other) {397 if (other.visibility() != STV_DEFAULT) {398 uint8_t v = visibility(), ov = other.visibility();399 setVisibility(v == STV_DEFAULT ? ov : std::min(v, ov));400 }401 // An undefined symbol with non default visibility must be satisfied402 // in the same DSO.403 //404 // If this is a non-weak defined symbol in a discarded section, override the405 // existing undefined symbol for better error message later.406 if (isPlaceholder() || (isShared() && other.visibility() != STV_DEFAULT) ||407 (isUndefined() && other.binding != STB_WEAK && other.discardedSecIdx)) {408 other.overwrite(*this);409 return;410 }411 412 if (traced)413 printTraceSymbol(other, getName());414 415 if (isLazy()) {416 // An undefined weak will not extract archive members. See comment on Lazy417 // in Symbols.h for the details.418 if (other.binding == STB_WEAK) {419 binding = STB_WEAK;420 type = other.type;421 return;422 }423 424 // Do extra check for --warn-backrefs.425 //426 // --warn-backrefs is an option to prevent an undefined reference from427 // extracting an archive member written earlier in the command line. It can428 // be used to keep compatibility with GNU linkers to some degree. I'll429 // explain the feature and why you may find it useful in this comment.430 //431 // lld's symbol resolution semantics is more relaxed than traditional Unix432 // linkers. For example,433 //434 // ld.lld foo.a bar.o435 //436 // succeeds even if bar.o contains an undefined symbol that has to be437 // resolved by some object file in foo.a. Traditional Unix linkers don't438 // allow this kind of backward reference, as they visit each file only once439 // from left to right in the command line while resolving all undefined440 // symbols at the moment of visiting.441 //442 // In the above case, since there's no undefined symbol when a linker visits443 // foo.a, no files are pulled out from foo.a, and because the linker forgets444 // about foo.a after visiting, it can't resolve undefined symbols in bar.o445 // that could have been resolved otherwise.446 //447 // That lld accepts more relaxed form means that (besides it'd make more448 // sense) you can accidentally write a command line or a build file that449 // works only with lld, even if you have a plan to distribute it to wider450 // users who may be using GNU linkers. With --warn-backrefs, you can detect451 // a library order that doesn't work with other Unix linkers.452 //453 // The option is also useful to detect cyclic dependencies between static454 // archives. Again, lld accepts455 //456 // ld.lld foo.a bar.a457 //458 // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is459 // handled as an error.460 //461 // Here is how the option works. We assign a group ID to each file. A file462 // with a smaller group ID can pull out object files from an archive file463 // with an equal or greater group ID. Otherwise, it is a reverse dependency464 // and an error.465 //466 // A file outside --{start,end}-group gets a fresh ID when instantiated. All467 // files within the same --{start,end}-group get the same group ID. E.g.468 //469 // ld.lld A B --start-group C D --end-group E470 //471 // A forms group 0. B form group 1. C and D (including their member object472 // files) form group 2. E forms group 3. I think that you can see how this473 // group assignment rule simulates the traditional linker's semantics.474 bool backref = ctx.arg.warnBackrefs && file->groupId < other.file->groupId;475 extract(ctx);476 477 if (!ctx.arg.whyExtract.empty())478 recordWhyExtract(ctx, other.file, *file, *this);479 480 // We don't report backward references to weak symbols as they can be481 // overridden later.482 //483 // A traditional linker does not error for -ldef1 -lref -ldef2 (linking484 // sandwich), where def2 may or may not be the same as def1. We don't want485 // to warn for this case, so dismiss the warning if we see a subsequent lazy486 // definition. this->file needs to be saved because in the case of LTO it487 // may be reset to internalFile or be replaced with a file named lto.tmp.488 if (backref && !isWeak())489 ctx.backwardReferences.try_emplace(this,490 std::make_pair(other.file, file));491 return;492 }493 494 // Undefined symbols in a SharedFile do not change the binding.495 if (isa<SharedFile>(other.file))496 return;497 498 if (isUndefined() || isShared()) {499 // The binding will be weak if there is at least one reference and all are500 // weak. The binding has one opportunity to change to weak: if the first501 // reference is weak.502 if (other.binding != STB_WEAK || !referenced)503 binding = other.binding;504 }505}506 507// Compare two symbols. Return true if the new symbol should win.508bool Symbol::shouldReplace(Ctx &ctx, const Defined &other) const {509 if (LLVM_UNLIKELY(isCommon())) {510 if (ctx.arg.warnCommon)511 Warn(ctx) << "common " << getName() << " is overridden";512 return !other.isWeak();513 }514 if (!isDefined())515 return true;516 517 // Incoming STB_GLOBAL overrides STB_WEAK/STB_GNU_UNIQUE. -fgnu-unique changes518 // some vague linkage data in COMDAT from STB_WEAK to STB_GNU_UNIQUE. Treat519 // STB_GNU_UNIQUE like STB_WEAK so that we prefer the first among all520 // STB_WEAK/STB_GNU_UNIQUE copies. If we prefer an incoming STB_GNU_UNIQUE to521 // an existing STB_WEAK, there may be discarded section errors because the522 // selected copy may be in a non-prevailing COMDAT.523 return !isGlobal() && other.isGlobal();524}525 526void elf::reportDuplicate(Ctx &ctx, const Symbol &sym, const InputFile *newFile,527 InputSectionBase *errSec, uint64_t errOffset) {528 if (ctx.arg.allowMultipleDefinition)529 return;530 // In glibc<2.32, crti.o has .gnu.linkonce.t.__x86.get_pc_thunk.bx, which531 // is sort of proto-comdat. There is actually no duplicate if we have532 // full support for .gnu.linkonce.533 const Defined *d = dyn_cast<Defined>(&sym);534 if (!d || d->getName() == "__x86.get_pc_thunk.bx")535 return;536 // Allow absolute symbols with the same value for GNU ld compatibility.537 if (!d->section && !errSec && errOffset && d->value == errOffset)538 return;539 if (!d->section || !errSec) {540 Err(ctx) << "duplicate symbol: " << &sym << "\n>>> defined in " << sym.file541 << "\n>>> defined in " << newFile;542 return;543 }544 545 // Construct and print an error message in the form of:546 //547 // ld.lld: error: duplicate symbol: foo548 // >>> defined at bar.c:30549 // >>> bar.o (/home/alice/src/bar.o)550 // >>> defined at baz.c:563551 // >>> baz.o in archive libbaz.a552 auto *sec1 = cast<InputSectionBase>(d->section);553 auto diag = Err(ctx);554 diag << "duplicate symbol: " << &sym << "\n>>> defined at ";555 auto tell = diag.tell();556 diag << sec1->getSrcMsg(sym, d->value);557 if (tell != diag.tell())558 diag << "\n>>> ";559 diag << sec1->getObjMsg(d->value) << "\n>>> defined at ";560 tell = diag.tell();561 diag << errSec->getSrcMsg(sym, errOffset);562 if (tell != diag.tell())563 diag << "\n>>> ";564 diag << errSec->getObjMsg(errOffset);565}566 567void Symbol::checkDuplicate(Ctx &ctx, const Defined &other) const {568 if (isDefined() && !isWeak() && !other.isWeak())569 reportDuplicate(ctx, *this, other.file,570 dyn_cast_or_null<InputSectionBase>(other.section),571 other.value);572}573 574void Symbol::resolve(Ctx &ctx, const CommonSymbol &other) {575 if (other.visibility() != STV_DEFAULT) {576 uint8_t v = visibility(), ov = other.visibility();577 setVisibility(v == STV_DEFAULT ? ov : std::min(v, ov));578 }579 if (isDefined() && !isWeak()) {580 if (ctx.arg.warnCommon)581 Warn(ctx) << "common " << getName() << " is overridden";582 return;583 }584 585 if (CommonSymbol *oldSym = dyn_cast<CommonSymbol>(this)) {586 if (ctx.arg.warnCommon)587 Warn(ctx) << "multiple common of " << getName();588 oldSym->alignment = std::max(oldSym->alignment, other.alignment);589 if (oldSym->size < other.size) {590 oldSym->file = other.file;591 oldSym->size = other.size;592 }593 return;594 }595 596 if (auto *s = dyn_cast<SharedSymbol>(this)) {597 // Increase st_size if the shared symbol has a larger st_size. The shared598 // symbol may be created from common symbols. The fact that some object599 // files were linked into a shared object first should not change the600 // regular rule that picks the largest st_size.601 uint64_t size = s->size;602 other.overwrite(*this);603 if (size > cast<CommonSymbol>(this)->size)604 cast<CommonSymbol>(this)->size = size;605 } else {606 other.overwrite(*this);607 }608}609 610void Symbol::resolve(Ctx &ctx, const Defined &other) {611 if (other.visibility() != STV_DEFAULT) {612 uint8_t v = visibility(), ov = other.visibility();613 setVisibility(v == STV_DEFAULT ? ov : std::min(v, ov));614 }615 if (shouldReplace(ctx, other))616 other.overwrite(*this);617}618 619void Symbol::resolve(Ctx &ctx, const LazySymbol &other) {620 if (isPlaceholder()) {621 other.overwrite(*this);622 return;623 }624 625 if (LLVM_UNLIKELY(!isUndefined())) {626 // See the comment in resolve(Ctx &, const Undefined &).627 if (isDefined()) {628 ctx.backwardReferences.erase(this);629 } else if (isCommon() && ctx.arg.fortranCommon &&630 other.file->shouldExtractForCommon(getName())) {631 // For common objects, we want to look for global or weak definitions that632 // should be extracted as the canonical definition instead.633 ctx.backwardReferences.erase(this);634 other.overwrite(*this);635 other.extract(ctx);636 }637 return;638 }639 640 // An undefined weak will not extract archive members. See comment on Lazy in641 // Symbols.h for the details.642 if (isWeak()) {643 uint8_t ty = type;644 other.overwrite(*this);645 type = ty;646 binding = STB_WEAK;647 return;648 }649 650 const InputFile *oldFile = file;651 other.extract(ctx);652 if (!ctx.arg.whyExtract.empty())653 recordWhyExtract(ctx, oldFile, *file, *this);654}655 656void Symbol::resolve(Ctx &ctx, const SharedSymbol &other) {657 isExported = true;658 if (isPlaceholder()) {659 other.overwrite(*this);660 return;661 }662 if (isCommon()) {663 // See the comment in resolveCommon() above.664 if (other.size > cast<CommonSymbol>(this)->size)665 cast<CommonSymbol>(this)->size = other.size;666 return;667 }668 if (visibility() == STV_DEFAULT && (isUndefined() || isLazy())) {669 // An undefined symbol with non default visibility must be satisfied670 // in the same DSO.671 uint8_t bind = binding;672 other.overwrite(*this);673 binding = bind;674 } else if (traced)675 printTraceSymbol(other, getName());676}677 678void Defined::overwrite(Symbol &sym) const {679 if (isa_and_nonnull<SharedFile>(sym.file))680 sym.versionId = VER_NDX_GLOBAL;681 Symbol::overwrite(sym, DefinedKind);682 auto &s = static_cast<Defined &>(sym);683 s.value = value;684 s.size = size;685 s.section = section;686}687