Blame elf/dl-runtime.c

Packit 6c4009
/* On-demand PLT fixup for shared objects.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#define IN_DL_RUNTIME 1		/* This can be tested in dl-machine.h.  */
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <sysdep-cancel.h>
Packit 6c4009
#include "dynamic-link.h"
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <dl-irel.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
Packit 6c4009
    || ELF_MACHINE_NO_REL
Packit 6c4009
# define PLTREL  ElfW(Rela)
Packit 6c4009
#else
Packit 6c4009
# define PLTREL  ElfW(Rel)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* The fixup functions might have need special attributes.  If none
Packit 6c4009
   are provided define the macro as empty.  */
Packit 6c4009
#ifndef ARCH_FIXUP_ATTRIBUTE
Packit 6c4009
# define ARCH_FIXUP_ATTRIBUTE
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef reloc_offset
Packit 6c4009
# define reloc_offset reloc_arg
Packit 6c4009
# define reloc_index  reloc_arg / sizeof (PLTREL)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This function is called through a special trampoline from the PLT the
Packit 6c4009
   first time each PLT entry is called.  We must perform the relocation
Packit 6c4009
   specified in the PLT of the given shared object, and return the resolved
Packit 6c4009
   function address to the trampoline, which will restart the original call
Packit 6c4009
   to that address.  Future calls will bounce directly from the PLT to the
Packit 6c4009
   function.  */
Packit 6c4009
Packit 6c4009
DL_FIXUP_VALUE_TYPE
Packit 6c4009
attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
Packit 6c4009
_dl_fixup (
Packit 6c4009
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
Packit 6c4009
	   ELF_MACHINE_RUNTIME_FIXUP_ARGS,
Packit 6c4009
# endif
Packit 6c4009
	   struct link_map *l, ElfW(Word) reloc_arg)
Packit 6c4009
{
Packit 6c4009
  const ElfW(Sym) *const symtab
Packit 6c4009
    = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
Packit 6c4009
  const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
Packit 6c4009
Packit 6c4009
  const PLTREL *const reloc
Packit 6c4009
    = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
Packit 6c4009
  const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
Packit 6c4009
  const ElfW(Sym) *refsym = sym;
Packit 6c4009
  void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
Packit 6c4009
  lookup_t result;
Packit 6c4009
  DL_FIXUP_VALUE_TYPE value;
Packit 6c4009
Packit 6c4009
  /* Sanity check that we're really looking at a PLT relocation.  */
Packit 6c4009
  assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
Packit 6c4009
Packit 6c4009
   /* Look up the target symbol.  If the normal lookup rules are not
Packit 6c4009
      used don't look in the global scope.  */
Packit 6c4009
  if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
Packit 6c4009
    {
Packit 6c4009
      const struct r_found_version *version = NULL;
Packit 6c4009
Packit 6c4009
      if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
Packit 6c4009
	{
Packit 6c4009
	  const ElfW(Half) *vernum =
Packit 6c4009
	    (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
Packit 6c4009
	  ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
Packit 6c4009
	  version = &l->l_versions[ndx];
Packit 6c4009
	  if (version->hash == 0)
Packit 6c4009
	    version = NULL;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* We need to keep the scope around so do some locking.  This is
Packit 6c4009
	 not necessary for objects which cannot be unloaded or when
Packit 6c4009
	 we are not using any threads (yet).  */
Packit 6c4009
      int flags = DL_LOOKUP_ADD_DEPENDENCY;
Packit 6c4009
      if (!RTLD_SINGLE_THREAD_P)
Packit 6c4009
	{
Packit 6c4009
	  THREAD_GSCOPE_SET_FLAG ();
Packit 6c4009
	  flags |= DL_LOOKUP_GSCOPE_LOCK;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
#ifdef RTLD_ENABLE_FOREIGN_CALL
Packit 6c4009
      RTLD_ENABLE_FOREIGN_CALL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
Packit 6c4009
				    version, ELF_RTYPE_CLASS_PLT, flags, NULL);
Packit 6c4009
Packit 6c4009
      /* We are done with the global scope.  */
Packit 6c4009
      if (!RTLD_SINGLE_THREAD_P)
Packit 6c4009
	THREAD_GSCOPE_RESET_FLAG ();
Packit 6c4009
Packit 6c4009
#ifdef RTLD_FINALIZE_FOREIGN_CALL
Packit 6c4009
      RTLD_FINALIZE_FOREIGN_CALL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      /* Currently result contains the base load address (or link map)
Packit 6c4009
	 of the object that defines sym.  Now add in the symbol
Packit 6c4009
	 offset.  */
Packit 6c4009
      value = DL_FIXUP_MAKE_VALUE (result,
Packit 6c4009
				   SYMBOL_ADDRESS (result, sym, false));
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* We already found the symbol.  The module (and therefore its load
Packit 6c4009
	 address) is also known.  */
Packit 6c4009
      value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, sym, true));
Packit 6c4009
      result = l;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* And now perhaps the relocation addend.  */
Packit 6c4009
  value = elf_machine_plt_value (l, reloc, value);
Packit 6c4009
Packit 6c4009
  if (sym != NULL
Packit 6c4009
      && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0))
Packit 6c4009
    value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
Packit 6c4009
Packit 6c4009
  /* Finally, fix up the plt itself.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_bind_not)))
Packit 6c4009
    return value;
Packit 6c4009
Packit 6c4009
  return elf_machine_fixup_plt (l, result, refsym, sym, reloc, rel_addr, value);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef PROF
Packit 6c4009
DL_FIXUP_VALUE_TYPE
Packit 6c4009
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
Packit 6c4009
_dl_profile_fixup (
Packit 6c4009
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
Packit 6c4009
		   ELF_MACHINE_RUNTIME_FIXUP_ARGS,
Packit 6c4009
#endif
Packit 6c4009
		   struct link_map *l, ElfW(Word) reloc_arg,
Packit 6c4009
		   ElfW(Addr) retaddr, void *regs, long int *framesizep)
Packit 6c4009
{
Packit 6c4009
  void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount;
Packit 6c4009
Packit 6c4009
  if (l->l_reloc_result == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* BZ #14843: ELF_DYNAMIC_RELOCATE is called before l_reloc_result
Packit 6c4009
	 is allocated.  We will get here if ELF_DYNAMIC_RELOCATE calls a
Packit 6c4009
	 resolver function to resolve an IRELATIVE relocation and that
Packit 6c4009
	 resolver calls a function that is not yet resolved (lazy).  For
Packit 6c4009
	 example, the resolver in x86-64 libm.so calls __get_cpu_features
Packit 6c4009
	 defined in libc.so.  Skip audit and resolve the external function
Packit 6c4009
	 in this case.  */
Packit 6c4009
      *framesizep = -1;
Packit 6c4009
      return _dl_fixup (
Packit 6c4009
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
Packit 6c4009
#  ifndef ELF_MACHINE_RUNTIME_FIXUP_PARAMS
Packit 6c4009
#   error Please define ELF_MACHINE_RUNTIME_FIXUP_PARAMS.
Packit 6c4009
#  endif
Packit 6c4009
			ELF_MACHINE_RUNTIME_FIXUP_PARAMS,
Packit 6c4009
# endif
Packit 6c4009
			l, reloc_arg);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* This is the address in the array where we store the result of previous
Packit 6c4009
     relocations.  */
Packit 6c4009
  struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
Packit 6c4009
Packit Service f7a43a
 /* CONCURRENCY NOTES:
Packit Service f7a43a
Packit Service f7a43a
  Multiple threads may be calling the same PLT sequence and with
Packit Service f7a43a
  LD_AUDIT enabled they will be calling into _dl_profile_fixup to
Packit Service f7a43a
  update the reloc_result with the result of the lazy resolution.
Packit Service f7a43a
  The reloc_result guard variable is reloc_init, and we use
Packit Service f7a43a
  acquire/release loads and store to it to ensure that the results of
Packit Service f7a43a
  the structure are consistent with the loaded value of the guard.
Packit Service f7a43a
  This does not fix all of the data races that occur when two or more
Packit Service f7a43a
  threads read reloc_result->reloc_init with a value of zero and read
Packit Service f7a43a
  and write to that reloc_result concurrently.  The expectation is
Packit Service f7a43a
  generally that while this is a data race it works because the
Packit Service f7a43a
  threads write the same values.  Until the data races are fixed
Packit Service f7a43a
  there is a potential for problems to arise from these data races.
Packit Service f7a43a
  The reloc result updates should happen in parallel but there should
Packit Service f7a43a
  be an atomic RMW which does the final update to the real result
Packit Service f7a43a
  entry (see bug 23790).
Packit Service f7a43a
Packit Service f7a43a
  The following code uses reloc_result->init set to 0 to indicate if it is
Packit Service f7a43a
  the first time this object is being relocated, otherwise 1 which
Packit Service f7a43a
  indicates the object has already been relocated.
Packit Service f7a43a
Packit Service f7a43a
  Reading/Writing from/to reloc_result->reloc_init must not happen
Packit Service f7a43a
  before previous writes to reloc_result complete as they could
Packit Service f7a43a
  end-up with an incomplete struct.  */
Packit Service f7a43a
  DL_FIXUP_VALUE_TYPE value;
Packit Service f7a43a
  unsigned int init = atomic_load_acquire (&reloc_result->init);
Packit Service f7a43a
Packit Service f7a43a
  if (init == 0)
Packit 6c4009
    {
Packit 6c4009
      /* This is the first time we have to relocate this object.  */
Packit 6c4009
      const ElfW(Sym) *const symtab
Packit 6c4009
	= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
Packit 6c4009
      const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
Packit 6c4009
Packit 6c4009
      const PLTREL *const reloc
Packit 6c4009
	= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
Packit 6c4009
      const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
Packit 6c4009
      const ElfW(Sym) *defsym = refsym;
Packit 6c4009
      lookup_t result;
Packit 6c4009
Packit 6c4009
      /* Sanity check that we're really looking at a PLT relocation.  */
Packit 6c4009
      assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
Packit 6c4009
Packit 6c4009
      /* Look up the target symbol.  If the symbol is marked STV_PROTECTED
Packit 6c4009
	 don't look in the global scope.  */
Packit 6c4009
      if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
Packit 6c4009
	{
Packit 6c4009
	  const struct r_found_version *version = NULL;
Packit 6c4009
Packit 6c4009
	  if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      const ElfW(Half) *vernum =
Packit 6c4009
		(const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
Packit 6c4009
	      ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
Packit 6c4009
	      version = &l->l_versions[ndx];
Packit 6c4009
	      if (version->hash == 0)
Packit 6c4009
		version = NULL;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* We need to keep the scope around so do some locking.  This is
Packit 6c4009
	     not necessary for objects which cannot be unloaded or when
Packit 6c4009
	     we are not using any threads (yet).  */
Packit 6c4009
	  int flags = DL_LOOKUP_ADD_DEPENDENCY;
Packit 6c4009
	  if (!RTLD_SINGLE_THREAD_P)
Packit 6c4009
	    {
Packit 6c4009
	      THREAD_GSCOPE_SET_FLAG ();
Packit 6c4009
	      flags |= DL_LOOKUP_GSCOPE_LOCK;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
Packit 6c4009
					&defsym, l->l_scope, version,
Packit 6c4009
					ELF_RTYPE_CLASS_PLT, flags, NULL);
Packit 6c4009
Packit 6c4009
	  /* We are done with the global scope.  */
Packit 6c4009
	  if (!RTLD_SINGLE_THREAD_P)
Packit 6c4009
	    THREAD_GSCOPE_RESET_FLAG ();
Packit 6c4009
Packit 6c4009
	  /* Currently result contains the base load address (or link map)
Packit 6c4009
	     of the object that defines sym.  Now add in the symbol
Packit 6c4009
	     offset.  */
Packit 6c4009
	  value = DL_FIXUP_MAKE_VALUE (result,
Packit 6c4009
				       SYMBOL_ADDRESS (result, defsym, false));
Packit 6c4009
Packit 6c4009
	  if (defsym != NULL
Packit 6c4009
	      && __builtin_expect (ELFW(ST_TYPE) (defsym->st_info)
Packit 6c4009
				   == STT_GNU_IFUNC, 0))
Packit 6c4009
	    value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* We already found the symbol.  The module (and therefore its load
Packit 6c4009
	     address) is also known.  */
Packit 6c4009
	  value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, refsym, true));
Packit 6c4009
Packit 6c4009
	  if (__builtin_expect (ELFW(ST_TYPE) (refsym->st_info)
Packit 6c4009
				== STT_GNU_IFUNC, 0))
Packit 6c4009
	    value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
Packit 6c4009
Packit 6c4009
	  result = l;
Packit 6c4009
	}
Packit 6c4009
      /* And now perhaps the relocation addend.  */
Packit 6c4009
      value = elf_machine_plt_value (l, reloc, value);
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
      /* Auditing checkpoint: we have a new binding.  Provide the
Packit 6c4009
	 auditing libraries the possibility to change the value and
Packit 6c4009
	 tell us whether further auditing is wanted.  */
Packit 6c4009
      if (defsym != NULL && GLRO(dl_naudit) > 0)
Packit 6c4009
	{
Packit 6c4009
	  reloc_result->bound = result;
Packit 6c4009
	  /* Compute index of the symbol entry in the symbol table of
Packit 6c4009
	     the DSO with the definition.  */
Packit 6c4009
	  reloc_result->boundndx = (defsym
Packit 6c4009
				    - (ElfW(Sym) *) D_PTR (result,
Packit 6c4009
							   l_info[DT_SYMTAB]));
Packit 6c4009
Packit 6c4009
	  /* Determine whether any of the two participating DSOs is
Packit 6c4009
	     interested in auditing.  */
Packit 6c4009
	  if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      unsigned int flags = 0;
Packit 6c4009
	      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
	      /* Synthesize a symbol record where the st_value field is
Packit 6c4009
		 the result.  */
Packit 6c4009
	      ElfW(Sym) sym = *defsym;
Packit 6c4009
	      sym.st_value = DL_FIXUP_VALUE_ADDR (value);
Packit 6c4009
Packit 6c4009
	      /* Keep track whether there is any interest in tracing
Packit 6c4009
		 the call in the lower two bits.  */
Packit 6c4009
	      assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
Packit 6c4009
	      assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
Packit 6c4009
	      reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
Packit 6c4009
Packit 6c4009
	      const char *strtab2 = (const void *) D_PTR (result,
Packit 6c4009
							  l_info[DT_STRTAB]);
Packit 6c4009
Packit 6c4009
	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
		{
Packit 6c4009
		  /* XXX Check whether both DSOs must request action or
Packit 6c4009
		     only one */
Packit Service 050912
		  struct auditstate *l_state = link_map_audit_state (l, cnt);
Packit Service 050912
		  struct auditstate *result_state
Packit Service 050912
		    = link_map_audit_state (result, cnt);
Packit Service 050912
		  if ((l_state->bindflags & LA_FLG_BINDFROM) != 0
Packit Service 050912
		      && (result_state->bindflags & LA_FLG_BINDTO) != 0)
Packit 6c4009
		    {
Packit 6c4009
		      if (afct->symbind != NULL)
Packit 6c4009
			{
Packit 6c4009
			  uintptr_t new_value
Packit 6c4009
			    = afct->symbind (&sym, reloc_result->boundndx,
Packit Service 050912
					     &l_state->cookie,
Packit Service 050912
					     &result_state->cookie,
Packit 6c4009
					     &flags,
Packit 6c4009
					     strtab2 + defsym->st_name);
Packit 6c4009
			  if (new_value != (uintptr_t) sym.st_value)
Packit 6c4009
			    {
Packit 6c4009
			      flags |= LA_SYMB_ALTVALUE;
Packit 6c4009
			      sym.st_value = new_value;
Packit 6c4009
			    }
Packit 6c4009
			}
Packit 6c4009
Packit 6c4009
		      /* Remember the results for every audit library and
Packit 6c4009
			 store a summary in the first two bits.  */
Packit 6c4009
		      reloc_result->enterexit
Packit 6c4009
			&= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
Packit 6c4009
		      reloc_result->enterexit
Packit 6c4009
			|= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
Packit 6c4009
			    << ((cnt + 1) * 2));
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    /* If the bind flags say this auditor is not interested,
Packit 6c4009
		       set the bits manually.  */
Packit 6c4009
		    reloc_result->enterexit
Packit 6c4009
		      |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
Packit 6c4009
			  << ((cnt + 1) * 2));
Packit 6c4009
Packit 6c4009
		  afct = afct->next;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      reloc_result->flags = flags;
Packit 6c4009
	      value = DL_FIXUP_ADDR_VALUE (sym.st_value);
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    /* Set all bits since this symbol binding is not interesting.  */
Packit 6c4009
	    reloc_result->enterexit = (1u << DL_NNS) - 1;
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      /* Store the result for later runs.  */
Packit 6c4009
      if (__glibc_likely (! GLRO(dl_bind_not)))
Packit Service f7a43a
	{
Packit Service f7a43a
	  reloc_result->addr = value;
Packit Service f7a43a
	  /* Guarantee all previous writes complete before
Packit Service f7a43a
	     init is updated.  See CONCURRENCY NOTES earlier  */
Packit Service f7a43a
	  atomic_store_release (&reloc_result->init, 1);
Packit Service f7a43a
	}
Packit Service f7a43a
      init = 1;
Packit 6c4009
    }
Packit Service f7a43a
  else
Packit Service f7a43a
    value = reloc_result->addr;
Packit 6c4009
Packit 6c4009
  /* By default we do not call the pltexit function.  */
Packit 6c4009
  long int framesize = -1;
Packit 6c4009
Packit Service f7a43a
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Auditing checkpoint: report the PLT entering and allow the
Packit 6c4009
     auditors to change the value.  */
Packit Service f7a43a
  if (GLRO(dl_naudit) > 0
Packit 6c4009
      /* Don't do anything if no auditor wants to intercept this call.  */
Packit 6c4009
      && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
Packit 6c4009
    {
Packit Service f7a43a
      /* Sanity check:  DL_FIXUP_VALUE_CODE_ADDR (value) should have been
Packit Service f7a43a
	 initialized earlier in this function or in another thread.  */
Packit Service f7a43a
      assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0);
Packit 6c4009
      ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
Packit 6c4009
						l_info[DT_SYMTAB])
Packit 6c4009
			   + reloc_result->boundndx);
Packit 6c4009
Packit 6c4009
      /* Set up the sym parameter.  */
Packit 6c4009
      ElfW(Sym) sym = *defsym;
Packit 6c4009
      sym.st_value = DL_FIXUP_VALUE_ADDR (value);
Packit 6c4009
Packit 6c4009
      /* Get the symbol name.  */
Packit 6c4009
      const char *strtab = (const void *) D_PTR (reloc_result->bound,
Packit 6c4009
						 l_info[DT_STRTAB]);
Packit 6c4009
      const char *symname = strtab + sym.st_name;
Packit 6c4009
Packit 6c4009
      /* Keep track of overwritten addresses.  */
Packit 6c4009
      unsigned int flags = reloc_result->flags;
Packit 6c4009
Packit 6c4009
      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (afct->ARCH_LA_PLTENTER != NULL
Packit 6c4009
	      && (reloc_result->enterexit
Packit 6c4009
		  & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      long int new_framesize = -1;
Packit Service 050912
	      struct auditstate *l_state = link_map_audit_state (l, cnt);
Packit Service 050912
	      struct auditstate *bound_state
Packit Service 050912
		= link_map_audit_state (reloc_result->bound, cnt);
Packit 6c4009
	      uintptr_t new_value
Packit 6c4009
		= afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
Packit Service 050912
					  &l_state->cookie,
Packit Service 050912
					  &bound_state->cookie,
Packit 6c4009
					  regs, &flags, symname,
Packit 6c4009
					  &new_framesize);
Packit 6c4009
	      if (new_value != (uintptr_t) sym.st_value)
Packit 6c4009
		{
Packit 6c4009
		  flags |= LA_SYMB_ALTVALUE;
Packit 6c4009
		  sym.st_value = new_value;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* Remember the results for every audit library and
Packit 6c4009
		 store a summary in the first two bits.  */
Packit 6c4009
	      reloc_result->enterexit
Packit 6c4009
		|= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
Packit 6c4009
		    << (2 * (cnt + 1)));
Packit 6c4009
Packit 6c4009
	      if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
Packit 6c4009
					      << (2 * (cnt + 1))))
Packit 6c4009
		  == 0 && new_framesize != -1 && framesize != -2)
Packit 6c4009
		{
Packit 6c4009
		  /* If this is the first call providing information,
Packit 6c4009
		     use it.  */
Packit 6c4009
		  if (framesize == -1)
Packit 6c4009
		    framesize = new_framesize;
Packit 6c4009
		  /* If two pltenter calls provide conflicting information,
Packit 6c4009
		     use the larger value.  */
Packit 6c4009
		  else if (new_framesize != framesize)
Packit 6c4009
		    framesize = MAX (new_framesize, framesize);
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  afct = afct->next;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      value = DL_FIXUP_ADDR_VALUE (sym.st_value);
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Store the frame size information.  */
Packit 6c4009
  *framesizep = framesize;
Packit 6c4009
Packit 6c4009
  (*mcount_fct) (retaddr, DL_FIXUP_VALUE_CODE_ADDR (value));
Packit 6c4009
Packit 6c4009
  return value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* PROF */
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
void
Packit 6c4009
ARCH_FIXUP_ATTRIBUTE
Packit 6c4009
_dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg,
Packit 6c4009
		  const void *inregs, void *outregs)
Packit 6c4009
{
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* This is the address in the array where we store the result of previous
Packit 6c4009
     relocations.  */
Packit 6c4009
  // XXX Maybe the bound information must be stored on the stack since
Packit 6c4009
  // XXX with bind_not a new value could have been stored in the meantime.
Packit 6c4009
  struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
Packit 6c4009
  ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
Packit 6c4009
					    l_info[DT_SYMTAB])
Packit 6c4009
		       + reloc_result->boundndx);
Packit 6c4009
Packit 6c4009
  /* Set up the sym parameter.  */
Packit 6c4009
  ElfW(Sym) sym = *defsym;
Packit 6c4009
  sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr);
Packit 6c4009
Packit 6c4009
  /* Get the symbol name.  */
Packit 6c4009
  const char *strtab = (const void *) D_PTR (reloc_result->bound,
Packit 6c4009
					     l_info[DT_STRTAB]);
Packit 6c4009
  const char *symname = strtab + sym.st_name;
Packit 6c4009
Packit 6c4009
  struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
  for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
    {
Packit 6c4009
      if (afct->ARCH_LA_PLTEXIT != NULL
Packit 6c4009
	  && (reloc_result->enterexit
Packit 6c4009
	      & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
Packit 6c4009
	{
Packit Service 050912
	  struct auditstate *l_state = link_map_audit_state (l, cnt);
Packit Service 050912
	  struct auditstate *bound_state
Packit Service 050912
	    = link_map_audit_state (reloc_result->bound, cnt);
Packit 6c4009
	  afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
Packit Service 050912
				 &l_state->cookie, &bound_state->cookie,
Packit 6c4009
				 inregs, outregs, symname);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      afct = afct->next;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
}