[llvm-bugs] [Bug 49897] New: Missing dyn symbol for a weak wrapped function when using --wrap

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Apr 8 10:09:48 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=49897

            Bug ID: 49897
           Summary: Missing dyn symbol for a weak wrapped function when
                    using --wrap
           Product: lld
           Version: unspecified
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: ELF
          Assignee: unassignedbugs at nondot.org
          Reporter: shuralnik at snapchat.com
                CC: llvm-bugs at lists.llvm.org, smithp352 at googlemail.com

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 (https://github.com/llvm/llvm-project.git
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 at 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 at 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 at plt>:
    17d0:       ff 25 02 22 00 00       jmpq   *0x2202(%rip)        # 39d8
<foo at 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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210408/d7154234/attachment.html>


More information about the llvm-bugs mailing list