[PATCH] D86762: [ELF] Add documentation for --warn-backrefs: a layering check tool

Fangrui Song via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 21:57:58 PDT 2020


MaskRay created this revision.
MaskRay added reviewers: grimar, jhenderson, psmith, ruiu, smeenai, thakis.
Herald added subscribers: llvm-commits, arphaman, emaste.
Herald added a reviewer: espindola.
Herald added a project: LLVM.
MaskRay requested review of this revision.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D86762

Files:
  lld/docs/ELF/warn_backrefs.rst
  lld/docs/index.rst


Index: lld/docs/index.rst
===================================================================
--- lld/docs/index.rst
+++ lld/docs/index.rst
@@ -177,3 +177,4 @@
    Partitions
    ReleaseNotes
    ELF/linker_script
+   ELF/warn_backrefs
Index: lld/docs/ELF/warn_backrefs.rst
===================================================================
--- /dev/null
+++ lld/docs/ELF/warn_backrefs.rst
@@ -0,0 +1,76 @@
+--warn-backrefs
+===============
+
+Linkers process input files from left to right and maintain the current set of
+undefined symbols. If an archive member (or an object file surrounded by
+``--start-lib`` and ``-end-lib``) does not satisfy any undefined symbol, it
+will be dropped by a traditional linker, and the link will fail with an
+``undefined reference`` error.
+
+    ld def.a ref.o
+
+LLD's archive selection semantics is more relaxed (commutative to some extent).
+The link succeeds even if an archive (``def.a``) is redundant at the time it is
+processed while a future archive/object file (``ref.o``) needs it.
+
+``--warn-backrefs`` can identify such an invocation which may be incompatible
+with a traditional linker.
+
+    % ld.lld --warn-backrefs ... -lB -lA
+    ld.lld: warning: backward reference detected: system in A.a(a.o) refers to B.a(b.o)
+
+    % ld.lld --warn-backrefs ... --start-lib B/b.o --end-lib --start-lib A/a.o --end-lib
+    ld.lld: warning: backward reference detected: system in A/a.o refers to B/b.o
+
+    # To suppress the warning, you can specify --warn-backrefs-exclude=<glob> to match B/b.o or B.a(b.o)
+
+The traditional behavior actually has a nice property: it is a layering check
+tool which enforces a topological order of libraries.  ``--warn-backrefs``
+retrieves the advantage with better and actionable feedback: which library
+defines the symbol. The diagnostic above indicates that there is a missing
+dependency A -> B. There are two main cases and one rare case:
+
+* If adding the dependency does not form a cycle: conceptually ``A`` is higher
+  level library while ``B`` is at a lower level. When you are developing an
+  application ``P`` which depends on ``A``, but does not directly depend on
+  ``B``, your link may fail surprisingly with ``undefined symbol:
+  symbol_defined_in_B`` if the used/linked part of ``A`` happens to need some
+  components of ``B``. It is inappropriate for ``P`` to add a dependency on
+  ``B`` since ``P`` does not use ``B`` directly.
+* If adding the dependency forms a cycle, e.g. ``B->C->A ~> B``. ``A``
+  is supposed to be at the lowest level while ``B`` is supposed to be at the
+  highest level. When you are developing ``C_test`` testing ``C``, your link may
+  fail surprisingly with ``undefined symbol`` if there is somehow a dependency on
+  some components of ``B``. You could fix the issue by adding the missing
+  dependency (``B``), however, then every test (``A_test``, ``B_test``,
+  ``C_test``) will link against every library. This breaks the motivation
+  breaking ``B``, ``C`` and ``A`` into separate libraries and makes binaries
+  unnecessarily large.  Moreover, the layering violation makes lower-level
+  libraries (e.g.  ``A``) vulnerable to changes to higher-level libraries (e.g.
+  ``B``, ``C``).
+* (Rare) ``A.a B A2.so``: a traditional linker picks the definition from
+  ``A2.so`` while LLD picks the definition from ``A.a``. ``A`` may be an
+  interceptor (e.g. it provides some optimized libc functions and A2 is libc),
+  ``B`` does not need to know about ``A``, and ``A`` may be pulled into the
+  link by other part of the program. In this case, add ``-Wl,--warn-backrefs-exclude=B/b.o``.
+
+Resolution:
+
+* Add a dependency from ``A`` to ``B``.
+* The reference may be unintended and can be removed.
+* In the case of circular dependency, sometimes merging the libraries are the best.
+
+There is a variant of ``A.a B A2.so``: ``A.a B A2.a``. I name this a "linking
+sandwich problem".
+
+* ``A2.a`` may be a replicate of ``A.a``. This is redundant but benign. In some
+  cases ``A.a`` and ``B`` should be surrounded by a pair of ``--start-group``
+  and ``--end-group``. This is especially common among system libraries (e.g.
+  ``-lc __isnanl references -lm``, ``-lc _IO_funlockfile references
+  -lpthread``, ``-lc __gcc_personality_v0 references -lgcc_eh``, and
+  ``-lpthread _Unwind_GetCFA references -lunwind``).
+* ``A2.a`` provides a different definition. In a C++ case this is likely a
+  violation of the One Definition Rule.
+
+``--warn-backrefs`` does not check this problem. We probably need a dedicated
+option for this ODR violation checking feature.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D86762.288530.patch
Type: text/x-patch
Size: 4612 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200828/b61ca3bb/attachment.bin>


More information about the llvm-commits mailing list