Blame elf/do-rel.h

Packit 6c4009
/* Do relocations for ELF dynamic linking.
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
/* This file may be included twice, to define both
Packit 6c4009
   `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.  */
Packit 6c4009
Packit 6c4009
#ifdef DO_RELA
Packit 6c4009
# define elf_dynamic_do_Rel		elf_dynamic_do_Rela
Packit 6c4009
# define Rel				Rela
Packit 6c4009
# define elf_machine_rel		elf_machine_rela
Packit 6c4009
# define elf_machine_rel_relative	elf_machine_rela_relative
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef DO_ELF_MACHINE_REL_RELATIVE
Packit 6c4009
# define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \
Packit 6c4009
  elf_machine_rel_relative (l_addr, relative,				      \
Packit 6c4009
			    (void *) (l_addr + relative->r_offset))
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Perform the relocations in MAP on the running program image as specified
Packit 6c4009
   by RELTAG, SZTAG.  If LAZY is nonzero, this is the first pass on PLT
Packit 6c4009
   relocations; they should be set up to call _dl_runtime_resolve, rather
Packit 6c4009
   than fully resolved now.  */
Packit 6c4009
Packit 6c4009
auto inline void __attribute__ ((always_inline))
Packit 6c4009
elf_dynamic_do_Rel (struct link_map *map,
Packit 6c4009
		    ElfW(Addr) reladdr, ElfW(Addr) relsize,
Packit 6c4009
		    __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
Packit 6c4009
		    int lazy, int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  const ElfW(Rel) *r = (const void *) reladdr;
Packit 6c4009
  const ElfW(Rel) *end = (const void *) (reladdr + relsize);
Packit 6c4009
  ElfW(Addr) l_addr = map->l_addr;
Packit 6c4009
# if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
Packit 6c4009
  const ElfW(Rel) *r2 = NULL;
Packit 6c4009
  const ElfW(Rel) *end2 = NULL;
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
Packit 6c4009
  /* We never bind lazily during ld.so bootstrap.  Unfortunately gcc is
Packit 6c4009
     not clever enough to see through all the function calls to realize
Packit 6c4009
     that.  */
Packit 6c4009
  if (lazy)
Packit 6c4009
    {
Packit 6c4009
      /* Doing lazy PLT relocations; they need very little info.  */
Packit 6c4009
      for (; r < end; ++r)
Packit 6c4009
# ifdef ELF_MACHINE_IRELATIVE
Packit 6c4009
	if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
Packit 6c4009
	  {
Packit 6c4009
	    if (r2 == NULL)
Packit 6c4009
	      r2 = r;
Packit 6c4009
	    end2 = r;
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
# endif
Packit 6c4009
	  elf_machine_lazy_rel (map, l_addr, r, skip_ifunc);
Packit 6c4009
Packit 6c4009
# ifdef ELF_MACHINE_IRELATIVE
Packit 6c4009
      if (r2 != NULL)
Packit 6c4009
	for (; r2 <= end2; ++r2)
Packit 6c4009
	  if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
Packit 6c4009
	    elf_machine_lazy_rel (map, l_addr, r2, skip_ifunc);
Packit 6c4009
# endif
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
#endif
Packit 6c4009
    {
Packit 6c4009
      const ElfW(Sym) *const symtab =
Packit 6c4009
	(const void *) D_PTR (map, l_info[DT_SYMTAB]);
Packit 6c4009
      const ElfW(Rel) *relative = r;
Packit 6c4009
      r += nrelative;
Packit 6c4009
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
      /* This is defined in rtld.c, but nowhere in the static libc.a; make
Packit 6c4009
	 the reference weak so static programs can still link.  This
Packit 6c4009
	 declaration cannot be done when compiling rtld.c (i.e. #ifdef
Packit 6c4009
	 RTLD_BOOTSTRAP) because rtld.c contains the common defn for
Packit 6c4009
	 _dl_rtld_map, which is incompatible with a weak decl in the same
Packit 6c4009
	 file.  */
Packit 6c4009
# ifndef SHARED
Packit 6c4009
      weak_extern (GL(dl_rtld_map));
Packit 6c4009
# endif
Packit 6c4009
      if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
Packit 6c4009
# if !defined DO_RELA || defined ELF_MACHINE_REL_RELATIVE
Packit 6c4009
	/* Rela platforms get the offset from r_addend and this must
Packit 6c4009
	   be copied in the relocation address.  Therefore we can skip
Packit 6c4009
	   the relative relocations only if this is for rel
Packit 6c4009
	   relocations or rela relocations if they are computed as
Packit 6c4009
	   memory_loc += l_addr...  */
Packit 6c4009
	if (l_addr != 0)
Packit 6c4009
# else
Packit 6c4009
	/* ...or we know the object has been prelinked.  */
Packit 6c4009
	if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	  for (; relative < r; ++relative)
Packit 6c4009
	    DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
Packit 6c4009
Packit 6c4009
#ifdef RTLD_BOOTSTRAP
Packit 6c4009
      /* The dynamic linker always uses versioning.  */
Packit 6c4009
      assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
Packit 6c4009
#else
Packit 6c4009
      if (map->l_info[VERSYMIDX (DT_VERSYM)])
Packit 6c4009
#endif
Packit 6c4009
	{
Packit 6c4009
	  const ElfW(Half) *const version =
Packit 6c4009
	    (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
Packit 6c4009
Packit 6c4009
	  for (; r < end; ++r)
Packit 6c4009
	    {
Packit 6c4009
#if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
Packit 6c4009
	      if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
Packit 6c4009
		{
Packit 6c4009
		  if (r2 == NULL)
Packit 6c4009
		    r2 = r;
Packit 6c4009
		  end2 = r;
Packit 6c4009
		  continue;
Packit 6c4009
		}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
Packit 6c4009
	      elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
Packit 6c4009
			       &map->l_versions[ndx],
Packit 6c4009
			       (void *) (l_addr + r->r_offset), skip_ifunc);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
#if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP
Packit 6c4009
	  if (r2 != NULL)
Packit 6c4009
	    for (; r2 <= end2; ++r2)
Packit 6c4009
	      if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
Packit 6c4009
		{
Packit 6c4009
		  ElfW(Half) ndx
Packit 6c4009
		    = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
Packit 6c4009
		  elf_machine_rel (map, r2,
Packit 6c4009
				   &symtab[ELFW(R_SYM) (r2->r_info)],
Packit 6c4009
				   &map->l_versions[ndx],
Packit 6c4009
				   (void *) (l_addr + r2->r_offset),
Packit 6c4009
				   skip_ifunc);
Packit 6c4009
		}
Packit 6c4009
#endif
Packit 6c4009
	}
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  for (; r < end; ++r)
Packit 6c4009
# ifdef ELF_MACHINE_IRELATIVE
Packit 6c4009
	    if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
Packit 6c4009
	      {
Packit 6c4009
		if (r2 == NULL)
Packit 6c4009
		  r2 = r;
Packit 6c4009
		end2 = r;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
# endif
Packit 6c4009
	      elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
Packit 6c4009
			       (void *) (l_addr + r->r_offset), skip_ifunc);
Packit 6c4009
Packit 6c4009
# ifdef ELF_MACHINE_IRELATIVE
Packit 6c4009
	  if (r2 != NULL)
Packit 6c4009
	    for (; r2 <= end2; ++r2)
Packit 6c4009
	      if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
Packit 6c4009
		elf_machine_rel (map, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
Packit 6c4009
				 NULL, (void *) (l_addr + r2->r_offset),
Packit 6c4009
				 skip_ifunc);
Packit 6c4009
# endif
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#undef elf_dynamic_do_Rel
Packit 6c4009
#undef Rel
Packit 6c4009
#undef elf_machine_rel
Packit 6c4009
#undef elf_machine_rel_relative
Packit 6c4009
#undef DO_ELF_MACHINE_REL_RELATIVE
Packit 6c4009
#undef DO_RELA