<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 - Missing dyn symbol for a weak wrapped function when using --wrap"
   href="https://bugs.llvm.org/show_bug.cgi?id=49897">49897</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Missing dyn symbol for a weak wrapped function when using --wrap
          </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>normal
          </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>shuralnik@snapchat.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, smithp352@googlemail.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Being honest I'm not sure if this is a really justified bug but at least
intuitively it really feels wrong. All below said is about current mainstream:

$ bin/clang -fuse-ld=lld -Wl,--version
LLD 13.0.0 (<a href="https://github.com/llvm/llvm-project.git">https://github.com/llvm/llvm-project.git</a>
37878de5036718481e13d5067a17d65eb85c3388) (compatible with GNU linkers)

When linking a DSO that refers to a some weak symbol, for which no shared
library with a definition was provided at the link time, I'm anyways getting
NOTYPE WEAK symbol in the final .dynsym:

$ cat test.c

__attribute__((weak))
extern int foo(int i);

int bar(int i) {
    return foo(i + 10);
}

$ bin/clang -fuse-ld=lld -shared -fPIC -Wl,--no-undefined test.c && readelf
--dyn-syms a.out | grep foo
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND foo

So that linker tolerates a weak external symbol with a missing definition. And
of course when providing some libfoo.so that has this symbol defined I'm
getting usual FUNC WEAK symbol:

$ bin/clang -fuse-ld=lld -shared -fPIC -Wl,--no-undefined test.c libfoo.so &&
readelf --dyn-syms a.out | grep foo
     5: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND foo

Then let's presume we need to wrap foo() in our DSO by linking in an additional
object:

$ cat test_wrap.c 

__attribute__((weak))
extern int __real_foo(int i);

int __wrap_foo(int i) {
    return __real_foo ? __real_foo(i + 100) : -1;
}

When libfoo.so is given to a linker - everything is OK:

$ bin/clang -fuse-ld=lld -shared -fPIC -Wl,--no-undefined test.c -Wl,--wrap=foo
test_wrap.c libfoo.so && readelf --dyn-syms a.out | grep foo
     5: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND foo
     9: 0000000000001730    73 FUNC    GLOBAL DEFAULT   10 __wrap_foo

__wrap_foo() refers to external foo() as expected:

$ objdump -d a.out 
...

0000000000001730 <__wrap_foo>:
    1730:       55                      push   %rbp
    1731:       48 89 e5                mov    %rsp,%rbp
    1734:       48 83 ec 10             sub    $0x10,%rsp
    1738:       89 7d fc                mov    %edi,-0x4(%rbp)
    173b:       48 8b 05 5e 12 00 00    mov    0x125e(%rip),%rax        # 29a0
<foo@Base>
    1742:       48 85 c0                test   %rax,%rax
    1745:       0f 84 18 00 00 00       je     1763 <__wrap_foo+0x33>
    174b:       e9 00 00 00 00          jmpq   1750 <__wrap_foo+0x20>
    1750:       8b 7d fc                mov    -0x4(%rbp),%edi
    1753:       83 c7 64                add    $0x64,%edi
    1756:       e8 75 00 00 00          callq  17d0 <foo@plt>
    175b:       89 45 f8                mov    %eax,-0x8(%rbp)
    175e:       e9 0d 00 00 00          jmpq   1770 <__wrap_foo+0x40>
    1763:       b8 ff ff ff ff          mov    $0xffffffff,%eax
    1768:       89 45 f8                mov    %eax,-0x8(%rbp)
    176b:       e9 00 00 00 00          jmpq   1770 <__wrap_foo+0x40>
    1770:       8b 45 f8                mov    -0x8(%rbp),%eax
    1773:       48 83 c4 10             add    $0x10,%rsp
    1777:       5d                      pop    %rbp
    1778:       c3                      retq   

...

00000000000017d0 <foo@plt>:
    17d0:       ff 25 02 22 00 00       jmpq   *0x2202(%rip)        # 39d8
<foo@Base>
    17d6:       68 02 00 00 00          pushq  $0x2
    17db:       e9 c0 ff ff ff          jmpq   17a0 <_fini+0xc>


But when libfoo.so is not provided it is quite expected to see a reference to
NOTYPE WEAK foo() from __wrap_foo(), exactly like it was with no --wrap. But
instead foo() is completely missing in .dynsym and __wrap_foo() refers to some
garbage:

$ bin/clang -fuse-ld=lld -shared -fPIC -Wl,--no-undefined test.c -Wl,--wrap=foo
test_wrap.c && readelf --dyn-syms a.out | grep foo
     8: 0000000000001690    73 FUNC    GLOBAL DEFAULT   10 __wrap_foo

$ objdump -d a.out 

...

0000000000001690 <__wrap_foo>:
    1690:       55                      push   %rbp
    1691:       48 89 e5                mov    %rsp,%rbp
    1694:       48 83 ec 10             sub    $0x10,%rsp
    1698:       89 7d fc                mov    %edi,-0x4(%rbp)
    169b:       48 8b 05 4e 12 00 00    mov    0x124e(%rip),%rax        # 28f0
<_DYNAMIC+0x1a0>
    16a2:       48 85 c0                test   %rax,%rax
    16a5:       0f 84 18 00 00 00       je     16c3 <__wrap_foo+0x33>
    16ab:       e9 00 00 00 00          jmpq   16b0 <__wrap_foo+0x20>
    16b0:       8b 7d fc                mov    -0x4(%rbp),%edi
    16b3:       83 c7 64                add    $0x64,%edi
    16b6:       e8 75 00 00 00          callq  1730 <*ABS*@plt>
    16bb:       89 45 f8                mov    %eax,-0x8(%rbp)
    16be:       e9 0d 00 00 00          jmpq   16d0 <__wrap_foo+0x40>
    16c3:       b8 ff ff ff ff          mov    $0xffffffff,%eax
    16c8:       89 45 f8                mov    %eax,-0x8(%rbp)
    16cb:       e9 00 00 00 00          jmpq   16d0 <__wrap_foo+0x40>
    16d0:       8b 45 f8                mov    -0x8(%rbp),%eax
    16d3:       48 83 c4 10             add    $0x10,%rsp
    16d7:       5d                      pop    %rbp
    16d8:       c3                      retq   

...

0000000000001730 <*ABS*@plt>:
    1730:       ff 25 f2 21 00 00       jmpq   *0x21f2(%rip)        # 3928
<__TMC_END__+0x28>
    1736:       68 02 00 00 00          pushq  $0x2
    173b:       e9 c0 ff ff ff          jmpq   1700 <_fini+0xc>


At the same time both GNU linkers expectedly emit NOTYPE symbols:

$ bin/clang -fuse-ld=bfd -shared -fPIC -Wl,--no-undefined test.c -Wl,--wrap=foo
test_wrap.c && readelf --dyn-syms a.out | grep foo
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND foo
    12: 0000000000000600    73 FUNC    GLOBAL DEFAULT   11 __wrap_foo
$ bin/clang -fuse-ld=gold -shared -fPIC -Wl,--no-undefined test.c
-Wl,--wrap=foo test_wrap.c && readelf --dyn-syms a.out | grep foo
     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND foo
    11: 00000000000006a0    73 FUNC    GLOBAL DEFAULT   11 __wrap_foo

Apparently LLD should generate NOTYPE as well, because otherwise resulting
binary seems to be broken.</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>