brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.3 KiB · 220ec99 Raw
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