Sort objects before relocations

This commit is contained in:
Ulrich Drepper 2012-01-27 15:05:19 -05:00
parent 43455e0916
commit 6ee65ed6dd
8 changed files with 158 additions and 35 deletions

View File

@ -1,3 +1,14 @@
2012-01-27 Ulrich Drepper <drepper@gmail.com>
[BZ #13618]
* elf/dl-open.c (dl_open_worker): Sort objects by dependency before
relocation.
* Makeconfig (libm): Define.
* elf/Makefile: Add rules to build and run tst-relsort1.
* elf/tst-relsort1.c: New file.
* elf/tst-relsort1mod1.c: New file.
* elf/tst-relsort1mod2.c: New file.
2012-01-26 Joseph Myers <joseph@codesourcery.com>
* crypt/md5.h: Remove __STDC__ conditionals.

View File

@ -900,6 +900,12 @@ else
libdl = $(common-objpfx)dlfcn/libdl.a
endif
ifeq ($(build-shared),yes)
libm = $(common-objpfx)math/libm.so$(libm.so-version)
else
libm = $(common-objpfx)math/libm.a
endif
# These are the subdirectories containing the library source. The order
# is more or less arbitrary. The sorting step will take care of the
# dependencies.

4
NEWS
View File

@ -1,4 +1,4 @@
GNU C Library NEWS -- history of user-visible changes. 2012-1-26
GNU C Library NEWS -- history of user-visible changes. 2012-1-27
Copyright (C) 1992-2009, 2010, 2011, 2012 Free Software Foundation, Inc.
See the end for copying conditions.
@ -10,7 +10,7 @@ Version 2.16
* The following bugs are resolved with this release:
13525, 13526, 13527, 13528, 13529, 13531, 13532, 13533, 13547, 13530,
13551, 13552, 13553, 13555, 13559, 13583
13551, 13552, 13553, 13555, 13559, 13583, 13618
* ISO C11 support:

View File

@ -124,7 +124,8 @@ distribute := rtld-Rules \
tst-initordera1.c tst-initordera2.c tst-initorderb1.c \
tst-initorderb2.c tst-initordera3.c tst-initordera4.c \
tst-initorder.c \
tst-initorder2.c
tst-initorder2.c \
tst-relsort1.c tst-relsort1mod1.c tst-relsort1mod2.c
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@ -227,7 +228,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
tst-audit1 tst-audit2 \
tst-stackguard1 tst-addr1 tst-thrlock \
tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
tst-initorder tst-initorder2
tst-initorder tst-initorder2 tst-relsort1
# reldep9
test-srcs = tst-pathopt
selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
@ -290,7 +291,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-initordera1 tst-initorderb1 \
tst-initordera2 tst-initorderb2 \
tst-initordera3 tst-initordera4 \
tst-initorder2a tst-initorder2b tst-initorder2c tst-initorder2d
tst-initorder2a tst-initorder2b tst-initorder2c \
tst-initorder2d \
tst-relsort1mod1 tst-relsort1mod2
ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep tst-array5dep
endif
@ -1195,3 +1198,9 @@ CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
endif
$(objpfx)tst-relsort1: $(libdl)
$(objpfx)tst-relsort1mod1.so: $(libm) $(objpfx)tst-relsort1mod2.so
$(objpfx)tst-relsort1mod2.so: $(libm)
$(objpfx)tst-relsort1.out: $(objpfx)tst-relsort1mod1.so \
$(objpfx)tst-relsort1mod2.so

View File

@ -1,5 +1,5 @@
/* Load a shared object at runtime, relocate it, and run its initializer.
Copyright (C) 1996-2007, 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 1996-2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -302,45 +302,109 @@ dl_open_worker (void *a)
if (GLRO(dl_lazy))
reloc_mode |= mode & RTLD_LAZY;
/* Relocate the objects loaded. We do this in reverse order so that copy
relocs of earlier objects overwrite the data written by later objects. */
/* Sort the objects by dependency for the relocation process. This
allows IFUNC relocations to work and it also means copy
relocation of dependencies are if necessary overwritten. */
size_t nmaps = 0;
struct link_map *l = new;
while (l->l_next)
l = l->l_next;
while (1)
do
{
if (! l->l_real->l_relocated)
++nmaps;
l = l->l_next;
}
while (l != NULL);
struct link_map *maps[nmaps];
nmaps = 0;
l = new;
do
{
if (! l->l_real->l_relocated)
maps[nmaps++] = l;
l = l->l_next;
}
while (l != NULL);
if (nmaps > 1)
{
char seen[nmaps];
memset (seen, '\0', nmaps);
size_t i = 0;
while (1)
{
#ifdef SHARED
if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
++seen[i];
struct link_map *thisp = maps[i];
/* Find the last object in the list for which the current one is
a dependency and move the current object behind the object
with the dependency. */
size_t k = nmaps - 1;
while (k > i)
{
/* If this here is the shared object which we want to profile
make sure the profile is started. We can find out whether
this is necessary or not by observing the `_dl_profile_map'
variable. If was NULL but is not NULL afterwars we must
start the profiling. */
struct link_map *old_profile_map = GL(dl_profile_map);
struct link_map **runp = maps[k]->l_initfini;
if (runp != NULL)
/* Look through the dependencies of the object. */
while (*runp != NULL)
if (__builtin_expect (*runp++ == thisp, 0))
{
/* Move the current object to the back past the last
object with it as the dependency. */
memmove (&maps[i], &maps[i + 1],
(k - i) * sizeof (maps[0]));
maps[k] = thisp;
_dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
if (seen[i + 1] > 1)
{
++i;
goto next_clear;
}
if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
{
/* We must prepare the profiling. */
_dl_start_profile ();
char this_seen = seen[i];
memmove (&seen[i], &seen[i + 1],
(k - i) * sizeof (seen[0]));
seen[k] = this_seen;
/* Prevent unloading the object. */
GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
}
goto next;
}
--k;
}
else
#endif
_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
}
if (l == new)
break;
l = l->l_prev;
if (++i == nmaps)
break;
next_clear:
memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0]));
next:;
}
}
for (size_t i = nmaps; i-- > 0; )
{
l = maps[i];
#ifdef SHARED
if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
{
/* If this here is the shared object which we want to profile
make sure the profile is started. We can find out whether
this is necessary or not by observing the `_dl_profile_map'
variable. If it was NULL but is not NULL afterwars we must
start the profiling. */
struct link_map *old_profile_map = GL(dl_profile_map);
_dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1);
if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
{
/* We must prepare the profiling. */
_dl_start_profile ();
/* Prevent unloading the object. */
GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
}
}
else
#endif
_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
}
/* If the file is not loaded now as a dependency, add the search

19
elf/tst-relsort1.c Normal file
View File

@ -0,0 +1,19 @@
#include <dlfcn.h>
#include <stdio.h>
static int
do_test ()
{
const char lib[] = "$ORIGIN/tst-relsort1mod1.so";
void *h = dlopen (lib, RTLD_NOW);
if (h == NULL)
{
puts (dlerror ());
return 1;
}
return 0;
}
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

7
elf/tst-relsort1mod1.c Normal file
View File

@ -0,0 +1,7 @@
extern int foo (double);
int
bar (void)
{
return foo (1.2);
}

7
elf/tst-relsort1mod2.c Normal file
View File

@ -0,0 +1,7 @@
#include <math.h>
int
foo (double d)
{
return floor (d) != 0.0;
}