[lld] r332061 - [ELF] --warn-backref: don't report backref to weak symbols.
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu May 10 16:53:05 PDT 2018
Author: maskray
Date: Thu May 10 16:53:05 2018
New Revision: 332061
URL: http://llvm.org/viewvc/llvm-project?rev=332061&view=rev
Log:
[ELF] --warn-backref: don't report backref to weak symbols.
Summary:
Suppose we visit symbols in this order:
1. weak definition of foo in a lazy object
2. reference of foo
3 (optional). definition of foo
bfd/gold allows 123 but not 12.
Current --warn-backrefs implementation will report both cases as a backward reference. With this change, both 123 (intended) and 12 (unintended) are allowed. The usage of weak definitions usually imply there are also global definitions, so the trade-off is justified.
Reviewers: ruiu, espindola
Subscribers: emaste, arichardson, llvm-commits
Differential Revision: https://reviews.llvm.org/D46624
Modified:
lld/trunk/ELF/SymbolTable.cpp
lld/trunk/test/ELF/warn-backrefs.s
Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=332061&r1=332060&r2=332061&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Thu May 10 16:53:05 2018
@@ -288,63 +288,6 @@ template <class ELFT> Symbol *SymbolTabl
static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
-// Do extra check for --warn-backrefs.
-//
-// --warn-backrefs is an option to prevent an undefined reference from
-// fetching an archive member written earlier in the command line. It can be
-// used to keep your program compatible with GNU linkers after you switch to
-// lld. I'll explain the feature and why you may find it useful in this
-// comment.
-//
-// lld's symbol resolution semantics is more relaxed than traditional Unix
-// linkers. For example,
-//
-// ld.lld foo.a bar.o
-//
-// succeeds even if bar.o contains an undefined symbol that have to be
-// resolved by some object file in foo.a. Traditional Unix linkers don't
-// allow this kind of backward reference, as they visit each file only once
-// from left to right in the command line while resolving all undefined
-// symbols at the moment of visiting.
-//
-// In the above case, since there's no undefined symbol when a linker visits
-// foo.a, no files are pulled out from foo.a, and because the linker forgets
-// about foo.a after visiting, it can't resolve undefined symbols in bar.o
-// that could have been resolved otherwise.
-//
-// That lld accepts more relaxed form means that (besides it'd make more
-// sense) you can accidentally write a command line or a build file that
-// works only with lld, even if you have a plan to distribute it to wider
-// users who may be using GNU linkers. With --warn-backrefs, you can detect
-// a library order that doesn't work with other Unix linkers.
-//
-// The option is also useful to detect cyclic dependencies between static
-// archives. Again, lld accepts
-//
-// ld.lld foo.a bar.a
-//
-// even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
-// handled as an error.
-//
-// Here is how the option works. We assign a group ID to each file. A file
-// with a smaller group ID can pull out object files from an archive file
-// with an equal or greater group ID. Otherwise, it is a reverse dependency
-// and an error.
-//
-// A file outside --{start,end}-group gets a fresh ID when instantiated. All
-// files within the same --{start,end}-group get the same group ID. E.g.
-//
-// ld.lld A B --start-group C D --end-group E
-//
-// A forms group 0. B form group 1. C and D (including their member object
-// files) form group 2. E forms group 3. I think that you can see how this
-// group assignment rule simulates the traditional linker's semantics.
-static void checkBackrefs(StringRef Name, InputFile *Old, InputFile *New) {
- if (Config->WarnBackrefs && New && Old->GroupId < New->GroupId)
- warn("backward reference detected: " + Name + " in " + toString(New) +
- " refers to " + toString(Old));
-}
-
template <class ELFT>
Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
uint8_t StOther, uint8_t Type,
@@ -377,8 +320,64 @@ Symbol *SymbolTable::addUndefined(String
return S;
}
- checkBackrefs(Name, S->File, File);
+ // Do extra check for --warn-backrefs.
+ //
+ // --warn-backrefs is an option to prevent an undefined reference from
+ // fetching an archive member written earlier in the command line. It can be
+ // used to keep compatibility with GNU linkers to some degree.
+ // I'll explain the feature and why you may find it useful in this comment.
+ //
+ // lld's symbol resolution semantics is more relaxed than traditional Unix
+ // linkers. For example,
+ //
+ // ld.lld foo.a bar.o
+ //
+ // succeeds even if bar.o contains an undefined symbol that has to be
+ // resolved by some object file in foo.a. Traditional Unix linkers don't
+ // allow this kind of backward reference, as they visit each file only once
+ // from left to right in the command line while resolving all undefined
+ // symbols at the moment of visiting.
+ //
+ // In the above case, since there's no undefined symbol when a linker visits
+ // foo.a, no files are pulled out from foo.a, and because the linker forgets
+ // about foo.a after visiting, it can't resolve undefined symbols in bar.o
+ // that could have been resolved otherwise.
+ //
+ // That lld accepts more relaxed form means that (besides it'd make more
+ // sense) you can accidentally write a command line or a build file that
+ // works only with lld, even if you have a plan to distribute it to wider
+ // users who may be using GNU linkers. With --warn-backrefs, you can detect
+ // a library order that doesn't work with other Unix linkers.
+ //
+ // The option is also useful to detect cyclic dependencies between static
+ // archives. Again, lld accepts
+ //
+ // ld.lld foo.a bar.a
+ //
+ // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is
+ // handled as an error.
+ //
+ // Here is how the option works. We assign a group ID to each file. A file
+ // with a smaller group ID can pull out object files from an archive file
+ // with an equal or greater group ID. Otherwise, it is a reverse dependency
+ // and an error.
+ //
+ // A file outside --{start,end}-group gets a fresh ID when instantiated. All
+ // files within the same --{start,end}-group get the same group ID. E.g.
+ //
+ // ld.lld A B --start-group C D --end-group E
+ //
+ // A forms group 0. B form group 1. C and D (including their member object
+ // files) form group 2. E forms group 3. I think that you can see how this
+ // group assignment rule simulates the traditional linker's semantics.
+ bool Backref =
+ Config->WarnBackrefs && File && S->File->GroupId < File->GroupId;
fetchLazy<ELFT>(S);
+ // We don't report backward references to weak symbols as they can be
+ // overriden later.
+ if (Backref && S->Binding != STB_WEAK)
+ warn("backward reference detected: " + Name + " in " + toString(File) +
+ " refers to " + toString(S->File));
}
return S;
}
Modified: lld/trunk/test/ELF/warn-backrefs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/warn-backrefs.s?rev=332061&r1=332060&r2=332061&view=diff
==============================================================================
--- lld/trunk/test/ELF/warn-backrefs.s (original)
+++ lld/trunk/test/ELF/warn-backrefs.s Thu May 10 16:53:05 2018
@@ -39,6 +39,10 @@
# RUN: echo ".globl foo; foo: call bar" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t4.o
# RUN: ld.lld --fatal-warnings --warn-backrefs %t1.o --start-lib %t3.o %t4.o --end-lib -o %t.exe
+# We don't report backward references to weak symbols as they can be overriden later.
+# RUN: echo ".weak foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t5.o
+# RUN: ld.lld --fatal-warnings --warn-backrefs --start-lib %t5.o --end-lib %t1.o %t2.o -o %t.exe
+
.globl _start, foo
_start:
call foo
More information about the llvm-commits
mailing list