<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - LLD can create incorrect debug PC ranges for functions in Comdat groups."
   href="https://bugs.llvm.org/show_bug.cgi?id=37212">37212</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>LLD can create incorrect debug PC ranges for functions in Comdat groups.
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lld
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>ELF
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>peter.smith@linaro.org
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>clang and gcc produce technically incorrect ELF when representing the debug
information for comdat groups. Both gold and bfd have special case code that
accounts for this whereas LLD does not. For a better C++ debug illusion we
should consider implementing the same compensating code as it may be some time
before there is a sufficiently correct debug output from the compilers.

The problem is best observed via an example:
// File t.h
template <class T>
class Foo {
public:
    Foo(T x, T y) : x_(x), y_(y) {}
    T add()  const { return x_ + y_; } 
private:    
    T x_;
    T y_;
};
// File t.cpp, instantiates Foo::Foo() and Foo::add() in comdat groups.
#include "t.h"

int f1(int a, int b, int c, int d) {
    Foo<int> f1(a, b);
    Foo<int> f2(c, d);
    return f1.add() + f2.add();
}
// File t2.cpp, instantiates Foo::Foo() and Foo::add() in comdat groups.
#include "t.h"

int f2(int a, int b, int c, int d) {
    Foo<int> f1(a, b);
    Foo<int> f2(c, d);
    return f1.add() + f2.add();
}
// main.cpp
extern int f1(int a, int b, int c, int d);
extern int f2(int a, int b, int c, int d);

int main(void) {
    return f1(1,2,3,4) + f2(5,6,7,8);
}

clang -g t.cpp t2.cpp main.cpp -o main.exe
With bfd as the linker:
llvm-dwarfdump main.exe | grep DW_AT_low_pc 
              DW_AT_low_pc      (0x0000000000000000)
                DW_AT_low_pc    (0x00000000004004c0)
                DW_AT_low_pc    (0x0000000000400520)
                DW_AT_low_pc    (0x0000000000400540)
              DW_AT_low_pc      (0x0000000000000000)
                DW_AT_low_pc    (0x0000000000400560)
                DW_AT_low_pc    (0x0000000000400520)
                DW_AT_low_pc    (0x0000000000400540)
              DW_AT_low_pc      (0x00000000004005c0)
                DW_AT_low_pc    (0x00000000004005c0)
With lld as the linker:
              DW_AT_low_pc      (0x0000000000000000)
                DW_AT_low_pc    (0x0000000000201100)
                DW_AT_low_pc    (0x0000000000201160)
                DW_AT_low_pc    (0x0000000000201180)
              DW_AT_low_pc      (0x0000000000000000)
                DW_AT_low_pc    (0x00000000002011a0)
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_low_pc    (0x0000000000000000)
              DW_AT_low_pc      (0x0000000000201200)
                DW_AT_low_pc    (0x0000000000201200)

Note that there are two more DW_AT_low_pc (0x0000000000000000) in the lld
output. These are references from the .debug_info, in the object where the
Foo::Foo() and Foo::add() groups were discarded, to a local symbol within the
group.
  Section (11) .rela.debug_info {
...
    0x10C R_X86_64_64 .text._ZN3FooIiEC2Eii 0x0
    0x150 R_X86_64_64 .text._ZNK3FooIiE3addEv 0x0
...

These references to local symbols defined within a group from outside the group
are not permitted by ELF. LLD has special case code to allow them, but gold and
bfd go further and redirect the relocation from the objects with discarded
groups to the object with the selected group. The special case code can be
found by searching for PRETEND in bfd and CB_PRETEND in gold.

What bfd and gold are doing is most definitely a hack, but it probably works
well enough to give a better debug illusion than resolving to 0. We may want to
follow suit and implement it.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>