diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 59b2950c5caf..7a8e387239f5 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -529,48 +529,27 @@ void Symbol::resolveUndefined(const Undefined &other) { // Compare two symbols. Return 1 if the new symbol should win, -1 if // the new symbol should lose, or 0 if there is a conflict. -int Symbol::compare(const Symbol *other) const { - assert(other->isDefined() || other->isCommon()); - - if (!isDefined() && !isCommon()) - return 1; +bool Symbol::compare(const Defined &other) const { + if (LLVM_UNLIKELY(isCommon())) { + if (config->warnCommon) + warn("common " + getName() + " is overridden"); + return !other.isWeak(); + } + if (!isDefined()) + return true; // .symver foo,foo@@VER unfortunately creates two defined symbols: foo and // foo@@VER. In GNU ld, if foo and foo@@VER are in the same file, foo is // ignored. In our implementation, when this is foo, this->getName() may still - // contain @@, return 1 in this case as well. - if (file == other->file) { - if (other->getName().contains("@@")) - return 1; + // contain @@, return true in this case as well. + if (LLVM_UNLIKELY(file == other.file)) { + if (other.getName().contains("@@")) + return true; if (getName().contains("@@")) - return -1; + return false; } - if (other->isWeak()) - return -1; - - if (isWeak()) - return 1; - - if (isCommon() && other->isCommon()) { - if (config->warnCommon) - warn("multiple common of " + getName()); - return 0; - } - - if (isCommon()) { - if (config->warnCommon) - warn("common " + getName() + " is overridden"); - return 1; - } - - if (other->isCommon()) { - if (config->warnCommon) - warn("common " + getName() + " is overridden"); - return -1; - } - - return 0; + return isWeak() && !other.isWeak(); } void elf::reportDuplicate(const Symbol &sym, InputFile *newFile, @@ -608,45 +587,46 @@ void elf::reportDuplicate(const Symbol &sym, InputFile *newFile, } void Symbol::checkDuplicate(const Defined &other) const { - if (compare(&other) == 0) + if (isDefined() && !isWeak() && !other.isWeak()) reportDuplicate(*this, other.file, dyn_cast_or_null(other.section), other.value); } void Symbol::resolveCommon(const CommonSymbol &other) { - int cmp = compare(&other); - if (cmp < 0) + if (isDefined() && !isWeak()) { + if (config->warnCommon) + warn("common " + getName() + " is overridden"); return; + } - if (cmp > 0) { - if (auto *s = dyn_cast(this)) { - // Increase st_size if the shared symbol has a larger st_size. The shared - // symbol may be created from common symbols. The fact that some object - // files were linked into a shared object first should not change the - // regular rule that picks the largest st_size. - uint64_t size = s->size; - replace(other); - if (size > cast(this)->size) - cast(this)->size = size; - } else { - replace(other); + if (CommonSymbol *oldSym = dyn_cast(this)) { + if (config->warnCommon) + warn("multiple common of " + getName()); + oldSym->alignment = std::max(oldSym->alignment, other.alignment); + if (oldSym->size < other.size) { + oldSym->file = other.file; + oldSym->size = other.size; } return; } - CommonSymbol *oldSym = cast(this); - - oldSym->alignment = std::max(oldSym->alignment, other.alignment); - if (oldSym->size < other.size) { - oldSym->file = other.file; - oldSym->size = other.size; + if (auto *s = dyn_cast(this)) { + // Increase st_size if the shared symbol has a larger st_size. The shared + // symbol may be created from common symbols. The fact that some object + // files were linked into a shared object first should not change the + // regular rule that picks the largest st_size. + uint64_t size = s->size; + replace(other); + if (size > cast(this)->size) + cast(this)->size = size; + } else { + replace(other); } } void Symbol::resolveDefined(const Defined &other) { - int cmp = compare(&other); - if (cmp > 0) + if (compare(other)) replace(other); } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index be4eb49d34a9..920569bcecf9 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -228,7 +228,7 @@ private: void resolveLazy(const LazyObject &other); void resolveShared(const SharedSymbol &other); - int compare(const Symbol *other) const; + bool compare(const Defined &other) const; inline size_t getSymbolSize() const;