This is the mail archive of the mailing list for the glibc project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: ppc64: Call to gettimeofday fails with segfault in __glink_PLTresolve because .plt0 is all zeros.

On 11/05/2013 10:03 AM, Alan Modra wrote:
> On Tue, Nov 05, 2013 at 12:56:32AM -0500, Carlos O'Donell wrote:
>> # PLT call stub (note that build_plt_stub() in bfd doesn't say much about
>> # why the stub does what it does so I my analysis might be wrong)...
>>    11dfc:       f8 41 00 28     std     r2,40(r1)
>>    11e00:       e9 62 99 a8     ld      r11,-26200(r2)
>>    11e04:       7d 69 03 a6     mtctr   r11
>> # At this point r11 points at the address of the VDSO __kernel_gettimeofday
> Which says you have had a successful resolution of that plt entry at
> some point.  The PLT is .bss on powerpc64, so it starts all zero then
> initialises the function entry address (first dword of each 2 or
> 3 dword plt entry) to point at the glink code if doing lazy linking or
> resolves to the final addresses if LD_BIND_NOW=1.

This is a binutils bug, that has likely been fixed in a newer binutils
(which I'm not using).

The reduced test case looks like this:

cat >> test-1026533.c <<EOF
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

union fptr {
  int (*func)(void);
  void *vfunc;

main (void)
  void *handle;
  union fptr myfptr;
  char *error;
  int ret;
  handle = dlopen ("./", RTLD_NOW);
  if (handle == NULL)
      fprintf (stderr, "FAIL: dlopen failed (%s)\n", dlerror ());
      exit (1);
  dlerror ();
  myfptr.vfunc = dlsym (handle, "func_1026533");
  if ((error = dlerror ()) != NULL)
      fprintf (stderr, "FAIL: dlsym failed (%s)\n", dlerror ());
      exit (1);
  ret = myfptr.func ();
  if (ret != 0xdeadbeef)
      fprintf (stderr, "FAIL: dlopen'd library function failed to "
		       "return expected value.\n");
      exit (1);
  dlclose (handle);
  fprintf (stderr, "PASS: dlopen'd library function did not crash.\n");
  exit (0);

cat >> lib-1026533.c <<EOF
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

func_1026533 (void)
  struct timeval now;
  int ret;
  ret = gettimeofday (&now, NULL);
  if (ret == -1)
      perror ("gettimeofday");
      fprintf (stderr, "FAIL: gettimeofday returned -1.\n");
      exit (1);
  fprintf (stdout, "Time is %ld.%06ld.\n", now.tv_sec, now.tv_usec);
  return 0xdeadbeef;

gcc -Wl,--plt-thread-safe -g3 -O0 -Wall -pedantic -m64 -shared -fPIC -Wl,--soname, -o lib-1026533.c
gcc -Wl,--plt-thread-safe -ldl -g3 -O0 -Wall -pedantic -m64 -o test-1026533 test-1026533.c

On a system *with* an IFUNC for gettimeofday:
Segmentation fault
echo $?

On a system *without* an IFUNC for gettimeofday:
Time is 1383686757.603343.
PASS: dlopen'd library function did not crash.
echo $?

It is the critical combination of the new thread-safe plt stubs 
*and* the VDSO OPD being incomplete, followed by a dlopen with 
RTLD_NOW which cause the failure.

The caller dlopen's the library with RTLD_NOW, thus the dynamic
loader expects never to need .plt0 and doesn't set it up.
However, because the IFUNC OPD has 0 for a TOC, because it's
incomplete for some reason (the bug?), and because the new
thread-safe plt sequences check for r2==0 and attempt a lazy
resolution if it is, we end up in a situation where we are
calling .glink0 without having setup .plt0.

This combination of events happens with glibc's gettimeofday 
(new enough glibc with IFUNC for that symbol) when called from from python (which always uses RTLD_NOW with
dlopen). However, it looks like it only happens when an older
binutils e.g. is used to build glibc.

Adhemerval says that doesn't have the problem
with the IFUNC's OPD having a zero TOC.

Any idea what patch fixed this?


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]