[lld] r363126 - [ELF][PPC64] Don't report "relocation refers to a discarded section" for .toc

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 12 00:35:43 PDT 2019


Author: maskray
Date: Wed Jun 12 00:35:42 2019
New Revision: 363126

URL: http://llvm.org/viewvc/llvm-project?rev=363126&view=rev
Log:
[ELF][PPC64] Don't report "relocation refers to a discarded section" for .toc

Summary:
clang (as of 2019-06-12) / gcc (as of 8.2.1) PPC64 may emit a .rela.toc
which references an embedded switch table in a discarded .rodata/.text
section. The .toc and the .rela.toc are incorrectly not placed in the
comdat.

Technically a relocation from outside the group is not allowed by the ELF spec:

> A symbol table entry with STB_LOCAL binding that is defined relative
> to one of a group's sections, and that is contained in a symbol table
> section that is not part of the group, must be discarded if the group
> members are discarded. References to this symbol table entry from
> outside the group are not allowed.

Don't report errors to work around the bug.

This should fix the ppc64le-lld-multistage-test bot while linking llvm-tblgen:

    ld.lld: error: relocation refers to a discarded section: .rodata._ZNK4llvm3MVT13getSizeInBitsEv
    >>> defined in utils/TableGen/CMakeFiles/llvm-tblgen.dir/CodeGenRegisters.cpp.o
    >>> referenced by CodeGenRegisters.cpp
    >>> utils/TableGen/CMakeFiles/llvm-tblgen.dir/CodeGenRegisters.cpp.o:(.toc+0x0)

Some other PPC specific sections may have similar problems. We can blacklist more
section names when problems occur.

    // A simple program that reproduces the bug.
    // Note .rela.toc (outside the group) references a section symbol (STB_LOCAL) in a group.
    void puts(const char *);
    struct A {
      void foo(int a) {
        switch (a) {
        case 0: puts("0"); break;
        case 1: puts("1"); puts("1"); break;
        case 2: puts("2"); break;
        case 3: puts("3"); puts("4"); break;
        case 4: puts("4"); break;
        case 5: puts("5"); puts("5"); break;
        case 6: puts("6"); break;
        }
      }
      int a;
    };
    void foo(A x) { x.foo(x.a); }

Reviewers: ruiu, sfertile, espindola

Reviewed By: ruiu

Subscribers: emaste, nemanjai, arichardson, kbarton, jsji, llvm-commits

Tags: #llvm

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

Added:
    lld/trunk/test/ELF/comdat-discarded-ppc64.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=363126&r1=363125&r2=363126&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed Jun 12 00:35:42 2019
@@ -438,11 +438,13 @@ void InputSection::copyRelocations(uint8
       // relocation in it pointing to discarded sections with R_*_NONE, which
       // hopefully creates a frame that is ignored at runtime. Also, don't warn
       // on .gcc_except_table and debug sections.
+      //
+      // See the comment in maybeReportUndefined for PPC64 .toc .
       auto *D = dyn_cast<Defined>(&Sym);
       if (!D) {
         if (!Sec->Name.startswith(".debug") &&
             !Sec->Name.startswith(".zdebug") && Sec->Name != ".eh_frame" &&
-            Sec->Name != ".gcc_except_table") {
+            Sec->Name != ".gcc_except_table" && Sec->Name != ".toc") {
           uint32_t SecIdx = cast<Undefined>(Sym).DiscardedSecIdx;
           Elf_Shdr_Impl<ELFT> Sec =
               CHECK(File->getObj().sections(), File)[SecIdx];

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=363126&r1=363125&r2=363126&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Wed Jun 12 00:35:42 2019
@@ -718,6 +718,15 @@ static bool maybeReportUndefined(Symbol
   if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
     return false;
 
+  // clang (as of 2019-06-12) / gcc (as of 8.2.1) PPC64 may emit a .rela.toc
+  // which references a switch table in a discarded .rodata/.text section. The
+  // .toc and the .rela.toc are incorrectly not placed in the comdat. The ELF
+  // spec says references from outside the group to a STB_LOCAL symbol are not
+  // allowed. Work around the bug.
+  if (Config->EMachine == EM_PPC64 &&
+      cast<Undefined>(Sym).DiscardedSecIdx != 0 && Sec.Name == ".toc")
+    return false;
+
   auto Visibility = [&]() -> std::string {
     switch (Sym.Visibility) {
     case STV_INTERNAL:

Added: lld/trunk/test/ELF/comdat-discarded-ppc64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/comdat-discarded-ppc64.s?rev=363126&view=auto
==============================================================================
--- lld/trunk/test/ELF/comdat-discarded-ppc64.s (added)
+++ lld/trunk/test/ELF/comdat-discarded-ppc64.s Wed Jun 12 00:35:42 2019
@@ -0,0 +1,17 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o
+# RUN: ld.lld %t.o %t.o -o /dev/null
+# RUN: ld.lld -r --fatal-warnings %t.o %t.o -o /dev/null
+
+## clang/gcc PPC64 may emit a .rela.toc which references a switch table in a
+## discarded .rodata/.text section. The .toc and the .rela.toc are incorrectly
+## not placed in the comdat.
+## Don't error "relocation refers to a discarded section".
+
+.section .text.foo,"axG", at progbits,foo,comdat
+.globl foo
+foo:
+.L0:
+
+.section .toc,"aw"
+.quad .L0




More information about the llvm-commits mailing list