mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 10:22:41 +08:00
e6caf4e12e
2002-03-01 Ulrich Drepper <drepper@redhat.com> * elf/Makefile (dl-routines): Add dl-origin. (elide-routines.os): Add dl-origin. * elf/Versions [ld] (GLIBC_PRIVATE): Add _dl_get_origin. * elf/dl-debug.c (_dl_debug_initialize): Add missing INTUSE around _dl_debug_state. * include/libc-symbols.c: Define attribute_hidden depending on HAVE_VISIBILITY_ATTRIBUTE. Add definition of INTVARDEF. * elf/dl-deps.c: Use INTUSE with __libc_enable_secure. * elf/dl-load.c: Likewise. * elf/rtld.c: Likewise. * include/unistd.h: Declare __libc_enable_secure_internal. * sysdeps/generic/dl-sysdep.c: Use INTVARDEF with __libc_enable_secure. Use INTUSE with __libc_enable_secure. * sysdeps/mach/hurd/dl-sysdep.c: Likewise. * elf/dl-deps.c: Use INTUSE with _dl_out_of_memory. * elf/dl-error.c: Likewise, * sysdeps/generic/ldsodefs.h: Declare _dl_out_of_memory_internal. * elf/dl-dst.h [_RTLD_GLOBAL]: Define _dl_get_origin to use INTUSE. * sysdeps/generic/dl-origin.c: Undefine _dl_get_origin macro before function definition. Use INTDEF with _dl_get_origin. * sysdeps/unix/sysv/linux/dl-origin.c: Likewise. * elf/dl-init.c: Use INTUSE with _dl_starting_up. * elf/rtld.c: Likewise. Use INTVARDEF for _dl_starting_up. * elf/dl-profile.c: Use INTDEF for _dl_mcount. * elf/dl-runtime.c: Use INTUSE with _dl_mcount. * sysdeps/generic/ldsodefs.h: Declare _dl_mcount_internal. * elf/dl-conflict.c: Use rtld_progrname instead of _dl_argv[0]. * elf/dl-deps.c: Likewise. * elf/dl-error.c: Likewise. * elf/dl-fini.c: Likewise. * elf/dl-init.c: Likewise. * elf/dl-load.c: Likewise. * elf/dl-lookup.c: Likewise. * elf/dl-reloc.c: Likewise. * elf/dl-version.c: Likewise. * elf/do-lookup.h: Likewise. * sysdeps/arm/dl-machine.h: Likewise. * sysdeps/cris/dl-machine.h: Likewise. * sysdeps/hppa/dl-machine.h: Likewise. * sysdeps/i386/dl-machine.h: Likewise. * sysdeps/m68k/dl-machine.h: Likewise. * sysdeps/powerpc/dl-machine.h: Likewise. * sysdeps/s390/s390-32/dl-machine.h: Likewise. * sysdeps/s390/s390-64/dl-machine.h: Likewise. * sysdeps/sh/dl-machine.h: Likewise. * sysdeps/sparc/sparc-32/dl-machine.h: Likewise. * sysdeps/sparc/sparc-64/dl-machine.h: Likewise. * sysdeps/x86_64/dl-machine.h: Likewise. * elf/rtld.c: Use INTDEF for _dl_argv. Use rtld_progrname instead of _dl_argv[0]. Use INTUSE with _dl_argv. * sysdeps/generic/dl-sysdep.c: Use INTUSE with _dl_argv. * sysdeps/generic/ldsodefs.h: Define rtld_progname macro.
236 lines
7.6 KiB
C
236 lines
7.6 KiB
C
/* On-demand PLT fixup for shared objects.
|
|
Copyright (C) 1995-1999, 2000, 2001, 2002 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
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307 USA. */
|
|
|
|
#include <alloca.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ldsodefs.h>
|
|
#include "dynamic-link.h"
|
|
|
|
#if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
|
|
|| ELF_MACHINE_NO_REL
|
|
# define PLTREL ElfW(Rela)
|
|
#else
|
|
# define PLTREL ElfW(Rel)
|
|
#endif
|
|
|
|
#ifndef VERSYMIDX
|
|
# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
|
|
#endif
|
|
|
|
|
|
/* This function is called through a special trampoline from the PLT the
|
|
first time each PLT entry is called. We must perform the relocation
|
|
specified in the PLT of the given shared object, and return the resolved
|
|
function address to the trampoline, which will restart the original call
|
|
to that address. Future calls will bounce directly from the PLT to the
|
|
function. */
|
|
|
|
#ifndef ELF_MACHINE_NO_PLT
|
|
static ElfW(Addr) __attribute_used__
|
|
fixup (
|
|
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
|
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
|
# endif
|
|
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
|
without the `__unbounded' qualifier. */
|
|
struct link_map *__unbounded l, ElfW(Word) reloc_offset)
|
|
{
|
|
const ElfW(Sym) *const symtab
|
|
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
|
|
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
|
|
|
|
const PLTREL *const reloc
|
|
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
|
|
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
|
|
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
|
|
lookup_t result;
|
|
ElfW(Addr) value;
|
|
|
|
/* The use of `alloca' here looks ridiculous but it helps. The goal is
|
|
to prevent the function from being inlined and thus optimized out.
|
|
There is no official way to do this so we use this trick. gcc never
|
|
inlines functions which use `alloca'. */
|
|
alloca (sizeof (int));
|
|
|
|
/* Sanity check that we're really looking at a PLT relocation. */
|
|
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
|
|
|
|
/* Look up the target symbol. If the normal lookup rules are not
|
|
used don't look in the global scope. */
|
|
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
|
{
|
|
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
|
{
|
|
default:
|
|
{
|
|
const ElfW(Half) *vernum =
|
|
(const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
|
|
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
|
|
const struct r_found_version *version = &l->l_versions[ndx];
|
|
|
|
if (version->hash != 0)
|
|
{
|
|
result = INTUSE(_dl_lookup_versioned_symbol) (strtab
|
|
+ sym->st_name,
|
|
l, &sym, l->l_scope,
|
|
version,
|
|
ELF_RTYPE_CLASS_PLT,
|
|
0);
|
|
break;
|
|
}
|
|
}
|
|
case 0:
|
|
result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym,
|
|
l->l_scope, ELF_RTYPE_CLASS_PLT, 0);
|
|
}
|
|
|
|
/* Currently result contains the base load address (or link map)
|
|
of the object that defines sym. Now add in the symbol
|
|
offset. */
|
|
value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
|
|
}
|
|
else
|
|
{
|
|
/* We already found the symbol. The module (and therefore its load
|
|
address) is also known. */
|
|
value = l->l_addr + sym->st_value;
|
|
#ifdef DL_LOOKUP_RETURNS_MAP
|
|
result = l;
|
|
#endif
|
|
}
|
|
|
|
/* And now perhaps the relocation addend. */
|
|
value = elf_machine_plt_value (l, reloc, value);
|
|
|
|
/* Finally, fix up the plt itself. */
|
|
if (__builtin_expect (GL(dl_bind_not), 0))
|
|
return value;
|
|
|
|
return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
|
|
}
|
|
#endif
|
|
|
|
#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
|
|
|
|
static ElfW(Addr) __attribute_used__
|
|
profile_fixup (
|
|
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
|
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
|
#endif
|
|
struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
|
|
{
|
|
void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
|
|
ElfW(Addr) *resultp;
|
|
lookup_t result;
|
|
ElfW(Addr) value;
|
|
|
|
/* The use of `alloca' here looks ridiculous but it helps. The goal is
|
|
to prevent the function from being inlined, and thus optimized out.
|
|
There is no official way to do this so we use this trick. gcc never
|
|
inlines functions which use `alloca'. */
|
|
alloca (sizeof (int));
|
|
|
|
/* This is the address in the array where we store the result of previous
|
|
relocations. */
|
|
resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
|
|
|
|
value = *resultp;
|
|
if (value == 0)
|
|
{
|
|
/* This is the first time we have to relocate this object. */
|
|
const ElfW(Sym) *const symtab
|
|
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
|
|
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
|
|
|
|
const PLTREL *const reloc
|
|
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
|
|
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
|
|
|
|
/* Sanity check that we're really looking at a PLT relocation. */
|
|
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
|
|
|
|
/* Look up the target symbol. If the symbol is marked STV_PROTECTED
|
|
don't look in the global scope. */
|
|
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
|
{
|
|
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
|
{
|
|
default:
|
|
{
|
|
const ElfW(Half) *vernum =
|
|
(const void *) D_PTR (l,l_info[VERSYMIDX (DT_VERSYM)]);
|
|
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
|
|
const struct r_found_version *version = &l->l_versions[ndx];
|
|
|
|
if (version->hash != 0)
|
|
{
|
|
result = INTUSE(_dl_lookup_versioned_symbol) (strtab
|
|
+ sym->st_name,
|
|
l, &sym,
|
|
l->l_scope,
|
|
version,
|
|
ELF_RTYPE_CLASS_PLT,
|
|
0);
|
|
break;
|
|
}
|
|
}
|
|
case 0:
|
|
result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym,
|
|
l->l_scope, ELF_RTYPE_CLASS_PLT,
|
|
0);
|
|
}
|
|
|
|
/* Currently result contains the base load address (or link map)
|
|
of the object that defines sym. Now add in the symbol
|
|
offset. */
|
|
value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
|
|
}
|
|
else
|
|
{
|
|
/* We already found the symbol. The module (and therefore its load
|
|
address) is also known. */
|
|
value = l->l_addr + sym->st_value;
|
|
#ifdef DL_LOOKUP_RETURNS_MAP
|
|
result = l;
|
|
#endif
|
|
}
|
|
/* And now perhaps the relocation addend. */
|
|
value = elf_machine_plt_value (l, reloc, value);
|
|
|
|
/* Store the result for later runs. */
|
|
if (__builtin_expect (! GL(dl_bind_not), 1))
|
|
*resultp = value;
|
|
}
|
|
|
|
(*mcount_fct) (retaddr, value);
|
|
|
|
return value;
|
|
}
|
|
|
|
#endif /* PROF && ELF_MACHINE_NO_PLT */
|
|
|
|
|
|
/* This macro is defined in dl-machine.h to define the entry point called
|
|
by the PLT. The `fixup' function above does the real work, but a little
|
|
more twiddling is needed to get the stack right and jump to the address
|
|
finally resolved. */
|
|
|
|
ELF_MACHINE_RUNTIME_TRAMPOLINE
|