Sort objects before relocations

(cherry picked from commit 6ee65ed6dd)
This commit is contained in:
Ulrich Drepper 2012-01-27 15:05:19 -05:00 committed by Carlos O'Donell
parent 9875bb2221
commit 4a659bb814
8 changed files with 160 additions and 37 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.
2014-01-04 Maxim Kuvyrkov <maxim@kugelworks.com>
Ondřej Bílka <neleai@seznam.cz>

View File

@ -950,6 +950,12 @@ libdl =
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
# is more or less arbitrary. The sorting step will take care of the
# dependencies.

8
NEWS
View File

@ -1,5 +1,5 @@
GNU C Library NEWS -- history of user-visible changes. 2011-12-23
Copyright (C) 1992-2012 Free Software Foundation, Inc.
Copyright (C) 1992-2014 Free Software Foundation, Inc.
See the end for copying conditions.
Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
@ -9,9 +9,9 @@ Version 2.15.1
* The following bugs are resolved with this release:
411, 2547, 2548, 11261, 11365, 11494, 13583, 13731, 13732, 13733, 13747,
13748, 13749, 13753, 13754, 13771, 13773, 13774, 13786, 14048, 14059,
14167, 14273, 14459, 14621, 14648, 14040, 15073
411, 2547, 2548, 11261, 11365, 11494, 13583, 13618, 13731, 13732, 13733,
13747, 13748, 13749, 13753, 13754, 13756, 13771, 13773, 13774, 13786,
14048, 14059, 14167, 14273, 14459, 14621, 14648, 14040, 15073
Version 2.15

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
@ -229,7 +230,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)
@ -292,7 +293,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
@ -1197,3 +1200,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;
}