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> 2012-01-26 Joseph Myers <joseph@codesourcery.com>
* crypt/md5.h: Remove __STDC__ conditionals. * crypt/md5.h: Remove __STDC__ conditionals.

View File

@ -900,6 +900,12 @@ else
libdl = $(common-objpfx)dlfcn/libdl.a libdl = $(common-objpfx)dlfcn/libdl.a
endif 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 # These are the subdirectories containing the library source. The order
# is more or less arbitrary. The sorting step will take care of the # is more or less arbitrary. The sorting step will take care of the
# dependencies. # 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. Copyright (C) 1992-2009, 2010, 2011, 2012 Free Software Foundation, Inc.
See the end for copying conditions. See the end for copying conditions.
@ -10,7 +10,7 @@ Version 2.16
* The following bugs are resolved with this release: * The following bugs are resolved with this release:
13525, 13526, 13527, 13528, 13529, 13531, 13532, 13533, 13547, 13530, 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: * ISO C11 support:

View File

@ -124,7 +124,8 @@ distribute := rtld-Rules \
tst-initordera1.c tst-initordera2.c tst-initorderb1.c \ tst-initordera1.c tst-initordera2.c tst-initorderb1.c \
tst-initorderb2.c tst-initordera3.c tst-initordera4.c \ tst-initorderb2.c tst-initordera3.c tst-initordera4.c \
tst-initorder.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-runtime.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-dl-lookup.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-audit1 tst-audit2 \
tst-stackguard1 tst-addr1 tst-thrlock \ tst-stackguard1 tst-addr1 tst-thrlock \
tst-unique1 tst-unique2 tst-unique3 tst-unique4 \ tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
tst-initorder tst-initorder2 tst-initorder tst-initorder2 tst-relsort1
# reldep9 # reldep9
test-srcs = tst-pathopt test-srcs = tst-pathopt
selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) 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-initordera1 tst-initorderb1 \
tst-initordera2 tst-initorderb2 \ tst-initordera2 tst-initorderb2 \
tst-initordera3 tst-initordera4 \ 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)) ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep tst-array5dep modules-names += tst-array2dep tst-array5dep
endif endif
@ -1195,3 +1198,9 @@ CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
endif 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. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -302,23 +302,92 @@ dl_open_worker (void *a)
if (GLRO(dl_lazy)) if (GLRO(dl_lazy))
reloc_mode |= mode & RTLD_LAZY; reloc_mode |= mode & RTLD_LAZY;
/* Relocate the objects loaded. We do this in reverse order so that copy /* Sort the objects by dependency for the relocation process. This
relocs of earlier objects overwrite the data written by later objects. */ 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; struct link_map *l = new;
while (l->l_next) do
l = l->l_next;
while (1)
{ {
if (! l->l_real->l_relocated) 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)
{
++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)
{
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;
if (seen[i + 1] > 1)
{
++i;
goto next_clear;
}
char this_seen = seen[i];
memmove (&seen[i], &seen[i + 1],
(k - i) * sizeof (seen[0]));
seen[k] = this_seen;
goto next;
}
--k;
}
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 #ifdef SHARED
if (__builtin_expect (GLRO(dl_profile) != NULL, 0)) if (__builtin_expect (GLRO(dl_profile) != NULL, 0))
{ {
/* If this here is the shared object which we want to profile /* If this here is the shared object which we want to profile
make sure the profile is started. We can find out whether make sure the profile is started. We can find out whether
this is necessary or not by observing the `_dl_profile_map' this is necessary or not by observing the `_dl_profile_map'
variable. If was NULL but is not NULL afterwars we must variable. If it was NULL but is not NULL afterwars we must
start the profiling. */ start the profiling. */
struct link_map *old_profile_map = GL(dl_profile_map); struct link_map *old_profile_map = GL(dl_profile_map);
@ -338,11 +407,6 @@ dl_open_worker (void *a)
_dl_relocate_object (l, l->l_scope, reloc_mode, 0); _dl_relocate_object (l, l->l_scope, reloc_mode, 0);
} }
if (l == new)
break;
l = l->l_prev;
}
/* If the file is not loaded now as a dependency, add the search /* If the file is not loaded now as a dependency, add the search
list of the newly loaded object to the scope. */ list of the newly loaded object to the scope. */
bool any_tls = false; bool any_tls = false;

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;
}