[llvm-branch-commits] [lld] 724ed20 - [ELF] Hint -z nostart-stop-gc for __start_ undefined references

Fangrui Song via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Dec 14 16:52:38 PST 2021


Author: Fangrui Song
Date: 2021-12-14T16:49:13-08:00
New Revision: 724ed207b76055d80264aa98b3da8566ef60d321

URL: https://github.com/llvm/llvm-project/commit/724ed207b76055d80264aa98b3da8566ef60d321
DIFF: https://github.com/llvm/llvm-project/commit/724ed207b76055d80264aa98b3da8566ef60d321.diff

LOG: [ELF] Hint -z nostart-stop-gc for __start_ undefined references

Make users aware what to do with ld.lld 13.0.0 / GNU ld<2015-10 --gc-sections
behavior.

Differential Revision: https://reviews.llvm.org/D114830

(cherry picked from commit 353fe72ca3d77f4bbe53132577a88424def172e8)

Added: 
    lld/docs/ELF/start-stop-gc.rst
    lld/test/ELF/gc-sections-startstop-hint.s

Modified: 
    lld/ELF/Relocations.cpp
    lld/docs/index.rst

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 537859f9e0b5b..fefd6f21f590e 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -927,6 +927,12 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
     msg +=
         "\n>>> the vtable symbol may be undefined because the class is missing "
         "its key function (see https://lld.llvm.org/missingkeyfunction)";
+  if (config->gcSections && config->zStartStopGC &&
+      sym.getName().startswith("__start_")) {
+    msg += "\n>>> the encapsulation symbol needs to be retained under "
+           "--gc-sections properly; consider -z nostart-stop-gc "
+           "(see https://lld.llvm.org/ELF/start-stop-gc)";
+  }
 
   if (undef.isWarning)
     warn(msg);

diff  --git a/lld/docs/ELF/start-stop-gc.rst b/lld/docs/ELF/start-stop-gc.rst
new file mode 100644
index 0000000000000..18ccc26defc1f
--- /dev/null
+++ b/lld/docs/ELF/start-stop-gc.rst
@@ -0,0 +1,66 @@
+-z start-stop-gc
+================
+
+If your ``-Wl,--gc-sections`` build fail with a linker error like this:
+
+    error: undefined symbol: __start_meta
+    >>> referenced by {{.*}}
+    >>> the encapsulation symbol needs to be retained under --gc-sections properly; consider -z nostart-stop-gc (see https://lld.llvm.org/ELF/start-stop-gc)
+
+it is likely your C identifier name sections are not properly annotated to
+suffice under ``--gc-sections``.
+
+``__start_meta`` and ``__stop_meta`` are sometimed called encapsulation
+symbols. In October 2015, GNU ld switched behavior and made a ``__start_meta``
+reference from a live section retain all ``meta`` input sections. This
+conservative behavior works for existing code which does not take GC into fair
+consideration, but unnecessarily increases sizes for modern metadata section
+usage which desires precise GC.
+
+GNU ld 2.37 added ``-z start-stop-gc`` to restore the traditional behavior
+ld.lld 13.0.0 defaults to ``-z start-stop-gc`` and supports ``-z nostart-stop-gc``
+to switch to the conservative behavior.
+
+The Apple ld64 linker has a similar ``section$start`` feature and always
+allowed GC (like ``-z start-stop-gc``).
+
+Annotate C identifier name sections
+-----------------------------------
+
+A C identifier name section (``meta``) sometimes depends on another section.
+Let that section reference ``meta`` via a relocation.
+
+.. code-block:: c
+
+  asm(".pushsection .init_array,\"aw\",%init_array\n" \
+      ".reloc ., BFD_RELOC_NONE, meta\n"              \
+      ".popsection\n")
+
+If a relocation is inconvenient, consider using ``__attribute__((retain))``
+(GCC 11 with modern binutils, Clang 13).
+
+.. code-block:: c
+
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wattributes"
+  __attribute__((retain,used,section("meta")))
+  static const char dummy[0];
+  #pragma GCC diagnostic pop
+
+GCC before 11 and Clang before 13 do not recognize ``__attribute__((retain))``,
+so ``-Wattributes`` may need to be ignored. On ELF targets,
+``__attribute__((used))`` prevents compiler discarding, but does not affect
+linker ``--gc-sections``.
+
+In a macro, you may use:
+
+.. code-block:: c
+
+  _Pragma("GCC diagnostic push")
+  _Pragma("GCC diagnostic ignored \"-Wattributes\"")
+  ...
+  _Pragma("GCC diagnostic pop")
+
+If you use the ``SECTIONS`` command in a linker script, use
+`the ``KEEP`` keyword <https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html>`_, e.g.
+``meta : { KEEP(*(meta)) }``

diff  --git a/lld/docs/index.rst b/lld/docs/index.rst
index 40da6d77cca82..b0080f54df245 100644
--- a/lld/docs/index.rst
+++ b/lld/docs/index.rst
@@ -178,4 +178,5 @@ document soon.
    Partitions
    ReleaseNotes
    ELF/linker_script
+   ELF/start-stop-gc
    ELF/warn_backrefs

diff  --git a/lld/test/ELF/gc-sections-startstop-hint.s b/lld/test/ELF/gc-sections-startstop-hint.s
new file mode 100644
index 0000000000000..33d088fa3af77
--- /dev/null
+++ b/lld/test/ELF/gc-sections-startstop-hint.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+## Some projects may not work with GNU ld<2015-10 (ld.lld 13.0.0) --gc-sections behavior.
+## Give a hint.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld %t.o -o /dev/null
+# RUN: ld.lld %t.o --gc-sections -z nostart-stop-gc -o /dev/null
+# RUN: not ld.lld %t.o --gc-sections -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK:      error: undefined symbol: __start_meta
+# CHECK-NEXT: >>> referenced by {{.*}}
+# CHECK-NEXT: >>> the encapsulation symbol needs to be retained under --gc-sections properly; consider -z nostart-stop-gc (see https://lld.llvm.org/ELF/start-stop-gc)
+
+.section .text,"ax", at progbits
+.global _start
+_start:
+  .quad __start_meta - .
+  .quad __stop_meta - .
+
+.section meta,"aw", at progbits
+.quad 0


        


More information about the llvm-branch-commits mailing list