public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "i at maskray dot me" <sourceware-bugzilla@sourceware.org>
To: glibc-bugs@sourceware.org
Subject: [Bug dynamic-link/28218] ld.so: ifunc resolver calls a lazy PLT. When does it work?
Date: Sun, 15 Aug 2021 01:32:13 +0000	[thread overview]
Message-ID: <bug-28218-131-DQ04ByvoFV@http.sourceware.org/bugzilla/> (raw)
In-Reply-To: <bug-28218-131@http.sourceware.org/bugzilla/>

https://sourceware.org/bugzilla/show_bug.cgi?id=28218

--- Comment #3 from Fangrui Song <i at maskray dot me> ---
(In reply to Florian Weimer from comment #2)
> (In reply to Alan Modra from comment #1)
> > > FreeBSD rtld resolves non-IRELATIVE relocations in all modules, then
> > > IRELATIVE relocations in all modules.
> > Yes, this is the correct way to do things, and the only general way to
> > support cross-module ifunc resolvers that themselves might need to be
> > relocated.  We have known this for a long time.  See for example
> > https://gcc.gnu.org/legacy-ml/gcc-patches/2009-07/msg01307.html
> 
> Cross-module IFUNC resolvers that have relocation dependencies need more
> deferral than just IRELATIVE relocations. Regular relocations which target
> an IFUNC symbol need to be deferred, and copy relocations as well. Even that
> does not completely address all cases.
> 
> My impression is that the glibc maintainers think that IFUNC resolvers must
> not use have relocation dependencies. This could mean that they can only be
> implemented in assembler on some targets.
> 
> Initial comments on a proposal were positive:
> https://sourceware.org/legacy-ml/libc-alpha/2017-01/msg00468.html But I
> think during later discussions, this approach was rejected.

I have read
https://libc-alpha.sourceware.narkive.com/EDssYfrx/ifunc-resolver-scheduling-bugs-21041-20019

I think using a dependency based topological sort is probably over-engineering.
A two-pass approach (used by FreeBSD, mentioned by Szabolcs Nagy) works well.
Cross-DSO calls are via JUMP_SLOT relocs and cross-DSO variable accesses are
via GLOB_DAT or absolute relocations. Such relocs have been properly set up in
the first pass of relocation resolving. Here is a somewhat complex case.

cat > ./a.c <<eof
  #include <stdio.h>

  int a_impl() { return 42; }
  void *a_resolver() {
    puts("a_resolver");
    return (void *)a_impl;
  }
  int a() __attribute__((ifunc("a_resolver")));

  // .rela.dyn.rel => R_X86_64_64 referencing STT_GNU_IFUNC in .rela.dyn
  int (*fptr_a)() = a;
  int b(); extern int (*fptr_b)();
  int c(); extern int (*fptr_c)();

  int main() {
    printf("%d\n", a());
    printf("b: %p %p\n", fptr_b, b);
    printf("c: %p %p\n", fptr_c, c);
  }
eof
cat > ./b.c <<eof
  #include <stdio.h>
  void c();
  int b_impl() { return 43; }
  void *b_resolver() {
    puts("b_resolver");
    c(); // c is defined in c.so
    return (void *)b_impl;
  }
  int b() __attribute__((ifunc("b_resolver")));
  int (*fptr_b)() = b;
eof
cat > ./c.c <<eof
  #include <stdio.h>
  int c_impl() { return 44; }
  void *c_resolver() {
    puts("c_resolver");
    return (void *)c_impl;
  }
  int c() __attribute__((ifunc("c_resolver")));
  int (*fptr_c)() = c;
eof
cat > ./Makefile <<'eof'
a: a.c b.so c.so
        cc -pie -fpie a.c ./b.so ./c.so -l dl -o $@

b.so: b.c
        cc -shared -fpic b.c -o $@

c.so: c.c
        cc -shared -fpic c.c -o $@
eof
```

Note that in `b.so`, the ifunc resolver has a PLT call to `c.so`.
In real world applications, `c` may be some performance critical functions like
`memset`.

`./a` obviously crashes with glibc. `./a` works on FreeBSD.
```text
c_resolver
b_resolver
c_resolver
a_resolver
b_resolver
c_resolver
42
b: 0x80106e670 0x80106e670
c: 0x801072630 0x801072630
```

Also works when `a` is built with `-no-pie -fno-pic` where there are copy
relocations.
We can let `b.so` depend on `c.so`, swap the link order of `./b.so` and
`./c.so`. Still works.

The approach also works with various examples where an ifunc resolver returns a
variable referencing an implementation.


> The main problem with the two-pass approach is that there is no place
> where it can cache symbol lookup results. If we assume that relocation
> performance is dominated by symbol lookups (which is reasonable IMHO),
> we are looking at a very substantial performance hit for the two-pass
> approach. [...]

We can handle just IRELATIVE and ignore R_X86_64_64 referencing STT_GNU_IFUNC.

* Check whether a module has IRELATIVE. If not, skip the second pass.
* If yes, handle IRELATIVE in the second pass.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

  parent reply	other threads:[~2021-08-15  1:32 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <bug-28218-131@http.sourceware.org/bugzilla/>
2021-08-10 17:37 ` [Bug dynamic-link/28218] ld: " i at maskray dot me
2021-08-10 17:37 ` [Bug dynamic-link/28218] ld.so: " i at maskray dot me
2021-08-12  6:16 ` amodra at gmail dot com
2021-08-12  7:36 ` fweimer at redhat dot com
2021-08-15  1:32 ` i at maskray dot me [this message]
2021-08-15 18:56 ` i at maskray dot me

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-28218-131-DQ04ByvoFV@http.sourceware.org/bugzilla/ \
    --to=sourceware-bugzilla@sourceware.org \
    --cc=glibc-bugs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).