Skip to content
Snippets Groups Projects
Commit b4dca7f0 authored by Rui Ueyama's avatar Rui Ueyama
Browse files

Select new undefined atom rather than old one if other conditions are the same.

We can add multiple undefined atoms having the same name to the symbol table.
If such atoms are added, the symbol table compares their canBeNull attributes,
and select one having a stronger constraint. If their canBeNulls are the same,
the choice is arbitrary. Currently it choose the existing one.

This patch changes the preference, so that the symbol table choose the new one
if the new atom has a greater canBeNull or a fallback atom. This shouldn't
change the behavior except the case described below.

A new undefined atom may have a new fallback atom attribute. By choosing the new
atom, we can update the fallback atom during Core Linking. PE/COFF actually need
that. For example, _lseek is an alias for __lseek on Windows. One of an object
file in OLDNAMES.LIB has an undefined atom for _lseek with the fallback to
__lseek. When the linker tries to resolve _read, it supposed to read the file
from OLDNAMES.LIB and use the new fallback from the file. Currently LLD cannot
handle such case because duplicate undefined atoms with the same attributes are
ignored.

Differential Revision: http://llvm-reviews.chandlerc.com/D2161

llvm-svn: 194777
parent 014192db
No related branches found
No related tags found
No related merge requests found
...@@ -172,28 +172,42 @@ void SymbolTable::addByName(const Atom & newAtom) { ...@@ -172,28 +172,42 @@ void SymbolTable::addByName(const Atom & newAtom) {
} }
break; break;
case NCR_DupUndef: { case NCR_DupUndef: {
const UndefinedAtom* existingUndef = const UndefinedAtom* existingUndef = dyn_cast<UndefinedAtom>(existing);
dyn_cast<UndefinedAtom>(existing); const UndefinedAtom* newUndef = dyn_cast<UndefinedAtom>(&newAtom);
const UndefinedAtom* newUndef = assert(existingUndef != nullptr);
dyn_cast<UndefinedAtom>(&newAtom); assert(newUndef != nullptr);
assert(existingUndef != nullptr);
assert(newUndef != nullptr); bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
if (existingUndef->canBeNull() == newUndef->canBeNull()) { if (!sameCanBeNull &&
useNew = false; _context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
} else { llvm::errs() << "lld warning: undefined symbol "
if (_context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { << existingUndef->name()
// FIXME: need diagonstics interface for writing warning messages << " has different weakness in "
llvm::errs() << "lld warning: undefined symbol " << existingUndef->file().path()
<< existingUndef->name() << " and in " << newUndef->file().path() << "\n";
<< " has different weakness in " }
<< existingUndef->file().path()
<< " and in " const UndefinedAtom *existingFallback = existingUndef->fallback();
<< newUndef->file().path(); const UndefinedAtom *newFallback = newUndef->fallback();
} bool hasDifferentFallback =
useNew = (newUndef->canBeNull() < existingUndef->canBeNull()); (existingFallback && newFallback &&
} existingFallback->name() != newFallback->name());
if (hasDifferentFallback) {
llvm::errs() << "lld warning: undefined symbol "
<< existingUndef->name() << " has different fallback: "
<< existingFallback->name() << " in "
<< existingUndef->file().path() << " and "
<< newFallback->name() << " in "
<< newUndef->file().path() << "\n";
} }
bool hasNewFallback = newUndef->fallback();
if (sameCanBeNull)
useNew = hasNewFallback;
else
useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
break; break;
}
case NCR_DupShLib: { case NCR_DupShLib: {
const SharedLibraryAtom* curShLib = const SharedLibraryAtom* curShLib =
dyn_cast<SharedLibraryAtom>(existing); dyn_cast<SharedLibraryAtom>(existing);
......
# RUN: lld -core %s | FileCheck %s # RUN: lld -core %s 2> %t.err | FileCheck %s
# RUN: FileCheck -check-prefix=ERROR %s < %t.err
# #
# Test that undefined symbols preserve their attributes and merge properly # Test that undefined symbols preserve their attributes and merge properly
...@@ -8,86 +9,75 @@ ...@@ -8,86 +9,75 @@
undefined-atoms: undefined-atoms:
- name: regular_func - name: regular_func
can-be-null: never can-be-null: never
- name: weak_import_func - name: weak_import_func
can-be-null: at-runtime can-be-null: at-runtime
- name: weak_func - name: weak_func
can-be-null: at-buildtime can-be-null: at-buildtime
- name: bar1 - name: bar1
can-be-null: never can-be-null: never
- name: bar2 - name: bar2
can-be-null: at-runtime can-be-null: at-runtime
- name: bar3 - name: bar3
can-be-null: at-buildtime can-be-null: at-buildtime
- name: bar4 - name: bar4
can-be-null: never can-be-null: never
- name: bar5 - name: bar5
can-be-null: at-runtime can-be-null: at-runtime
- name: bar6 - name: bar6
can-be-null: at-buildtime can-be-null: at-buildtime
- name: bar7 - name: bar7
can-be-null: never can-be-null: never
- name: bar8 - name: bar8
can-be-null: at-runtime can-be-null: at-runtime
fallback:
name: baz1
- name: bar9 - name: bar9
can-be-null: at-buildtime can-be-null: at-buildtime
fallback:
name: baz2
--- ---
undefined-atoms: undefined-atoms:
- name: bar1 - name: bar1
can-be-null: never can-be-null: never
- name: bar2 - name: bar2
can-be-null: at-runtime can-be-null: at-runtime
- name: bar3 - name: bar3
can-be-null: at-buildtime can-be-null: at-buildtime
- name: bar4 - name: bar4
can-be-null: at-runtime can-be-null: at-runtime
- name: bar5 - name: bar5
can-be-null: at-buildtime can-be-null: at-buildtime
- name: bar6 - name: bar6
can-be-null: never can-be-null: never
- name: bar7 - name: bar7
can-be-null: at-buildtime can-be-null: at-buildtime
- name: bar8 - name: bar8
can-be-null: never can-be-null: never
- name: bar9 - name: bar9
can-be-null: at-runtime can-be-null: at-runtime
fallback:
name: baz3
... ...
# CHECK: - name: regular_func # CHECK: - name: regular_func
# CHECK: - name: weak_import_func # CHECK-NEXT: - name: weak_import_func
# CHECK: can-be-null: at-runtime # CHECK-NEXT: can-be-null: at-runtime
# CHECK: - name: weak_func # CHECK-NEXT: - name: weak_func
# CHECK: can-be-null: at-buildtime # CHECK-NEXT: can-be-null: at-buildtime
# CHECK: - name: bar1 # CHECK-NEXT: - name: bar1
# CHECK: - name: bar2 # CHECK-NEXT: - name: bar2
# CHECK: can-be-null: at-runtime # CHECK-NEXT: can-be-null: at-runtime
# CHECK: - name: bar3 # CHECK-NEXT: - name: bar3
# CHECK: can-be-null: at-buildtime # CHECK-NEXT: can-be-null: at-buildtime
# CHECK: - name: bar4 # CHECK-NEXT: - name: bar4
# CHECK: - name: bar5 # CHECK-NEXT: - name: bar5
# CHECK: can-be-null: at-runtime # CHECK-NEXT: can-be-null: at-runtime
# CHECK: - name: bar7 # CHECK-NEXT: - name: bar7
# CHECK: - name: bar6 # CHECK-NEXT: - name: bar6
# CHECK: - name: bar8 # CHECK-NEXT: - name: bar8
# CHECK: - name: bar9 # CHECK-NEXT: - name: bar9
# CHECK: can-be-null: at-runtime # CHECK-NEXT: can-be-null: at-runtime
# CHECK: ... # CHECK-NEXT: fallback:
# CHECK-NEXT: name: baz3
# ERROR: undefined symbol bar9 has different fallback: baz2 in and baz3 in
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment