xref: /llvm-project-15.0.7/lld/ELF/Symbols.cpp (revision 7fd3849b)
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Symbols.h"
10 #include "Driver.h"
11 #include "InputFiles.h"
12 #include "InputSection.h"
13 #include "OutputSections.h"
14 #include "SyntheticSections.h"
15 #include "Target.h"
16 #include "Writer.h"
17 #include "lld/Common/ErrorHandler.h"
18 #include "lld/Common/Strings.h"
19 #include <cstring>
20 
21 using namespace llvm;
22 using namespace llvm::object;
23 using namespace llvm::ELF;
24 using namespace lld;
25 using namespace lld::elf;
26 
27 std::string lld::toString(const elf::Symbol &sym) {
28   StringRef name = sym.getName();
29   std::string ret = demangle(name, config->demangle);
30 
31   const char *suffix = sym.getVersionSuffix();
32   if (*suffix == '@')
33     ret += suffix;
34   return ret;
35 }
36 
37 Defined *ElfSym::bss;
38 Defined *ElfSym::etext1;
39 Defined *ElfSym::etext2;
40 Defined *ElfSym::edata1;
41 Defined *ElfSym::edata2;
42 Defined *ElfSym::end1;
43 Defined *ElfSym::end2;
44 Defined *ElfSym::globalOffsetTable;
45 Defined *ElfSym::mipsGp;
46 Defined *ElfSym::mipsGpDisp;
47 Defined *ElfSym::mipsLocalGp;
48 Defined *ElfSym::relaIpltStart;
49 Defined *ElfSym::relaIpltEnd;
50 Defined *ElfSym::riscvGlobalPointer;
51 Defined *ElfSym::tlsModuleBase;
52 DenseMap<const Symbol *, std::pair<const InputFile *, const InputFile *>>
53     elf::backwardReferences;
54 SmallVector<SymbolAux, 0> elf::symAux;
55 
56 static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
57   switch (sym.kind()) {
58   case Symbol::DefinedKind: {
59     auto &d = cast<Defined>(sym);
60     SectionBase *isec = d.section;
61 
62     // This is an absolute symbol.
63     if (!isec)
64       return d.value;
65 
66     assert(isec != &InputSection::discarded);
67 
68     uint64_t offset = d.value;
69 
70     // An object in an SHF_MERGE section might be referenced via a
71     // section symbol (as a hack for reducing the number of local
72     // symbols).
73     // Depending on the addend, the reference via a section symbol
74     // refers to a different object in the merge section.
75     // Since the objects in the merge section are not necessarily
76     // contiguous in the output, the addend can thus affect the final
77     // VA in a non-linear way.
78     // To make this work, we incorporate the addend into the section
79     // offset (and zero out the addend for later processing) so that
80     // we find the right object in the section.
81     if (d.isSection())
82       offset += addend;
83 
84     // In the typical case, this is actually very simple and boils
85     // down to adding together 3 numbers:
86     // 1. The address of the output section.
87     // 2. The offset of the input section within the output section.
88     // 3. The offset within the input section (this addition happens
89     //    inside InputSection::getOffset).
90     //
91     // If you understand the data structures involved with this next
92     // line (and how they get built), then you have a pretty good
93     // understanding of the linker.
94     uint64_t va = isec->getVA(offset);
95     if (d.isSection())
96       va -= addend;
97 
98     // MIPS relocatable files can mix regular and microMIPS code.
99     // Linker needs to distinguish such code. To do so microMIPS
100     // symbols has the `STO_MIPS_MICROMIPS` flag in the `st_other`
101     // field. Unfortunately, the `MIPS::relocate()` method has
102     // a symbol value only. To pass type of the symbol (regular/microMIPS)
103     // to that routine as well as other places where we write
104     // a symbol value as-is (.dynamic section, `Elf_Ehdr::e_entry`
105     // field etc) do the same trick as compiler uses to mark microMIPS
106     // for CPU - set the less-significant bit.
107     if (config->emachine == EM_MIPS && isMicroMips() &&
108         ((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsCopy))
109       va |= 1;
110 
111     if (d.isTls() && !config->relocatable) {
112       // Use the address of the TLS segment's first section rather than the
113       // segment's address, because segment addresses aren't initialized until
114       // after sections are finalized. (e.g. Measuring the size of .rela.dyn
115       // for Android relocation packing requires knowing TLS symbol addresses
116       // during section finalization.)
117       if (!Out::tlsPhdr || !Out::tlsPhdr->firstSec)
118         fatal(toString(d.file) +
119               " has an STT_TLS symbol but doesn't have an SHF_TLS section");
120       return va - Out::tlsPhdr->firstSec->addr;
121     }
122     return va;
123   }
124   case Symbol::SharedKind:
125   case Symbol::UndefinedKind:
126     return 0;
127   case Symbol::LazyObjectKind:
128     llvm_unreachable("lazy symbol reached writer");
129   case Symbol::CommonKind:
130     llvm_unreachable("common symbol reached writer");
131   case Symbol::PlaceholderKind:
132     llvm_unreachable("placeholder symbol reached writer");
133   }
134   llvm_unreachable("invalid symbol kind");
135 }
136 
137 uint64_t Symbol::getVA(int64_t addend) const {
138   return getSymVA(*this, addend) + addend;
139 }
140 
141 uint64_t Symbol::getGotVA() const {
142   if (gotInIgot)
143     return in.igotPlt->getVA() + getGotPltOffset();
144   return in.got->getVA() + getGotOffset();
145 }
146 
147 uint64_t Symbol::getGotOffset() const {
148   return getGotIdx() * target->gotEntrySize;
149 }
150 
151 uint64_t Symbol::getGotPltVA() const {
152   if (isInIplt)
153     return in.igotPlt->getVA() + getGotPltOffset();
154   return in.gotPlt->getVA() + getGotPltOffset();
155 }
156 
157 uint64_t Symbol::getGotPltOffset() const {
158   if (isInIplt)
159     return getPltIdx() * target->gotEntrySize;
160   return (getPltIdx() + target->gotPltHeaderEntriesNum) * target->gotEntrySize;
161 }
162 
163 uint64_t Symbol::getPltVA() const {
164   uint64_t outVA = isInIplt
165                        ? in.iplt->getVA() + getPltIdx() * target->ipltEntrySize
166                        : in.plt->getVA() + in.plt->headerSize +
167                              getPltIdx() * target->pltEntrySize;
168 
169   // While linking microMIPS code PLT code are always microMIPS
170   // code. Set the less-significant bit to track that fact.
171   // See detailed comment in the `getSymVA` function.
172   if (config->emachine == EM_MIPS && isMicroMips())
173     outVA |= 1;
174   return outVA;
175 }
176 
177 uint64_t Symbol::getSize() const {
178   if (const auto *dr = dyn_cast<Defined>(this))
179     return dr->size;
180   return cast<SharedSymbol>(this)->size;
181 }
182 
183 OutputSection *Symbol::getOutputSection() const {
184   if (auto *s = dyn_cast<Defined>(this)) {
185     if (auto *sec = s->section)
186       return sec->getOutputSection();
187     return nullptr;
188   }
189   return nullptr;
190 }
191 
192 // If a symbol name contains '@', the characters after that is
193 // a symbol version name. This function parses that.
194 void Symbol::parseSymbolVersion() {
195   // Return if localized by a local: pattern in a version script.
196   if (versionId == VER_NDX_LOCAL)
197     return;
198   StringRef s = getName();
199   size_t pos = s.find('@');
200   if (pos == StringRef::npos)
201     return;
202   StringRef verstr = s.substr(pos + 1);
203 
204   // Truncate the symbol name so that it doesn't include the version string.
205   nameSize = pos;
206 
207   if (verstr.empty())
208     return;
209 
210   // If this is not in this DSO, it is not a definition.
211   if (!isDefined())
212     return;
213 
214   // '@@' in a symbol name means the default version.
215   // It is usually the most recent one.
216   bool isDefault = (verstr[0] == '@');
217   if (isDefault)
218     verstr = verstr.substr(1);
219 
220   for (const VersionDefinition &ver : namedVersionDefs()) {
221     if (ver.name != verstr)
222       continue;
223 
224     if (isDefault)
225       versionId = ver.id;
226     else
227       versionId = ver.id | VERSYM_HIDDEN;
228     return;
229   }
230 
231   // It is an error if the specified version is not defined.
232   // Usually version script is not provided when linking executable,
233   // but we may still want to override a versioned symbol from DSO,
234   // so we do not report error in this case. We also do not error
235   // if the symbol has a local version as it won't be in the dynamic
236   // symbol table.
237   if (config->shared && versionId != VER_NDX_LOCAL)
238     error(toString(file) + ": symbol " + s + " has undefined version " +
239           verstr);
240 }
241 
242 void Symbol::extract() const {
243   if (file->lazy) {
244     file->lazy = false;
245     parseFile(file);
246   }
247 }
248 
249 uint8_t Symbol::computeBinding() const {
250   if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) ||
251       versionId == VER_NDX_LOCAL)
252     return STB_LOCAL;
253   if (binding == STB_GNU_UNIQUE && !config->gnuUnique)
254     return STB_GLOBAL;
255   return binding;
256 }
257 
258 bool Symbol::includeInDynsym() const {
259   if (computeBinding() == STB_LOCAL)
260     return false;
261   if (!isDefined() && !isCommon())
262     // This should unconditionally return true, unfortunately glibc -static-pie
263     // expects undefined weak symbols not to exist in .dynsym, e.g.
264     // __pthread_mutex_lock reference in _dl_add_to_namespace_list,
265     // __pthread_initialize_minimal reference in csu/libc-start.c.
266     return !(isUndefWeak() && config->noDynamicLinker);
267 
268   return exportDynamic || inDynamicList;
269 }
270 
271 // Print out a log message for --trace-symbol.
272 void elf::printTraceSymbol(const Symbol &sym, StringRef name) {
273   std::string s;
274   if (sym.isUndefined())
275     s = ": reference to ";
276   else if (sym.isLazy())
277     s = ": lazy definition of ";
278   else if (sym.isShared())
279     s = ": shared definition of ";
280   else if (sym.isCommon())
281     s = ": common definition of ";
282   else
283     s = ": definition of ";
284 
285   message(toString(sym.file) + s + name);
286 }
287 
288 static void recordWhyExtract(const InputFile *reference,
289                              const InputFile &extracted, const Symbol &sym) {
290   driver->whyExtract.emplace_back(toString(reference), &extracted, sym);
291 }
292 
293 void elf::maybeWarnUnorderableSymbol(const Symbol *sym) {
294   if (!config->warnSymbolOrdering)
295     return;
296 
297   // If UnresolvedPolicy::Ignore is used, no "undefined symbol" error/warning
298   // is emitted. It makes sense to not warn on undefined symbols.
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() &&
303       config->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(toString(file) + s + sym->getName()); };
310 
311   if (sym->isUndefined())
312     report(": unable to order undefined symbol: ");
313   else if (sym->isShared())
314     report(": unable to order shared symbol: ");
315   else if (d && !d->section)
316     report(": unable to order absolute symbol: ");
317   else if (d && isa<OutputSection>(d->section))
318     report(": unable to order synthetic symbol: ");
319   else if (d && !d->section->isLive())
320     report(": unable to order discarded symbol: ");
321 }
322 
323 // Returns true if a symbol can be replaced at load-time by a symbol
324 // with the same name defined in other ELF executable or DSO.
325 bool elf::computeIsPreemptible(const Symbol &sym) {
326   assert(!sym.isLocal() || sym.isPlaceholder());
327 
328   // Only symbols with default visibility that appear in dynsym can be
329   // preempted. Symbols with protected visibility cannot be preempted.
330   if (!sym.includeInDynsym() || sym.visibility != STV_DEFAULT)
331     return false;
332 
333   // At this point copy relocations have not been created yet, so any
334   // symbol that is not defined locally is preemptible.
335   if (!sym.isDefined())
336     return true;
337 
338   if (!config->shared)
339     return false;
340 
341   // If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is
342   // specified and the symbol is STT_FUNC, the symbol is preemptible iff it is
343   // in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of
344   // -Bsymbolic-functions.
345   if (config->symbolic ||
346       (config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) ||
347       (config->bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() &&
348        sym.binding != STB_WEAK))
349     return sym.inDynamicList;
350   return true;
351 }
352 
353 void elf::reportBackrefs() {
354   for (auto &it : backwardReferences) {
355     const Symbol &sym = *it.first;
356     std::string to = toString(it.second.second);
357     // Some libraries have known problems and can cause noise. Filter them out
358     // with --warn-backrefs-exclude=. to may look like *.o or *.a(*.o).
359     bool exclude = false;
360     for (const llvm::GlobPattern &pat : config->warnBackrefsExclude)
361       if (pat.match(to)) {
362         exclude = true;
363         break;
364       }
365     if (!exclude)
366       warn("backward reference detected: " + sym.getName() + " in " +
367            toString(it.second.first) + " refers to " + to);
368   }
369 }
370 
371 static uint8_t getMinVisibility(uint8_t va, uint8_t vb) {
372   if (va == STV_DEFAULT)
373     return vb;
374   if (vb == STV_DEFAULT)
375     return va;
376   return std::min(va, vb);
377 }
378 
379 // Merge symbol properties.
380 //
381 // When we have many symbols of the same name, we choose one of them,
382 // and that's the result of symbol resolution. However, symbols that
383 // were not chosen still affect some symbol properties.
384 void Symbol::mergeProperties(const Symbol &other) {
385   if (other.exportDynamic)
386     exportDynamic = true;
387 
388   // DSO symbols do not affect visibility in the output.
389   if (!other.isShared())
390     visibility = getMinVisibility(visibility, other.visibility);
391 }
392 
393 void Symbol::resolve(const Symbol &other) {
394   mergeProperties(other);
395 
396   if (isPlaceholder()) {
397     replace(other);
398     return;
399   }
400 
401   switch (other.kind()) {
402   case Symbol::UndefinedKind:
403     resolveUndefined(cast<Undefined>(other));
404     break;
405   case Symbol::CommonKind:
406     resolveCommon(cast<CommonSymbol>(other));
407     break;
408   case Symbol::DefinedKind:
409     resolveDefined(cast<Defined>(other));
410     break;
411   case Symbol::LazyObjectKind:
412     resolveLazy(cast<LazyObject>(other));
413     break;
414   case Symbol::SharedKind:
415     resolveShared(cast<SharedSymbol>(other));
416     break;
417   case Symbol::PlaceholderKind:
418     llvm_unreachable("bad symbol kind");
419   }
420 }
421 
422 void Symbol::resolveUndefined(const Undefined &other) {
423   // An undefined symbol with non default visibility must be satisfied
424   // in the same DSO.
425   //
426   // If this is a non-weak defined symbol in a discarded section, override the
427   // existing undefined symbol for better error message later.
428   if ((isShared() && other.visibility != STV_DEFAULT) ||
429       (isUndefined() && other.binding != STB_WEAK && other.discardedSecIdx)) {
430     replace(other);
431     return;
432   }
433 
434   if (traced)
435     printTraceSymbol(other, getName());
436 
437   if (isLazy()) {
438     // An undefined weak will not extract archive members. See comment on Lazy
439     // in Symbols.h for the details.
440     if (other.binding == STB_WEAK) {
441       binding = STB_WEAK;
442       type = other.type;
443       return;
444     }
445 
446     // Do extra check for --warn-backrefs.
447     //
448     // --warn-backrefs is an option to prevent an undefined reference from
449     // extracting an archive member written earlier in the command line. It can
450     // be used to keep compatibility with GNU linkers to some degree. I'll
451     // explain the feature and why you may find it useful in this comment.
452     //
453     // lld's symbol resolution semantics is more relaxed than traditional Unix
454     // linkers. For example,
455     //
456     //   ld.lld foo.a bar.o
457     //
458     // succeeds even if bar.o contains an undefined symbol that has to be
459     // resolved by some object file in foo.a. Traditional Unix linkers don't
460     // allow this kind of backward reference, as they visit each file only once
461     // from left to right in the command line while resolving all undefined
462     // symbols at the moment of visiting.
463     //
464     // In the above case, since there's no undefined symbol when a linker visits
465     // foo.a, no files are pulled out from foo.a, and because the linker forgets
466     // about foo.a after visiting, it can't resolve undefined symbols in bar.o
467     // that could have been resolved otherwise.
468     //
469     // That lld accepts more relaxed form means that (besides it'd make more
470     // sense) you can accidentally write a command line or a build file that
471     // works only with lld, even if you have a plan to distribute it to wider
472     // users who may be using GNU linkers. With --warn-backrefs, you can detect
473     // a library order that doesn't work with other Unix linkers.
474     //
475     // The option is also useful to detect cyclic dependencies between static
476     // archives. Again, lld accepts
477     //
478     //   ld.lld foo.a bar.a
479     //
480     // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
481     // handled as an error.
482     //
483     // Here is how the option works. We assign a group ID to each file. A file
484     // with a smaller group ID can pull out object files from an archive file
485     // with an equal or greater group ID. Otherwise, it is a reverse dependency
486     // and an error.
487     //
488     // A file outside --{start,end}-group gets a fresh ID when instantiated. All
489     // files within the same --{start,end}-group get the same group ID. E.g.
490     //
491     //   ld.lld A B --start-group C D --end-group E
492     //
493     // A forms group 0. B form group 1. C and D (including their member object
494     // files) form group 2. E forms group 3. I think that you can see how this
495     // group assignment rule simulates the traditional linker's semantics.
496     bool backref = config->warnBackrefs && other.file &&
497                    file->groupId < other.file->groupId;
498     extract();
499 
500     if (!config->whyExtract.empty())
501       recordWhyExtract(other.file, *file, *this);
502 
503     // We don't report backward references to weak symbols as they can be
504     // overridden later.
505     //
506     // A traditional linker does not error for -ldef1 -lref -ldef2 (linking
507     // sandwich), where def2 may or may not be the same as def1. We don't want
508     // to warn for this case, so dismiss the warning if we see a subsequent lazy
509     // definition. this->file needs to be saved because in the case of LTO it
510     // may be reset to nullptr or be replaced with a file named lto.tmp.
511     if (backref && !isWeak())
512       backwardReferences.try_emplace(this, std::make_pair(other.file, file));
513     return;
514   }
515 
516   // Undefined symbols in a SharedFile do not change the binding.
517   if (isa_and_nonnull<SharedFile>(other.file))
518     return;
519 
520   if (isUndefined() || isShared()) {
521     // The binding will be weak if there is at least one reference and all are
522     // weak. The binding has one opportunity to change to weak: if the first
523     // reference is weak.
524     if (other.binding != STB_WEAK || !referenced)
525       binding = other.binding;
526   }
527 }
528 
529 // Compare two symbols. Return true if the new symbol should win.
530 bool Symbol::compare(const Defined &other) const {
531   if (LLVM_UNLIKELY(isCommon())) {
532     if (config->warnCommon)
533       warn("common " + getName() + " is overridden");
534     return !other.isWeak();
535   }
536   if (!isDefined())
537     return true;
538 
539   // .symver foo,foo@@VER unfortunately creates two defined symbols: foo and
540   // foo@@VER. In GNU ld, if foo and foo@@VER are in the same file, foo is
541   // ignored. In our implementation, when this is foo, this->getName() may still
542   // contain @@, return true in this case as well.
543   if (LLVM_UNLIKELY(file == other.file)) {
544     if (other.getName().contains("@@"))
545       return true;
546     if (getName().contains("@@"))
547       return false;
548   }
549 
550   return isWeak() && !other.isWeak();
551 }
552 
553 void elf::reportDuplicate(const Symbol &sym, InputFile *newFile,
554                           InputSectionBase *errSec, uint64_t errOffset) {
555   if (config->allowMultipleDefinition)
556     return;
557   const Defined *d = cast<Defined>(&sym);
558   if (!d->section || !errSec) {
559     error("duplicate symbol: " + toString(sym) + "\n>>> defined in " +
560           toString(sym.file) + "\n>>> defined in " + toString(newFile));
561     return;
562   }
563 
564   // Construct and print an error message in the form of:
565   //
566   //   ld.lld: error: duplicate symbol: foo
567   //   >>> defined at bar.c:30
568   //   >>>            bar.o (/home/alice/src/bar.o)
569   //   >>> defined at baz.c:563
570   //   >>>            baz.o in archive libbaz.a
571   auto *sec1 = cast<InputSectionBase>(d->section);
572   std::string src1 = sec1->getSrcMsg(sym, d->value);
573   std::string obj1 = sec1->getObjMsg(d->value);
574   std::string src2 = errSec->getSrcMsg(sym, errOffset);
575   std::string obj2 = errSec->getObjMsg(errOffset);
576 
577   std::string msg = "duplicate symbol: " + toString(sym) + "\n>>> defined at ";
578   if (!src1.empty())
579     msg += src1 + "\n>>>            ";
580   msg += obj1 + "\n>>> defined at ";
581   if (!src2.empty())
582     msg += src2 + "\n>>>            ";
583   msg += obj2;
584   error(msg);
585 }
586 
587 void Symbol::checkDuplicate(const Defined &other) const {
588   if (isDefined() && !isWeak() && !other.isWeak())
589     reportDuplicate(*this, other.file,
590                     dyn_cast_or_null<InputSectionBase>(other.section),
591                     other.value);
592 }
593 
594 void Symbol::resolveCommon(const CommonSymbol &other) {
595   if (isDefined() && !isWeak()) {
596     if (config->warnCommon)
597       warn("common " + getName() + " is overridden");
598     return;
599   }
600 
601   if (CommonSymbol *oldSym = dyn_cast<CommonSymbol>(this)) {
602     if (config->warnCommon)
603       warn("multiple common of " + getName());
604     oldSym->alignment = std::max(oldSym->alignment, other.alignment);
605     if (oldSym->size < other.size) {
606       oldSym->file = other.file;
607       oldSym->size = other.size;
608     }
609     return;
610   }
611 
612   if (auto *s = dyn_cast<SharedSymbol>(this)) {
613     // Increase st_size if the shared symbol has a larger st_size. The shared
614     // symbol may be created from common symbols. The fact that some object
615     // files were linked into a shared object first should not change the
616     // regular rule that picks the largest st_size.
617     uint64_t size = s->size;
618     replace(other);
619     if (size > cast<CommonSymbol>(this)->size)
620       cast<CommonSymbol>(this)->size = size;
621   } else {
622     replace(other);
623   }
624 }
625 
626 void Symbol::resolveDefined(const Defined &other) {
627   if (compare(other))
628     replace(other);
629 }
630 
631 void Symbol::resolveLazy(const LazyObject &other) {
632   // For common objects, we want to look for global or weak definitions that
633   // should be extracted as the canonical definition instead.
634   if (LLVM_UNLIKELY(isCommon()) && elf::config->fortranCommon &&
635       other.file->shouldExtractForCommon(getName())) {
636     backwardReferences.erase(this);
637     replace(other);
638     other.extract();
639     return;
640   }
641 
642   if (!isUndefined()) {
643     // See the comment in resolveUndefined().
644     if (isDefined())
645       backwardReferences.erase(this);
646     return;
647   }
648 
649   // An undefined weak will not extract archive members. See comment on Lazy in
650   // Symbols.h for the details.
651   if (isWeak()) {
652     uint8_t ty = type;
653     replace(other);
654     type = ty;
655     binding = STB_WEAK;
656     return;
657   }
658 
659   const InputFile *oldFile = file;
660   other.extract();
661   if (!config->whyExtract.empty())
662     recordWhyExtract(oldFile, *file, *this);
663 }
664 
665 void Symbol::resolveShared(const SharedSymbol &other) {
666   if (isCommon()) {
667     // See the comment in resolveCommon() above.
668     if (other.size > cast<CommonSymbol>(this)->size)
669       cast<CommonSymbol>(this)->size = other.size;
670     return;
671   }
672   if (visibility == STV_DEFAULT && (isUndefined() || isLazy())) {
673     // An undefined symbol with non default visibility must be satisfied
674     // in the same DSO.
675     uint8_t bind = binding;
676     replace(other);
677     binding = bind;
678   } else if (traced)
679     printTraceSymbol(other, getName());
680 }
681