2001-12-11  Jakub Jelinek  <jakub@redhat.com>

	* elf/Makefile (dl-routines): Add conflict.
	(rtld-ldscript-in, rtld-ldscript, rtld-parms): Remove.
	(ld.so): Add _begin local symbol.
	* elf/elf.h (DT_VALTAGIDX, DT_VALNUM, DT_ADDRTAGIDX, DT_ADDRNUM):
	Define.
	* elf/dl-deps.c (_dl_build_local_scope): New.
	(_dl_map_object_deps): If LD_TRACE_PRELINKING, compute local scopes
	of all libraries.
	* elf/do-rel.h (VALIDX): Define.
	(elf_dynamic_do_rel): If ELF_MACHINE_PLT_REL is defined, don't do
	lazy binding for RELA.  If DT_GNU_PRELINKED, DT_RELACOUNT relocations
	can be skipped.
	* elf/dl-conflict.c: New file.
	* elf/dl-lookup.c (_dl_debug_bindings): New.
	(_dl_lookup_symbol): Use _dl_debug_bindings.  Reference_name is always
	non-NULL.
	(_dl_lookup_symbol_skip): Likewise.
	(_dl_lookup_versioned_symbol): Likewise.
	(_dl_lookup_versioned_symbol_skip): Likewise.
	* elf/dl-runtime.c (PLTREL): If ELF_MACHINE_PLT_REL is defined,
	define to ElfW(Rel).
	* elf/dynamic-link.h (elf_get_dynamic_info): Record selected dynamic
	tags in the DT_VALRNGLO..DT_VALRNGHI and DT_ADDRRNGLO..DT_ADDRRNGHI
	ranges.
	Don't adjust address dynamic tags if l_addr is 0.
	* elf/rtld.c (_dl_trace_prelink, _dl_trace_prelink_map): New variables.
	(_dl_start): Skip ELF_DYNAMIC_RELOCATE if ld.so is prelinked.
	(VALIDX, ADDRIDX): Define.
	(_dl_start_final): Initialize _dl_rtld_map's l_map_start and l_map_end.
	(dl_main): Print library list for LD_TRACE_PRELINKING.
	If prelinking information can be used, skip relocating libraries and
	call _dl_resolve_conflicts instead.
	(process_envvars): Handle LD_TRACE_PRELINKING envvar.
	* elf/dl-load.c (_dl_map_object): Don't create fake libs
	if LD_TRACE_PRELINKING.
	* include/link.h (struct link_map) [l_info]: Add DT_VALNUM
	+ DT_ADDRNUM.
	* sysdeps/generic/ldsodefs.h (_dl_trace_prelink_map): New declaration.
	(DL_DEBUG_PRELINK): Define.
	(_dl_resolve_conflicts): Add prototype.

	* sysdeps/alpha/dl-machine.h (elf_machine_runtime_setup): Reinitialize
	.plt for prelinked libraries where prelinking info cannot be used.
	(elf_machine_rela): If relocating R_ALPHA_JMP_SLOT in .gnu.conflict
	section, use RESOLVE_CONFLICT_FIND_MAP to find out reloc's link_map.
	* sysdeps/arm/bits/link.h: New file.
	* sysdeps/arm/dl-machine.h (elf_machine_runtime_setup): Save original
	content of .got[1].
	(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
	(ELF_MACHINE_PLT_REL): Define.
	(elf_machine_rela, elf_machine_rela_relative): New.
	(elf_machine_lazy_rel): Reinitialize R_ARM_JUMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/i386/bits/link.h: New file.
	* sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Save original
	content of .got[1].
	(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
	(ELF_MACHINE_PLT_REL): Define.
	(elf_machine_rela, elf_machine_rela_relative): New.
	(elf_machine_lazy_rel): Reinitialize R_386_JUMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/powerpc/dl-machine.h (elf_machine_rela): If relocating
	conflicts, skip finaladdr computation.  Use RESOLVE_CONFLICT_FIND_MAP
	to find out map for R_PPC_JMP_SLOT relocs.
	* sysdeps/sparc/sparc32/dl-machine.h (VALIDX): Define.
	(OPCODE_BA): Define.
	(elf_machine_runtime_setup): Reinitialize .plt for prelinked
	libraries where prelinking info cannot be used.
	(sparc_fixup_plt): Renamed from elf_machine_fixup_plt.
	(elf_machine_fixup_plt): Call sparc_fixup_plt.
	(elf_machine_rela): Set value to 0 if relocating conflicts.
	Call sparc_fixup_plt for R_SPARC_JMP_SLOT.
	* sysdeps/sparc/sparc64/dl-machine.h (VALIDX): Define.
	(sparc64_fixup_plt): Fix a typo.
	(elf_machine_rela): Set value to 0 if relocating conflicts.
	Handle R_SPARC_JMP_SLOT relocs when relocating conflicts.
	(elf_machine_runtime_setup): Reinitialize .plt for prelinked
	libraries where prelinking info cannot be used.
	* sysdeps/sh/bits/link.h: New file.
	* sysdeps/sh/dl-machine.h (elf_machine_runtime_setup): Save original
	content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_SH_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/s390/s390-32/bits/link.h: New file.
	* sysdeps/s390/s390-32/dl-machine.h (elf_machine_runtime_setup):
	Save original content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/s390/s390-64/bits/link.h: New file.
	* sysdeps/s390/s390-64/dl-machine.h (elf_machine_runtime_setup):
	Save original content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
	* sysdeps/x86_64/bits/link.h: New file.
	* sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup):
	Save original content of .got[1].
	(elf_machine_lazy_rel): Reinitialize R_X86_64_JMP_SLOT address instead
	of adjusting it if prelinked and prelinking cannot be used.
This commit is contained in:
Ulrich Drepper 2001-12-12 00:21:26 +00:00
parent 4be601a15e
commit 32e6df3621
29 changed files with 1043 additions and 201 deletions

101
ChangeLog
View File

@ -1,3 +1,104 @@
2001-12-11 Jakub Jelinek <jakub@redhat.com>
* elf/Makefile (dl-routines): Add conflict.
(rtld-ldscript-in, rtld-ldscript, rtld-parms): Remove.
(ld.so): Add _begin local symbol.
* elf/elf.h (DT_VALTAGIDX, DT_VALNUM, DT_ADDRTAGIDX, DT_ADDRNUM):
Define.
* elf/dl-deps.c (_dl_build_local_scope): New.
(_dl_map_object_deps): If LD_TRACE_PRELINKING, compute local scopes
of all libraries.
* elf/do-rel.h (VALIDX): Define.
(elf_dynamic_do_rel): If ELF_MACHINE_PLT_REL is defined, don't do
lazy binding for RELA. If DT_GNU_PRELINKED, DT_RELACOUNT relocations
can be skipped.
* elf/dl-conflict.c: New file.
* elf/dl-lookup.c (_dl_debug_bindings): New.
(_dl_lookup_symbol): Use _dl_debug_bindings. Reference_name is always
non-NULL.
(_dl_lookup_symbol_skip): Likewise.
(_dl_lookup_versioned_symbol): Likewise.
(_dl_lookup_versioned_symbol_skip): Likewise.
* elf/dl-runtime.c (PLTREL): If ELF_MACHINE_PLT_REL is defined,
define to ElfW(Rel).
* elf/dynamic-link.h (elf_get_dynamic_info): Record selected dynamic
tags in the DT_VALRNGLO..DT_VALRNGHI and DT_ADDRRNGLO..DT_ADDRRNGHI
ranges.
Don't adjust address dynamic tags if l_addr is 0.
* elf/rtld.c (_dl_trace_prelink, _dl_trace_prelink_map): New variables.
(_dl_start): Skip ELF_DYNAMIC_RELOCATE if ld.so is prelinked.
(VALIDX, ADDRIDX): Define.
(_dl_start_final): Initialize _dl_rtld_map's l_map_start and l_map_end.
(dl_main): Print library list for LD_TRACE_PRELINKING.
If prelinking information can be used, skip relocating libraries and
call _dl_resolve_conflicts instead.
(process_envvars): Handle LD_TRACE_PRELINKING envvar.
* elf/dl-load.c (_dl_map_object): Don't create fake libs
if LD_TRACE_PRELINKING.
* include/link.h (struct link_map) [l_info]: Add DT_VALNUM
+ DT_ADDRNUM.
* sysdeps/generic/ldsodefs.h (_dl_trace_prelink_map): New declaration.
(DL_DEBUG_PRELINK): Define.
(_dl_resolve_conflicts): Add prototype.
* sysdeps/alpha/dl-machine.h (elf_machine_runtime_setup): Reinitialize
.plt for prelinked libraries where prelinking info cannot be used.
(elf_machine_rela): If relocating R_ALPHA_JMP_SLOT in .gnu.conflict
section, use RESOLVE_CONFLICT_FIND_MAP to find out reloc's link_map.
* sysdeps/arm/bits/link.h: New file.
* sysdeps/arm/dl-machine.h (elf_machine_runtime_setup): Save original
content of .got[1].
(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
(ELF_MACHINE_PLT_REL): Define.
(elf_machine_rela, elf_machine_rela_relative): New.
(elf_machine_lazy_rel): Reinitialize R_ARM_JUMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/i386/bits/link.h: New file.
* sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Save original
content of .got[1].
(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
(ELF_MACHINE_PLT_REL): Define.
(elf_machine_rela, elf_machine_rela_relative): New.
(elf_machine_lazy_rel): Reinitialize R_386_JUMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/powerpc/dl-machine.h (elf_machine_rela): If relocating
conflicts, skip finaladdr computation. Use RESOLVE_CONFLICT_FIND_MAP
to find out map for R_PPC_JMP_SLOT relocs.
* sysdeps/sparc/sparc32/dl-machine.h (VALIDX): Define.
(OPCODE_BA): Define.
(elf_machine_runtime_setup): Reinitialize .plt for prelinked
libraries where prelinking info cannot be used.
(sparc_fixup_plt): Renamed from elf_machine_fixup_plt.
(elf_machine_fixup_plt): Call sparc_fixup_plt.
(elf_machine_rela): Set value to 0 if relocating conflicts.
Call sparc_fixup_plt for R_SPARC_JMP_SLOT.
* sysdeps/sparc/sparc64/dl-machine.h (VALIDX): Define.
(sparc64_fixup_plt): Fix a typo.
(elf_machine_rela): Set value to 0 if relocating conflicts.
Handle R_SPARC_JMP_SLOT relocs when relocating conflicts.
(elf_machine_runtime_setup): Reinitialize .plt for prelinked
libraries where prelinking info cannot be used.
* sysdeps/sh/bits/link.h: New file.
* sysdeps/sh/dl-machine.h (elf_machine_runtime_setup): Save original
content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_SH_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/s390/s390-32/bits/link.h: New file.
* sysdeps/s390/s390-32/dl-machine.h (elf_machine_runtime_setup):
Save original content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/s390/s390-64/bits/link.h: New file.
* sysdeps/s390/s390-64/dl-machine.h (elf_machine_runtime_setup):
Save original content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
* sysdeps/x86_64/bits/link.h: New file.
* sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup):
Save original content of .got[1].
(elf_machine_lazy_rel): Reinitialize R_X86_64_JMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.
2001-12-11 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/ptsname.c (__ptsname_r): Use sizeof

View File

@ -29,7 +29,7 @@ routines = $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
# profiled libraries.
dl-routines = $(addprefix dl-,load cache lookup object reloc deps \
runtime error init fini debug misc \
version profile)
version profile conflict)
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure \
@ -154,30 +154,16 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
$(objpfx)librtld.os: $(objpfx)dl-allobjs.os $(common-objpfx)libc_pic.a
$(reloc-link) '-Wl,-(' $^ -lgcc '-Wl,-)'
# Do we need a linker script?
rtld-ldscript-in := $(firstword $(wildcard $(+sysdep_dirs:%=%/rtld-ldscript.in)))
ifneq (,$(rtld-ldscript-in))
rtld-ldscript = $(objpfx)rtld-ldscript
generated += rtld-ldscript
LDFLAGS-rtld = -T $(rtld-ldscript)
before-compile += $(rtld-ldscript)
rtld-parms = $(wildcard $(+sysdep_dirs:%=%/rtld-parms))
include $(rtld-parms)
$(rtld-ldscript): $(rtld-ldscript-in) $(rtld-parms)
sed -e 's#@@rtld-oformat@@#$(rtld-oformat)#' \
-e 's#@@rtld-arch@@#$(rtld-arch)#' \
-e 's#@@rtld-entry@@#$(rtld-entry)#' \
-e 's#@@rtld-base@@#$(rtld-base)#' $< >$@
endif
$(objpfx)ld.so: $(objpfx)librtld.os $(rtld-ldscript) $(ld-map)
$(LINK.o) -nostdlib -nostartfiles -shared -o $@ $(LDFLAGS-rtld) \
$(filter-out $(rtld-ldscript) $(map-file),$^) \
$(load-map-file) -Wl,-soname=$(rtld-installed-name)
$(objpfx)ld.so: $(objpfx)librtld.os $(ld-map)
$(LINK.o) -nostdlib -nostartfiles -shared \
$(LDFLAGS-rtld) -Wl,--verbose 2>&1 | \
sed -e '/^=========/,/^=========/!d;/^=========/d' \
-e 's/\. = 0 + SIZEOF_HEADERS;/& _begin = . - SIZEOF_HEADERS;/' \
> $@.lds; \
$(LINK.o) -nostdlib -nostartfiles -shared -o $@ $(LDFLAGS-rtld) \
$(filter-out $(map-file),$^) $(load-map-file) \
-Wl,-soname=$(rtld-installed-name) -T $@.lds; \
rm -f $@.lds
# interp.c exists just to get this string into the libraries.
CFLAGS-interp.c = -D'RUNTIME_LINKER="$(slibdir)/$(rtld-installed-name)"'

66
elf/dl-conflict.c Normal file
View File

@ -0,0 +1,66 @@
/* Resolve conflicts against already prelinked libraries.
Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <errno.h>
#include <libintl.h>
#include <stdlib.h>
#include <unistd.h>
#include <ldsodefs.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "dynamic-link.h"
extern unsigned long int _dl_num_cache_relocations; /* in dl-lookup.c */
void
_dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
ElfW(Rela) *conflictend)
{
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_RELOC, 0))
_dl_printf ("\nconflict processing: %s\n",
l->l_name[0] ? l->l_name : _dl_argv[0]);
{
/* Do the conflict relocation of the object and library GOT and other
data. */
/* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
#define RESOLVE_MAP(ref, version, flags) (*ref = NULL, 0)
#define RESOLVE(ref, version, flags) (*ref = NULL, 0)
#define RESOLVE_CONFLICT_FIND_MAP(map, r_offset) \
do \
{ \
while (resolve_conflict_map->l_map_end < (r_offset) \
|| resolve_conflict_map->l_map_start > (r_offset)) \
resolve_conflict_map \
= resolve_conflict_map->l_next; \
(map) = resolve_conflict_map; \
} while (0)
struct link_map *resolve_conflict_map = _dl_loaded;
#include "dynamic-link.h"
_dl_num_cache_relocations += conflictend - conflict;
for (; conflict < conflictend; ++conflict)
elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset);
}
}

View File

@ -21,6 +21,7 @@
#include <dlfcn.h>
#include <errno.h>
#include <libintl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -70,6 +71,21 @@ openaux (void *a)
args->trace_mode, 0);
}
static ptrdiff_t
internal_function
_dl_build_local_scope (struct link_map **list, struct link_map *map)
{
struct link_map **p = list;
struct link_map **q;
*p++ = map;
map->l_reserved = 1;
if (map->l_initfini)
for (q = map->l_initfini + 1; *q; ++q)
if (! (*q)->l_reserved)
p += _dl_build_local_scope (p, *q);
return p - list;
}
/* We use a very special kind of list to track the path
@ -491,6 +507,51 @@ _dl_map_object_deps (struct link_map *map,
runp->map->l_reserved = 0;
}
if (__builtin_expect(_dl_debug_mask & DL_DEBUG_PRELINK, 0) != 0
&& map == _dl_loaded)
{
/* If we are to compute conflicts, we have to build local scope
for each library, not just the ultimate loader. */
for (i = 0; i < nlist; ++i)
{
struct link_map *l = map->l_searchlist.r_list[i];
unsigned int j, cnt;
/* The local scope has been already computed. */
if (l == map
|| (l->l_local_scope[0]
&& l->l_local_scope[0]->r_nlist) != 0)
continue;
if (l->l_info[AUXTAG] || l->l_info[FILTERTAG])
{
/* As current DT_AUXILIARY/DT_FILTER implementation needs to be
rewritten, no need to bother with prelinking the old
implementation. */
_dl_signal_error (EINVAL, l->l_name, NULL, N_("\
Filters not supported with LD_TRACE_PRELINKING"));
}
cnt = _dl_build_local_scope (map->l_initfini, l);
assert (cnt <= nlist);
for (j = 0; j < cnt; j++)
map->l_initfini[j]->l_reserved = 0;
l->l_local_scope[0] =
(struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
+ (cnt
* sizeof (struct link_map *)));
if (l->l_local_scope[0] == NULL)
_dl_signal_error (ENOMEM, map->l_name, NULL,
N_("cannot allocate symbol search list"));
l->l_local_scope[0]->r_nlist = cnt;
l->l_local_scope[0]->r_list =
(struct link_map **) (l->l_local_scope[0] + 1);
memcpy (l->l_local_scope[0]->r_list, map->l_initfini,
cnt * sizeof (struct link_map *));
}
}
/* Maybe we can remove some relocation dependencies now. */
assert (map->l_searchlist.r_list[0] == map);
for (i = 0; i < map->l_reldepsact; ++i)

View File

@ -1782,7 +1782,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (__builtin_expect (fd, 0) == -1)
{
if (trace_mode)
if (trace_mode
&& __builtin_expect (_dl_debug_mask & DL_DEBUG_PRELINK, 0) == 0)
{
/* We haven't found an appropriate library. But since we
are only interested in the list of libraries this isn't

View File

@ -194,6 +194,12 @@ _dl_do_lookup_versioned (const char *undef_name, unsigned long int hash,
const struct r_found_version *const version,
struct link_map *skip, int type_class);
static void
internal_function
_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
struct sym_val *value, const struct r_found_version *version,
int type_class, int protected);
/* Search loaded objects' symbol tables for a definition of the symbol
UNDEF_NAME. */
@ -204,7 +210,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
int type_class, int explicit)
{
unsigned long int hash = _dl_elf_hash (undef_name);
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
int protected;
@ -241,7 +247,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
/* We could find no value for a strong reference. */
/* XXX We cannot translate the messages. */
_dl_signal_cerror (0, (reference_name && reference_name[0]
_dl_signal_cerror (0, (reference_name[0]
? reference_name
: (_dl_argv[0] ?: "<main program>")),
N_("relocation error"),
@ -251,25 +257,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
}
protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
_dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n",
(reference_name && reference_name[0]
? reference_name : (_dl_argv[0] ?: "<main program>")),
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
protected ? "protected" : "normal", undef_name);
}
if (__builtin_expect (protected == 0, 1))
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
else
if (__builtin_expect (protected != 0, 0))
{
/* It is very tricky. We need to figure out what value to
return for the protected symbol */
@ -280,14 +268,20 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
0, NULL, ELF_RTYPE_CLASS_PLT))
break;
if (protected_value.s == NULL || protected_value.m == undef_map)
if (protected_value.s != NULL && protected_value.m != undef_map)
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
current_value.s = *ref;
current_value.m = undef_map;
}
return LOOKUP_VALUE (undef_map);
}
if (__builtin_expect (_dl_debug_mask
& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
_dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
&current_value, NULL, type_class, protected);
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
@ -303,7 +297,6 @@ _dl_lookup_symbol_skip (const char *undef_name,
struct r_scope_elem *symbol_scope[],
struct link_map *skip_map)
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
@ -332,20 +325,7 @@ _dl_lookup_symbol_skip (const char *undef_name,
protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
_dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n",
(reference_name && reference_name[0]
? reference_name : (_dl_argv[0] ?: "<main program>")),
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
protected ? "protected" : "normal", undef_name);
if (__builtin_expect (protected == 0, 1))
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
else
if (__builtin_expect (protected != 0, 0))
{
/* It is very tricky. We need to figure out what value to
return for the protected symbol. */
@ -359,14 +339,20 @@ _dl_lookup_symbol_skip (const char *undef_name,
0, skip_map, ELF_RTYPE_CLASS_PLT))
break;
if (protected_value.s == NULL || protected_value.m == undef_map)
if (protected_value.s != NULL && protected_value.m != undef_map)
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
current_value.s = *ref;
current_value.m = undef_map;
}
return LOOKUP_VALUE (undef_map);
}
if (__builtin_expect (_dl_debug_mask
& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
_dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
&current_value, NULL, 0, protected);
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
@ -383,7 +369,7 @@ _dl_lookup_versioned_symbol (const char *undef_name,
const struct r_found_version *version,
int type_class, int explicit)
{
unsigned long int hash = _dl_elf_hash (undef_name);
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
int protected;
@ -423,7 +409,7 @@ _dl_lookup_versioned_symbol (const char *undef_name,
const char *reference_name = undef_map ? undef_map->l_name : NULL;
/* XXX We cannot translate the message. */
_dl_signal_cerror (0, (reference_name && reference_name[0]
_dl_signal_cerror (0, (reference_name[0]
? reference_name
: (_dl_argv[0] ?: "<main program>")),
N_("relocation error"),
@ -447,7 +433,7 @@ _dl_lookup_versioned_symbol (const char *undef_name,
const char *reference_name = undef_map ? undef_map->l_name : NULL;
/* XXX We cannot translate the message. */
_dl_signal_cerror (0, (reference_name && reference_name[0]
_dl_signal_cerror (0, (reference_name[0]
? reference_name
: (_dl_argv[0] ?: "<main program>")), NULL,
make_string (undefined_msg, undef_name,
@ -460,25 +446,7 @@ _dl_lookup_versioned_symbol (const char *undef_name,
protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
_dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n",
(reference_name && reference_name[0]
? reference_name : (_dl_argv[0] ?: "<main program>")),
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
protected ? "protected" : "normal",
undef_name, version->name);
}
if (__builtin_expect (protected == 0, 1))
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
else
if (__builtin_expect (protected != 0, 0))
{
/* It is very tricky. We need to figure out what value to
return for the protected symbol */
@ -490,14 +458,20 @@ _dl_lookup_versioned_symbol (const char *undef_name,
ELF_RTYPE_CLASS_PLT))
break;
if (protected_value.s == NULL || protected_value.m == undef_map)
if (protected_value.s != NULL && protected_value.m != undef_map)
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
current_value.s = *ref;
current_value.m = undef_map;
}
return LOOKUP_VALUE (undef_map);
}
if (__builtin_expect (_dl_debug_mask
& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
_dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
&current_value, version, type_class, protected);
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
@ -512,7 +486,7 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
const struct r_found_version *version,
struct link_map *skip_map)
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
const char *reference_name = undef_map->l_name;
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
@ -543,7 +517,7 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
__mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
undef_name, len + 1);
/* XXX We cannot translate the messages. */
_dl_signal_cerror (0, (reference_name && reference_name[0]
_dl_signal_cerror (0, (reference_name[0]
? reference_name
: (_dl_argv[0] ?: "<main program>")),
NULL, buf);
@ -554,21 +528,7 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0))
_dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n",
(reference_name && reference_name[0]
? reference_name : (_dl_argv[0] ?: "<main program>")),
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
protected ? "protected" : "normal",
undef_name, version->name);
if (__builtin_expect (protected == 0, 1))
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
else
if (__builtin_expect (protected != 0, 0))
{
/* It is very tricky. We need to figure out what value to
return for the protected symbol */
@ -584,14 +544,20 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
skip_map, ELF_RTYPE_CLASS_PLT))
break;
if (protected_value.s == NULL || protected_value.m == undef_map)
if (protected_value.s != NULL && protected_value.m != undef_map)
{
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
current_value.s = *ref;
current_value.m = undef_map;
}
return LOOKUP_VALUE (undef_map);
}
if (__builtin_expect (_dl_debug_mask
& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
_dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
&current_value, version, 0, protected);
*ref = current_value.s;
return LOOKUP_VALUE (current_value.m);
}
@ -615,6 +581,79 @@ _dl_setup_hash (struct link_map *map)
map->l_chain = hash;
}
static void
internal_function
_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
struct sym_val *value, const struct r_found_version *version,
int type_class, int protected)
{
const char *reference_name = undef_map->l_name;
if (_dl_debug_mask & DL_DEBUG_BINDINGS)
{
_dl_debug_printf ("binding file %s to %s: %s symbol `%s'",
(reference_name[0]
? reference_name : (_dl_argv[0] ?: "<main program>")),
value->m->l_name[0] ? value->m->l_name : _dl_argv[0],
protected ? "protected" : "normal",
undef_name);
if (version)
_dl_debug_printf_c (" [%s]\n", version->name);
else
_dl_debug_printf_c ("\n");
}
#ifdef SHARED
if (_dl_debug_mask & DL_DEBUG_PRELINK)
{
int conflict = 0;
struct sym_val val = { NULL, NULL };
if ((_dl_trace_prelink_map == NULL
|| _dl_trace_prelink_map == _dl_loaded)
&& undef_map != _dl_loaded)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
if (version == 0)
_dl_do_lookup (undef_name, hash, *ref, &val,
undef_map->l_local_scope[0], 0, NULL, type_class);
else
_dl_do_lookup_versioned (undef_name, hash, *ref, &val,
undef_map->l_local_scope[0], 0, version,
NULL, type_class);
if (val.s != value->s || val.m != value->m)
conflict = 1;
}
if (conflict
|| _dl_trace_prelink_map == undef_map
|| _dl_trace_prelink_map == NULL)
{
_dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ",
conflict ? "conflict" : "lookup",
(int) sizeof (ElfW(Addr)) * 2, undef_map->l_map_start,
(int) sizeof (ElfW(Addr)) * 2,
((ElfW(Addr)) *ref) - undef_map->l_map_start,
(int) sizeof (ElfW(Addr)) * 2,
(ElfW(Addr)) (value->s ? value->m->l_map_start : 0),
(int) sizeof (ElfW(Addr)) * 2,
(ElfW(Addr)) (value->s ? value->s->st_value : 0));
if (conflict)
_dl_printf ("x 0x%0*Zx 0x%0*Zx ",
(int) sizeof (ElfW(Addr)) * 2,
(ElfW(Addr)) (val.s ? val.m->l_map_start : 0),
(int) sizeof (ElfW(Addr)) * 2,
(ElfW(Addr)) (val.s ? val.s->st_value : 0));
_dl_printf ("/%x %s\n", type_class, undef_name);
}
}
#endif
}
/* These are here so that we only inline do_lookup{,_versioned} in the common
case, not everywhere. */
static int

View File

@ -23,7 +23,8 @@
#include <ldsodefs.h>
#include "dynamic-link.h"
#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
#if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
|| ELF_MACHINE_NO_REL
# define PLTREL ElfW(Rela)
#else
# define PLTREL ElfW(Rel)

View File

@ -33,6 +33,10 @@
#ifndef VERSYMIDX
# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
#endif
#ifndef VALIDX
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
#endif
/* Perform the relocations in MAP on the running program image as specified
by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT
@ -48,7 +52,7 @@ elf_dynamic_do_rel (struct link_map *map,
const ElfW(Rel) *end = (const void *) (reladdr + relsize);
ElfW(Addr) l_addr = map->l_addr;
#ifndef RTLD_BOOTSTRAP
#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
/* We never bind lazily during ld.so bootstrap. Unfortunately gcc is
not clever enough to see through all the function calls to realize
that. */
@ -81,8 +85,11 @@ elf_dynamic_do_rel (struct link_map *map,
/* Rela platforms get the offset from r_addend and this must
be copied in the relocation address. Therefore we can skip
the relative relocations only if this is for rel
relocations. */
relocations... */
if (l_addr != 0)
# else
/* ...or we know the object has been prelinked. */
if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
# endif
#endif
for (; relative < r; ++relative)

View File

@ -1,5 +1,5 @@
/* Inline functions for dynamic linking.
Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc.
Copyright (C) 1995,96,97,98,99,2000,2001 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
@ -58,31 +58,39 @@ elf_get_dynamic_info (struct link_map *l)
else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+ DT_VERSIONTAGNUM] = dyn;
else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+ DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
+ DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
else
assert (! "bad dynamic tag");
++dyn;
}
#ifndef DL_RO_DYN_SECTION
if (info[DT_PLTGOT] != NULL)
info[DT_PLTGOT]->d_un.d_ptr += l_addr;
if (info[DT_STRTAB] != NULL)
info[DT_STRTAB]->d_un.d_ptr += l_addr;
if (info[DT_SYMTAB] != NULL)
info[DT_SYMTAB]->d_un.d_ptr += l_addr;
# if ! ELF_MACHINE_NO_RELA
if (info[DT_RELA] != NULL)
/* Don't adjust .dynamic unnecessarily. */
if (l_addr)
{
assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
info[DT_RELA]->d_un.d_ptr += l_addr;
}
if (info[DT_PLTGOT] != NULL)
info[DT_PLTGOT]->d_un.d_ptr += l_addr;
if (info[DT_STRTAB] != NULL)
info[DT_STRTAB]->d_un.d_ptr += l_addr;
if (info[DT_SYMTAB] != NULL)
info[DT_SYMTAB]->d_un.d_ptr += l_addr;
# if ! ELF_MACHINE_NO_RELA
if (info[DT_RELA] != NULL)
info[DT_RELA]->d_un.d_ptr += l_addr;
# endif
# if ! ELF_MACHINE_NO_REL
if (info[DT_REL] != NULL)
{
assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
info[DT_REL]->d_un.d_ptr += l_addr;
}
if (info[DT_REL] != NULL)
info[DT_REL]->d_un.d_ptr += l_addr;
# endif
if (info[DT_JMPREL] != NULL)
info[DT_JMPREL]->d_un.d_ptr += l_addr;
if (info[VERSYMIDX (DT_VERSYM)] != NULL)
info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
}
#endif
if (info[DT_PLTREL] != NULL)
{
@ -95,12 +103,14 @@ elf_get_dynamic_info (struct link_map *l)
|| info[DT_PLTREL]->d_un.d_val == DT_RELA);
# endif
}
#ifndef DL_RO_DYN_SECTION
if (info[DT_JMPREL] != NULL)
info[DT_JMPREL]->d_un.d_ptr += l_addr;
if (info[VERSYMIDX (DT_VERSYM)] != NULL)
info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
#endif
# if ! ELF_MACHINE_NO_RELA
if (info[DT_RELA] != NULL)
assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
# endif
# if ! ELF_MACHINE_NO_REL
if (info[DT_REL] != NULL)
assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
# endif
if (info[DT_FLAGS] != NULL)
{
/* Flags are used. Translate to the old form where available.
@ -177,8 +187,8 @@ elf_get_dynamic_info (struct link_map *l)
\
if ((map)->l_info[DT_##RELOC]) \
{ \
ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
} \
if ((map)->l_info[DT_PLTREL] \
&& (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \

View File

@ -676,6 +676,8 @@ typedef struct
#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
#define DT_VALRNGHI 0x6ffffdff
#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
#define DT_VALNUM 12
/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
@ -692,6 +694,8 @@ typedef struct
#define DT_MOVETAB 0x6ffffefe /* Move table. */
#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
#define DT_ADDRRNGHI 0x6ffffeff
#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
#define DT_ADDRNUM 10
/* The versioning entry types. The next are defined as part of the
GNU extension. */

View File

@ -67,6 +67,8 @@ struct r_search_path *_dl_search_paths;
const char *_dl_profile;
const char *_dl_profile_output;
struct link_map *_dl_profile_map;
const char *_dl_trace_prelink;
struct link_map *_dl_trace_prelink_map;
int _dl_lazy = 1;
/* XXX I know about at least one case where we depend on the old weak
behavior (it has to do with librt). Until we get DSO groups implemented
@ -183,10 +185,14 @@ _dl_start (void *arg)
ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
#endif
/* Relocate ourselves so we can do normal function calls and
data access using the global offset table. */
if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)])
{
/* Relocate ourselves so we can do normal function calls and
data access using the global offset table. */
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
}
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
/* Please note that we don't allow profiling of this object and
therefore need not test whether we have to allocate the array
for the relocation results (as done in dl-reloc.c). */
@ -209,6 +215,15 @@ _dl_start (void *arg)
}
#ifndef VALIDX
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
#endif
#ifndef ADDRIDX
# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
#endif
static ElfW(Addr)
_dl_start_final (void *arg, struct link_map *bootstrap_map_p,
hp_timing_t start_time)
@ -218,6 +233,7 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
way to do this so we use this trick. gcc never inlines functions
which use `alloca'. */
ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
extern char _begin[], _end[];
if (HP_TIMING_AVAIL)
{
@ -237,10 +253,8 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
sizeof _dl_rtld_map.l_info);
_dl_setup_hash (&_dl_rtld_map);
_dl_rtld_map.l_mach = bootstrap_map_p->l_mach;
/* Don't bother trying to work out how ld.so is mapped in memory. */
_dl_rtld_map.l_map_start = ~0;
_dl_rtld_map.l_map_end = ~0;
_dl_rtld_map.l_map_start = (ElfW(Addr)) _begin;
_dl_rtld_map.l_map_end = (ElfW(Addr)) _end;
/* Call the OS-dependent function to set up life so we can do things like
file access. It will call `dl_main' (below) to do all the real work
@ -383,6 +397,7 @@ dl_main (const ElfW(Phdr) *phdr,
char *file;
int has_interp = 0;
unsigned int i;
int prelinked = 0;
int rtld_is_main = 0;
#ifndef HP_TIMING_NONAVAIL
hp_timing_t start;
@ -885,13 +900,42 @@ of this helper program; chances are you did not intend to run this program.\n\
{
struct link_map *l;
for (l = _dl_loaded->l_next; l; l = l->l_next)
if (l->l_faked)
/* The library was not found. */
_dl_printf ("\t%s => not found\n", l->l_libname->name);
else
_dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name,
l->l_name, (int) sizeof l->l_addr * 2, l->l_addr);
if (_dl_debug_mask & DL_DEBUG_PRELINK)
{
struct r_scope_elem *scope = &_dl_loaded->l_searchlist;
for (i = 0; i < scope->r_nlist; i++)
{
l = scope->r_list [i];
if (l->l_faked)
{
_dl_printf ("\t%s => not found\n", l->l_libname->name);
continue;
}
if (_dl_name_match_p (_dl_trace_prelink, l))
_dl_trace_prelink_map = l;
_dl_printf ("\t%s => %s (0x%0*Zx, 0x%0*Zx)\n",
l->l_libname->name[0] ? l->l_libname->name
: _dl_argv[0] ?: "<main program>",
l->l_name[0] ? l->l_name
: _dl_argv[0] ?: "<main program>",
(int) sizeof l->l_map_start * 2,
l->l_map_start,
(int) sizeof l->l_addr * 2,
l->l_addr);
}
}
else
{
for (l = _dl_loaded->l_next; l; l = l->l_next)
if (l->l_faked)
/* The library was not found. */
_dl_printf ("\t%s => not found\n", l->l_libname->name);
else
_dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name,
l->l_name, (int) sizeof l->l_map_start * 2,
l->l_map_start);
}
}
if (__builtin_expect (mode, trace) != trace)
@ -936,6 +980,10 @@ of this helper program; chances are you did not intend to run this program.\n\
}
l = l->l_prev;
} while (l);
if ((_dl_debug_mask & DL_DEBUG_PRELINK)
&& _dl_rtld_map.l_opencount > 1)
_dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0);
}
#define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED))
@ -1014,6 +1062,84 @@ of this helper program; chances are you did not intend to run this program.\n\
_exit (0);
}
if (_dl_loaded->l_info [ADDRIDX (DT_GNU_LIBLIST)]
&& ! __builtin_expect (_dl_profile != NULL, 0))
{
ElfW(Lib) *liblist, *liblistend;
struct link_map **r_list, **r_listend, *l;
const char *strtab = (const void *)
D_PTR (_dl_loaded, l_info[DT_STRTAB]);
assert (_dl_loaded->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
liblist = (ElfW(Lib) *)
_dl_loaded->l_info [ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
liblistend = (ElfW(Lib) *)
((char *) liblist
+ _dl_loaded->l_info [VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
r_list = _dl_loaded->l_searchlist.r_list;
r_listend = r_list + _dl_loaded->l_searchlist.r_nlist;
for (; r_list < r_listend && liblist < liblistend; r_list++)
{
l = *r_list;
if (l == _dl_loaded)
continue;
/* If the library is not mapped where it should, fail. */
if (l->l_addr)
break;
/* Next, check if checksum matches. */
if (l->l_info [VALIDX(DT_CHECKSUM)] == NULL
|| l->l_info [VALIDX(DT_CHECKSUM)]->d_un.d_val
!= liblist->l_checksum)
break;
if (l->l_info [VALIDX(DT_GNU_PRELINKED)] == NULL
|| l->l_info [VALIDX(DT_GNU_PRELINKED)]->d_un.d_val
!= liblist->l_time_stamp)
break;
if (! _dl_name_match_p (strtab + liblist->l_name, l))
break;
++liblist;
}
if (r_list == r_listend && liblist == liblistend)
prelinked = 1;
if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0))
_dl_printf ("\nprelink checking: %s\n", prelinked ? "ok" : "failed");
}
if (prelinked)
{
if (_dl_loaded->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
{
ElfW(Rela) *conflict, *conflictend;
#ifndef HP_TIMING_NONAVAIL
hp_timing_t start;
hp_timing_t stop;
#endif
HP_TIMING_NOW (start);
assert (_dl_loaded->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
conflict = (ElfW(Rela) *)
_dl_loaded->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
conflictend = (ElfW(Rela) *)
((char *) conflict
+ _dl_loaded->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
_dl_resolve_conflicts (_dl_loaded, conflict, conflictend);
HP_TIMING_NOW (stop);
HP_TIMING_DIFF (relocate_time, start, stop);
}
_dl_sysdep_start_cleanup ();
}
else
{
/* Now we have all the objects loaded. Relocate them all except for
the dynamic linker itself. We do this in reverse order so that copy
@ -1094,7 +1220,7 @@ of this helper program; chances are you did not intend to run this program.\n\
_dl_main_searchlist = &_dl_loaded->l_searchlist;
_dl_global_scope[0] = &_dl_loaded->l_searchlist;
/* Safe the information about the original global scope list since
/* Save the information about the original global scope list since
we need it in the memory handling later. */
_dl_initial_searchlist = *_dl_main_searchlist;
@ -1371,6 +1497,17 @@ process_envvars (enum mode *modep)
_dl_profile_output = &envline[15];
break;
case 16:
/* The mode of the dynamic linker can be set. */
if (memcmp (envline, "TRACE_PRELINKING", 16) == 0)
{
mode = trace;
_dl_verbose = 1;
_dl_debug_mask |= DL_DEBUG_PRELINK;
_dl_trace_prelink = &envline[17];
}
break;
case 20:
/* The mode of the dynamic linker can be set. */
if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0)

View File

@ -132,14 +132,20 @@ struct link_map
/* Indexed pointers to dynamic section.
[0,DT_NUM) are indexed by the processor-independent tags.
[DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC.
[DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_EXTRANUM) are indexed
by DT_EXTRATAGIDX(tagvalue) and
[DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are
indexed by DT_VERSIONTAGIDX(tagvalue).
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM,
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM)
are indexed by DT_EXTRATAGIDX(tagvalue) (see <elf.h>). */
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by
DT_EXTRATAGIDX(tagvalue).
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM,
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are
indexed by DT_VALTAGIDX(tagvalue) and
[DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM,
DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM)
are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>. */
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ DT_EXTRANUM];
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */
ElfW(Addr) l_entry; /* Entry point location. */
ElfW(Half) l_phnum; /* Number of program header entries. */

View File

@ -122,8 +122,30 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
*(Elf64_Addr *)(plt + 24) = (Elf64_Addr) l;
/* If the first instruction of the plt entry is not
"br $28, plt0", we cannot do lazy relocation. */
lazy = (*(unsigned int *)(plt + 32) == 0xc39ffff7);
"br $28, plt0", we have to reinitialize .plt for lazy relocation. */
if (*(unsigned int *)(plt + 32) != 0xc39ffff7)
{
unsigned int val = 0xc39ffff7;
unsigned int *slot, *end;
const Elf64_Rela *rela = D_PTR (l, l_info[DT_JMPREL]);
Elf64_Addr l_addr = l->l_addr;
/* br t12,.+4; ldq t12,12(t12); nop; jmp t12,(t12),.+4 */
*(unsigned long *)plt = 0xa77b000cc3600000;
*(unsigned long *)(plt + 8) = 0x6b7b000047ff041f;
slot = (unsigned int *)(plt + 32);
end = (unsigned int *)(plt + 32
+ l->l_info[DT_PLTRELSZ]->d_un.d_val / 2);
while (slot < end)
{
/* br at,.plt+0 */
*slot = val;
*(Elf64_Addr *) rela->r_offset = (Elf64_Addr) slot - l_addr;
val -= 3;
slot += 3;
++rela;
}
}
}
return lazy;
@ -520,8 +542,23 @@ elf_machine_rela (struct link_map *map,
if (r_type == R_ALPHA_GLOB_DAT)
*reloc_addr = sym_value;
else if (r_type == R_ALPHA_JMP_SLOT)
#ifdef RESOLVE_CONFLICT_FIND_MAP
/* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
are .rela.plt index. */
else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
{
/* elf_machine_fixup_plt needs the map reloc_addr points into,
while in _dl_resolve_conflicts map is _dl_loaded. */
RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
+ (r_type >> 8);
elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
}
#else
else if (r_type == R_ALPHA_JMP_SLOT)
elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
#endif
#ifndef RTLD_BOOTSTRAP
else if (r_type == R_ALPHA_REFQUAD)
{

4
sysdeps/arm/bits/link.h Normal file
View File

@ -0,0 +1,4 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt */
};

View File

@ -92,6 +92,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
/* If a library is prelinked but we have to relocate anyway,
we have to be able to undo the prelinking of .got.plt.
The prelinker saved us here address of .plt. */
if (got[1])
l->l_mach.plt = got[1] + l->l_addr;
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
/* The got[2] entry contains the address of a function which gets
@ -334,8 +339,9 @@ _dl_start_user:
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_ARM_JUMP_SLOT
/* The ARM never uses Elf32_Rela relocations. */
#define ELF_MACHINE_NO_RELA 1
/* ARM never uses Elf32_Rela relocations for the dynamic linker.
Prelinked libraries may use Elf32_Rela though. */
#define ELF_MACHINE_PLT_REL 1
/* We define an initialization functions. This is called very early in
_dl_sysdep_start. */
@ -371,6 +377,12 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
#ifdef RESOLVE
/* ARM never uses Elf32_Rela relocations for the dynamic linker.
Prelinked libraries may use Elf32_Rela though. */
#ifdef RTLD_BOOTSTRAP
#define ELF_MACHINE_NO_RELA 1
#endif
extern char **_dl_argv;
/* Deal with an out-of-range PC24 reloc. */
@ -517,6 +529,64 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
}
}
#ifndef RTLD_BOOTSTRAP
static inline void
elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
const Elf32_Sym *sym, const struct r_found_version *version,
Elf32_Addr *const reloc_addr)
{
const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
*reloc_addr = map->l_addr + reloc->r_addend;
#ifndef RTLD_BOOTSTRAP
else if (__builtin_expect (r_type == R_ARM_NONE, 0))
return;
#endif
else
{
const Elf32_Sym *const refsym = sym;
Elf32_Addr value = RESOLVE (&sym, version, r_type);
if (sym)
value += sym->st_value;
switch (r_type)
{
case R_ARM_GLOB_DAT:
case R_ARM_JUMP_SLOT:
case R_ARM_ABS32:
*reloc_addr = value + reloc->r_addend;
break;
case R_ARM_PC24:
{
Elf32_Addr newvalue, topbits;
newvalue = value + reloc->r_addend - (Elf32_Addr)reloc_addr;
topbits = newvalue & 0xfe000000;
if (topbits != 0xfe000000 && topbits != 0x00000000)
{
newvalue = fix_bad_pc24(reloc_addr, value)
- (Elf32_Addr)reloc_addr + (addend << 2);
topbits = newvalue & 0xfe000000;
if (topbits != 0xfe000000 && topbits != 0x00000000)
{
_dl_signal_error (0, map->l_name, NULL,
"R_ARM_PC24 relocation out of range");
}
}
newvalue >>= 2;
value = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
*reloc_addr = value;
}
break;
default:
_dl_reloc_bad_type (map, r_type, 0);
break;
}
}
}
#endif
static inline void
elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
Elf32_Addr *const reloc_addr)
@ -524,6 +594,15 @@ elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
*reloc_addr += l_addr;
}
#ifndef RTLD_BOOTSTRAP
static inline void
elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
Elf32_Addr *const reloc_addr)
{
*reloc_addr = l_addr + reloc->r_addend;
}
#endif
static inline void
elf_machine_lazy_rel (struct link_map *map,
Elf32_Addr l_addr, const Elf32_Rel *reloc)
@ -532,7 +611,12 @@ elf_machine_lazy_rel (struct link_map *map,
const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
*reloc_addr += l_addr;
{
if (__builtin_expect (map->l_mach.plt, 0) == 0)
*reloc_addr += l_addr;
else
*reloc_addr = map->l_mach.plt;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}

View File

@ -207,6 +207,8 @@ extern const char *_dl_profile;
extern struct link_map *_dl_profile_map;
/* Filename of the output file. */
extern const char *_dl_profile_output;
/* Map of shared object to be prelink traced. */
extern struct link_map *_dl_trace_prelink_map;
/* If nonzero the appropriate debug information is printed. */
extern int _dl_debug_mask;
@ -220,6 +222,7 @@ extern int _dl_debug_mask;
#define DL_DEBUG_STATISTICS (1 << 7)
/* This one is used only internally. */
#define DL_DEBUG_HELP (1 << 8)
#define DL_DEBUG_PRELINK (1 << 9)
/* Expect cache ID. */
extern int _dl_correct_cache_id;
@ -435,6 +438,11 @@ extern void _dl_reloc_bad_type (struct link_map *map,
unsigned int type, int plt)
internal_function __attribute__ ((__noreturn__));
/* Resolve conflicts if prelinking. */
extern void _dl_resolve_conflicts (struct link_map *l,
ElfW(Rela) *conflict,
ElfW(Rela) *conflictend);
/* Check the version dependencies of all objects available through
MAP. If VERBOSE print some more diagnostics. */
extern int _dl_check_all_versions (struct link_map *map, int verbose,

5
sysdeps/i386/bits/link.h Normal file
View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};

View File

@ -87,6 +87,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
/* If a library is prelinked but we have to relocate anyway,
we have to be able to undo the prelinking of .got.plt.
The prelinker saved us here address of .plt + 0x16. */
if (got[1])
{
l->l_mach.plt = got[1] + l->l_addr;
l->l_mach.gotplt = (Elf32_Addr) &got[3];
}
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
/* The got[2] entry contains the address of a function which gets
@ -258,8 +266,9 @@ _dl_start_user:\n\
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_386_JMP_SLOT
/* The i386 never uses Elf32_Rela relocations. */
#define ELF_MACHINE_NO_RELA 1
/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
Prelinked libraries may use Elf32_Rela though. */
#define ELF_MACHINE_PLT_REL 1
/* We define an initialization functions. This is called very early in
_dl_sysdep_start. */
@ -295,6 +304,12 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
#ifdef RESOLVE
/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
Prelinked libraries may use Elf32_Rela though. */
#ifdef RTLD_BOOTSTRAP
#define ELF_MACHINE_NO_RELA 1
#endif
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
MAP is the object containing the reloc. */
@ -378,6 +393,41 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
}
}
#ifndef RTLD_BOOTSTRAP
static inline void
elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
const Elf32_Sym *sym, const struct r_found_version *version,
Elf32_Addr *const reloc_addr)
{
if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
*reloc_addr = map->l_addr + reloc->r_addend;
else if (ELF32_R_TYPE (reloc->r_info) != R_386_NONE)
{
/* const Elf32_Sym *const refsym = sym; */
Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
if (sym)
value += sym->st_value;
switch (ELF32_R_TYPE (reloc->r_info))
{
case R_386_GLOB_DAT:
case R_386_JMP_SLOT:
case R_386_32:
*reloc_addr = value + reloc->r_addend;
break;
case R_386_PC32:
*reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
break;
default:
/* We add these checks in the version to relocate ld.so only
if we are still debugging. */
_dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
break;
}
}
}
#endif
static inline void
elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
Elf32_Addr *const reloc_addr)
@ -386,6 +436,15 @@ elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
*reloc_addr += l_addr;
}
#ifndef RTLD_BOOTSTRAP
static inline void
elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
Elf32_Addr *const reloc_addr)
{
*reloc_addr = l_addr + reloc->r_addend;
}
#endif
static inline void
elf_machine_lazy_rel (struct link_map *map,
Elf32_Addr l_addr, const Elf32_Rel *reloc)
@ -394,9 +453,26 @@ elf_machine_lazy_rel (struct link_map *map,
const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
*reloc_addr += l_addr;
{
if (__builtin_expect (map->l_mach.plt, 0) == 0)
*reloc_addr += l_addr;
else
*reloc_addr =
map->l_mach.plt
+ (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}
#ifndef RTLD_BOOTSTRAP
static inline void
elf_machine_lazy_rela (struct link_map *map,
Elf32_Addr l_addr, const Elf32_Rela *reloc)
{
}
#endif
#endif /* RESOLVE */

View File

@ -347,6 +347,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
Elf32_Word loadbase, finaladdr;
const int rinfo = ELF32_R_TYPE (reloc->r_info);
#ifndef RESOLVE_CONFLICT_FIND_MAP
if (__builtin_expect (rinfo == R_PPC_NONE, 0))
return;
@ -375,6 +376,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
+ reloc->r_addend);
}
#else
finaladdr = reloc->r_addend;
if (rinfo == R_PPC_JMP_SLOT)
RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
#endif
/* A small amount of code is duplicated here for speed. In libc,
more than 90% of the relocs are R_PPC_RELATIVE; in the X11 shared

View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x2c */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};

View File

@ -92,6 +92,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
Elf32_Addr *got;
got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
/* If a library is prelinked but we have to relocate anyway,
we have to be able to undo the prelinking of .got.plt.
The prelinker saved us here address of .plt + 0x2c. */
if (got[1])
{
l->l_mach.plt = got[1] + l->l_addr;
l->l_mach.gotplt = (Elf32_Addr) &got[3];
}
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
/* The got[2] entry contains the address of a function which gets
@ -454,7 +462,14 @@ elf_machine_lazy_rel (struct link_map *map,
const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
*reloc_addr += l_addr;
{
if (__builtin_expect (map->l_mach.plt, 0) == 0)
*reloc_addr += l_addr;
else
*reloc_addr =
map->l_mach.plt
+ (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 8;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}

View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf64_Addr plt; /* Address of .plt + 0x2e */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
};

View File

@ -85,6 +85,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
Elf64_Addr *got;
got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
/* If a library is prelinked but we have to relocate anyway,
we have to be able to undo the prelinking of .got.plt.
The prelinker saved us here address of .plt + 0x2e. */
if (got[1])
{
l->l_mach.plt = got[1] + l->l_addr;
l->l_mach.gotplt = (Elf64_Addr) &got[3];
}
got[1] = (Elf64_Addr) l; /* Identify this shared object. */
/* The got[2] entry contains the address of a function which gets
@ -434,7 +442,14 @@ elf_machine_lazy_rel (struct link_map *map,
const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
*reloc_addr += l_addr;
{
if (__builtin_expect (map->l_mach.plt, 0) == 0)
*reloc_addr += l_addr;
else
*reloc_addr =
map->l_mach.plt
+ (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}

5
sysdeps/sh/bits/link.h Normal file
View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 36 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
};

View File

@ -85,6 +85,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
offset into the .rela.plt section and _GLOBAL_OFFSET_TABLE_[1],
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
/* If a library is prelinked but we have to relocate anyway,
we have to be able to undo the prelinking of .got.plt.
The prelinker saved us here address of .plt + 36. */
if (got[1])
{
l->l_mach.plt = got[1] + l->l_addr;
l->l_mach.gotplt = (Elf32_Addr) &got[3];
}
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
/* The got[2] entry contains the address of a function which gets
@ -582,7 +590,14 @@ elf_machine_lazy_rel (struct link_map *map,
Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
/* Check for unexpected PLT reloc type. */
if (ELF32_R_TYPE (reloc->r_info) == R_SH_JMP_SLOT)
*reloc_addr += l_addr;
{
if (__builtin_expect (map->l_mach.plt, 0) == 0)
*reloc_addr += l_addr;
else
*reloc_addr =
map->l_mach.plt
+ (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 7;
}
else
_dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
}

View File

@ -23,6 +23,10 @@
#include <sys/param.h>
#include <ldsodefs.h>
#ifndef VALIDX
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
#endif
/* Some SPARC opcodes we need to use for self-modifying code. */
#define OPCODE_NOP 0x01000000 /* nop */
@ -30,6 +34,7 @@
#define OPCODE_SETHI_G1 0x03000000 /* sethi ?, %g1; add value>>10 */
#define OPCODE_JMP_G1 0x81c06000 /* jmp %g1+?; add lo 10 bits of value */
#define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
#define OPCODE_BA 0x30800000 /* b,a ?; add PC-rel word address */
/* Protect some broken versions of gcc from misinterpreting weak addresses. */
#define WEAKADDR(x) ({ __typeof(x) *_px = &x; \
@ -139,6 +144,37 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
plt[1] = OPCODE_CALL | ((rfunc - (Elf32_Addr) &plt[1]) >> 2);
plt[2] = OPCODE_NOP; /* Fill call delay slot. */
plt[3] = (Elf32_Addr) l;
if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
|| __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
{
/* Need to reinitialize .plt to undo prelinking. */
unsigned long *hwcap;
int do_flush;
Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]);
Elf32_Rela *relaend
= (Elf32_Rela *) ((char *) rela
+ l->l_info[DT_PLTRELSZ]->d_un.d_val);
weak_extern (_dl_hwcap);
hwcap = WEAKADDR(_dl_hwcap);
do_flush = (!hwcap || (*hwcap & HWCAP_SPARC_FLUSH));
/* prelink must ensure there are no R_SPARC_NONE relocs left
in .rela.plt. */
while (rela < relaend)
{
*(unsigned int *) rela->r_offset
= OPCODE_SETHI_G1 | (rela->r_offset - (Elf32_Addr) plt);
*(unsigned int *) (rela->r_offset + 4)
= OPCODE_BA | ((((Elf32_Addr) plt
- rela->r_offset - 4) >> 2) & 0x3fffff);
if (do_flush)
{
__asm __volatile ("flush %0" : : "r"(rela->r_offset));
__asm __volatile ("flush %0+4" : : "r"(rela->r_offset));
}
++rela;
}
}
}
return lazy;
@ -292,10 +328,10 @@ _dl_start_user:
.previous");
static inline Elf32_Addr
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
const Elf32_Rela *reloc,
Elf32_Addr *reloc_addr, Elf32_Addr value)
sparc_fixup_plt (const Elf32_Rela *reloc, Elf32_Addr *reloc_addr,
Elf32_Addr value, int t)
{
Elf32_Sword disp = value - (Elf32_Addr) reloc_addr;
#ifndef RTLD_BOOTSTRAP
/* Note that we don't mask the hwcap here, as the flush is essential to
functionality on those cpu's that implement it. */
@ -309,23 +345,44 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t t,
ld.so will not execute corrupt PLT entry instructions. */
const int do_flush = 1;
#endif
if (0 && disp >= -0x800000 && disp < 0x800000)
{
/* Don't need to worry about thread safety. We're writing just one
instruction. */
/* For thread safety, write the instructions from the bottom and
flush before we overwrite the critical "b,a". This of course
need not be done during bootstrapping, since there are no threads.
But we also can't tell if we _can_ use flush, so don't. */
reloc_addr[0] = OPCODE_BA | ((disp >> 2) & 0x3fffff);
if (do_flush)
__asm __volatile ("flush %0" : : "r"(reloc_addr));
}
else
{
/* For thread safety, write the instructions from the bottom and
flush before we overwrite the critical "b,a". This of course
need not be done during bootstrapping, since there are no threads.
But we also can't tell if we _can_ use flush, so don't. */
reloc_addr[2] = OPCODE_JMP_G1 | (value & 0x3ff);
if (do_flush)
__asm __volatile ("flush %0+8" : : "r"(reloc_addr));
reloc_addr += t;
reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
if (do_flush)
__asm __volatile ("flush %0+4" : : "r"(reloc_addr));
reloc_addr[1] = OPCODE_SETHI_G1 | (value >> 10);
if (do_flush)
__asm __volatile ("flush %0+4" : : "r"(reloc_addr));
reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
if (do_flush)
__asm __volatile ("flush %0" : : "r"(reloc_addr));
}
return value;
}
static inline Elf32_Addr
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
const Elf32_Rela *reloc,
Elf32_Addr *reloc_addr, Elf32_Addr value)
{
return sparc_fixup_plt (reloc, reloc_addr, value, 1);
}
/* Return the final value of a plt relocation. */
static inline Elf32_Addr
elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
@ -366,10 +423,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
else
#endif
{
#ifndef RTLD_BOOTSTRAP
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
const Elf32_Sym *const refsym = sym;
#endif
Elf32_Addr value;
#ifndef RESOLVE_CONFLICT_FIND_MAP
if (sym->st_shndx != SHN_UNDEF &&
ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
value = map->l_addr;
@ -379,11 +437,14 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
if (sym)
value += sym->st_value;
}
#else
value = 0;
#endif
value += reloc->r_addend; /* Assume copy relocs have zero addend. */
switch (r_type)
{
#ifndef RTLD_BOOTSTRAP
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
case R_SPARC_COPY:
if (sym == NULL)
/* This can happen in trace mode if an object could not be
@ -410,7 +471,9 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
*reloc_addr = value;
break;
case R_SPARC_JMP_SLOT:
elf_machine_fixup_plt(map, 0, reloc, reloc_addr, value);
/* At this point we don't need to bother with thread safety,
so we can optimize the first instruction of .plt out. */
sparc_fixup_plt (reloc, reloc_addr, value, 0);
break;
#ifndef RTLD_BOOTSTRAP
case R_SPARC_8:

View File

@ -24,6 +24,11 @@
#include <ldsodefs.h>
#include <sysdep.h>
#ifndef VALIDX
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
#endif
#define ELF64_R_TYPE_ID(info) ((info) & 0xff)
#define ELF64_R_TYPE_DATA(info) ((info) >> 8)
@ -147,7 +152,7 @@ sparc64_fixup_plt (struct link_map *map, const Elf64_Rela *reloc,
insns[1] = 0x40000000 | (displacement >> 2);
__asm __volatile ("flush %0 + 4" : : "r" (insns));
insns[t] = 0x8210000f;
insns[0] = 0x8210000f;
__asm __volatile ("flush %0" : : "r" (insns));
}
/* Worst case, ho hum... */
@ -251,10 +256,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
else
#endif
{
#ifndef RTLD_BOOTSTRAP
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
const Elf64_Sym *const refsym = sym;
#endif
Elf64_Addr value;
#ifndef RESOLVE_CONFLICT_FIND_MAP
if (sym->st_shndx != SHN_UNDEF &&
ELF64_ST_BIND (sym->st_info) == STB_LOCAL)
value = map->l_addr;
@ -264,11 +270,14 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
if (sym)
value += sym->st_value;
}
#else
value = 0;
#endif
value += reloc->r_addend; /* Assume copy relocs have zero addend. */
switch (r_type)
{
#ifndef RTLD_BOOTSTRAP
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
case R_SPARC_COPY:
if (sym == NULL)
/* This can happen in trace mode if an object could not be
@ -371,8 +380,18 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
break;
#endif
case R_SPARC_JMP_SLOT:
#ifdef RESOLVE_CONFLICT_FIND_MAP
/* R_SPARC_JMP_SLOT conflicts against .plt[32768+]
relocs should be turned into R_SPARC_64 relocs
in .gnu.conflict section.
r_addend non-zero does not mean it is a .plt[32768+]
reloc, instead it is the actual address of the function
to call. */
sparc64_fixup_plt (NULL, reloc, reloc_addr, value, 0, 0);
#else
sparc64_fixup_plt (map, reloc, reloc_addr, value,
reloc->r_addend, 0);
#endif
break;
#ifndef RTLD_BOOTSTRAP
case R_SPARC_UA16:
@ -536,6 +555,47 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
/* Now put the magic cookie at the beginning of .PLT2
Entry .PLT3 is unused by this implementation. */
*((struct link_map **)(&plt[16 + 0])) = l;
if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
|| __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
{
/* Need to reinitialize .plt to undo prelinking. */
Elf64_Rela *rela = (Elf64_Rela *) D_PTR (l, l_info[DT_JMPREL]);
Elf64_Rela *relaend
= (Elf64_Rela *) ((char *) rela
+ l->l_info[DT_PLTRELSZ]->d_un.d_val);
/* prelink must ensure there are no R_SPARC_NONE relocs left
in .rela.plt. */
while (rela < relaend)
{
if (__builtin_expect (rela->r_addend, 0) != 0)
{
Elf64_Addr slot = ((rela->r_offset + 0x400
- (Elf64_Addr) plt)
/ 0x1400) * 0x1400
+ (Elf64_Addr) plt - 0x400;
/* ldx [%o7 + X], %g1 */
unsigned int first_ldx = *(unsigned int *)(slot + 12);
Elf64_Addr ptr = slot + (first_ldx & 0xfff) + 4;
*(Elf64_Addr *) rela->r_offset
= (Elf64_Addr) plt
- (slot + ((rela->r_offset - ptr) / 8) * 24 + 4);
++rela;
continue;
}
*(unsigned int *) rela->r_offset
= 0x03000000 | (rela->r_offset - (Elf64_Addr) plt);
*(unsigned int *) (rela->r_offset + 4)
= 0x30680000 | ((((Elf64_Addr) plt + 32
- rela->r_offset - 4) >> 2) & 0x7ffff);
__asm __volatile ("flush %0" : : "r" (rela->r_offset));
__asm __volatile ("flush %0+4" : : "r" (rela->r_offset));
++rela;
}
}
}
return lazy;

View File

@ -0,0 +1,5 @@
struct link_map_machine
{
Elf64_Addr plt; /* Address of .plt + 0x16 */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
};

View File

@ -76,6 +76,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
and then jump to _GLOBAL_OFFSET_TABLE[2]. */
got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
/* If a library is prelinked but we have to relocate anyway,
we have to be able to undo the prelinking of .got.plt.
The prelinker saved us here address of .plt + 0x16. */
if (got[1])
{
l->l_mach.plt = got[1] + l->l_addr;
l->l_mach.gotplt = (Elf64_Addr) &got[3];
}
got[1] = (Elf64_Addr) l; /* Identify this shared object. */
/* The got[2] entry contains the address of a function which gets
@ -409,7 +417,14 @@ elf_machine_lazy_rel (struct link_map *map,
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == R_X86_64_JUMP_SLOT, 1))
*reloc_addr += l_addr;
{
if (__builtin_expect (map->l_mach.plt, 0) == 0)
*reloc_addr += l_addr;
else
*reloc_addr =
map->l_mach.plt
+ (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 2;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}