Blame sysdeps/microblaze/dl-machine.h

Packit 6c4009
/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
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 License as
Packit 6c4009
   published by the Free Software Foundation; either version 2.1 of the
Packit 6c4009
   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
#ifndef dl_machine_h
Packit 6c4009
#define dl_machine_h
Packit 6c4009
Packit 6c4009
#define ELF_MACHINE_NAME "microblaze"
Packit 6c4009
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
Packit 6c4009
/* Return nonzero iff ELF header is compatible with the running host.  */
Packit 6c4009
static inline int
Packit 6c4009
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  return (ehdr->e_machine == EM_MICROBLAZE);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
Packit 6c4009
   first element of the GOT.  This must be inlined in a function which
Packit 6c4009
   uses global data.  */
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
  /* This produces a GOTOFF reloc that resolves to zero at link time, so in
Packit 6c4009
     fact just loads from the GOT register directly.  By doing it without
Packit 6c4009
     an asm we can let the compiler choose any register.  */
Packit 6c4009
Packit 6c4009
  Elf32_Addr got_entry_0;
Packit 6c4009
  __asm__ __volatile__(
Packit 6c4009
    "lwi %0,r20,0"
Packit 6c4009
    :"=r"(got_entry_0)
Packit 6c4009
    );
Packit 6c4009
  return got_entry_0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the run-time load address of the shared object.  */
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  /* Compute the difference between the runtime address of _DYNAMIC as seen
Packit 6c4009
     by a GOTOFF reference, and the link-time address found in the special
Packit 6c4009
     unrelocated first GOT entry.  */
Packit 6c4009
Packit 6c4009
  Elf32_Addr dyn;
Packit 6c4009
  __asm__ __volatile__ (
Packit 6c4009
    "addik %0,r20,_DYNAMIC@GOTOFF"
Packit 6c4009
    : "=r"(dyn)
Packit 6c4009
    );
Packit 6c4009
  return dyn - elf_machine_dynamic ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Set up the loaded object described by L so its unrelocated PLT
Packit 6c4009
   entries will jump to the on-demand fixup code in dl-runtime.c.  */
Packit 6c4009
Packit 6c4009
static inline int __attribute__ ((always_inline))
Packit 6c4009
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
Packit 6c4009
{
Packit 6c4009
  extern void _dl_runtime_resolve (Elf32_Word);
Packit 6c4009
  extern void _dl_runtime_profile (Elf32_Word);
Packit 6c4009
Packit 6c4009
  return lazy;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* The PLT uses Elf32_Rela relocs.  */
Packit 6c4009
#define elf_machine_relplt elf_machine_rela
Packit 6c4009
Packit 6c4009
/* Mask identifying addresses reserved for the user program,
Packit 6c4009
   where the dynamic linker should not map anything.  */
Packit 6c4009
#define ELF_MACHINE_USER_ADDRESS_MASK	0x80000000UL
Packit 6c4009
Packit 6c4009
/* Initial entry point code for the dynamic linker.
Packit 6c4009
   The C function `_dl_start' is the real entry point;
Packit 6c4009
   its return value is the user program's entry point.  */
Packit 6c4009
Packit 6c4009
#define RTLD_START asm ("\
Packit 6c4009
	.text\n\
Packit 6c4009
	.globl _start\n\
Packit 6c4009
	.type _start,@function\n\
Packit 6c4009
_start:\n\
Packit 6c4009
	addk  r5,r0,r1\n\
Packit 6c4009
	addk  r3,r0,r0\n\
Packit 6c4009
1:\n\
Packit 6c4009
	addik r5,r5,4\n\
Packit 6c4009
	lw    r4,r5,r0\n\
Packit 6c4009
	bneid r4,1b\n\
Packit 6c4009
	addik r3,r3,1\n\
Packit 6c4009
	addik r3,r3,-1\n\
Packit 6c4009
	addk  r5,r0,r1\n\
Packit 6c4009
	sw    r3,r5,r0\n\
Packit 6c4009
	addik r1,r1,-24\n\
Packit 6c4009
	sw    r15,r1,r0\n\
Packit 6c4009
	brlid r15,_dl_start\n\
Packit 6c4009
	nop\n\
Packit 6c4009
	/* FALLTHRU.  */\n\
Packit 6c4009
\n\
Packit 6c4009
	.globl _dl_start_user\n\
Packit 6c4009
	.type _dl_start_user,@function\n\
Packit 6c4009
_dl_start_user:\n\
Packit 6c4009
	mfs   r20,rpc\n\
Packit 6c4009
	addik r20,r20,_GLOBAL_OFFSET_TABLE_+8\n\
Packit 6c4009
	lwi   r4,r20,_dl_skip_args@GOTOFF\n\
Packit 6c4009
	lwi   r5,r1,24\n\
Packit 6c4009
	rsubk r5,r4,r5\n\
Packit 6c4009
	addk  r4,r4,r4\n\
Packit 6c4009
	addk  r4,r4,r4\n\
Packit 6c4009
	addk  r1,r1,r4\n\
Packit 6c4009
	swi   r5,r1,24\n\
Packit 6c4009
	swi   r3,r1,20\n\
Packit 6c4009
	addk  r6,r5,r0\n\
Packit 6c4009
	addk  r5,r5,r5\n\
Packit 6c4009
	addk  r5,r5,r5\n\
Packit 6c4009
	addik r7,r1,28\n\
Packit 6c4009
	addk  r8,r7,r5\n\
Packit 6c4009
	addik r8,r8,4\n\
Packit 6c4009
	lwi   r5,r20,_rtld_local@GOTOFF\n\
Packit 6c4009
	brlid r15,_dl_init\n\
Packit 6c4009
	nop\n\
Packit 6c4009
	lwi   r5,r1,24\n\
Packit 6c4009
	lwi   r3,r1,20\n\
Packit 6c4009
	addk  r4,r5,r5\n\
Packit 6c4009
	addk  r4,r4,r4\n\
Packit 6c4009
	addik r6,r1,28\n\
Packit 6c4009
	addk  r7,r6,r4\n\
Packit 6c4009
	addik r7,r7,4\n\
Packit 6c4009
	addik r15,r20,_dl_fini@GOTOFF\n\
Packit 6c4009
	addik r15,r15,-8\n\
Packit 6c4009
	brad  r3\n\
Packit 6c4009
	addik r1,r1,24\n\
Packit 6c4009
	nop\n\
Packit 6c4009
	.size _dl_start_user, . - _dl_start_user\n\
Packit 6c4009
	.previous");
Packit 6c4009
Packit 6c4009
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
Packit 6c4009
   TLS variable, so undefined references should not be allowed to
Packit 6c4009
   define the value.
Packit 6c4009
   ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
Packit 6c4009
   of the main executable's symbols, as for a COPY reloc.  */
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
# define elf_machine_type_class(type) \
Packit 6c4009
  (((type) == R_MICROBLAZE_JUMP_SLOT || \
Packit 6c4009
    (type) == R_MICROBLAZE_TLSDTPREL32 || \
Packit 6c4009
    (type) == R_MICROBLAZE_TLSDTPMOD32 || \
Packit 6c4009
    (type) == R_MICROBLAZE_TLSTPREL32) \
Packit 6c4009
    * ELF_RTYPE_CLASS_PLT \
Packit 6c4009
   | ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY)
Packit 6c4009
#else
Packit 6c4009
# define elf_machine_type_class(type) \
Packit 6c4009
  (((type) == R_MICROBLAZE_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT \
Packit 6c4009
   | ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
Packit 6c4009
#define ELF_MACHINE_JMP_SLOT	R_MICROBLAZE_JUMP_SLOT
Packit 6c4009
Packit 6c4009
/* The microblaze never uses Elf32_Rel relocations.  */
Packit 6c4009
#define ELF_MACHINE_NO_REL 1
Packit 6c4009
#define ELF_MACHINE_NO_RELA 0
Packit 6c4009
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
Packit 6c4009
		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
Packit 6c4009
		       const Elf32_Rela *reloc,
Packit 6c4009
		       Elf32_Addr *reloc_addr, Elf32_Addr value)
Packit 6c4009
{
Packit 6c4009
  return *reloc_addr = value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the final value of a plt relocation. Ignore the addend.  */
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
Packit 6c4009
		       Elf32_Addr value)
Packit 6c4009
{
Packit 6c4009
  return value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* !dl_machine_h.  */
Packit 6c4009
Packit 6c4009
/* Names of the architecture-specific auditing callback functions.  */
Packit 6c4009
#define ARCH_LA_PLTENTER microblaze_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT microblaze_gnu_pltexit
Packit 6c4009
Packit 6c4009
#ifdef RESOLVE_MAP
Packit 6c4009
Packit 6c4009
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
Packit 6c4009
   MAP is the object containing the reloc.  */
Packit 6c4009
Packit 6c4009
/* Macro to put 32-bit relocation value into 2 words.  */
Packit 6c4009
#define PUT_REL_64(rel_addr,val) \
Packit 6c4009
  do { \
Packit 6c4009
    ((unsigned short *)(rel_addr))[1] = (val) >> 16; \
Packit 6c4009
    ((unsigned short *)(rel_addr))[3] = (val) & 0xffff; \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
auto inline void __attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
Packit 6c4009
		  const Elf32_Sym *sym, const struct r_found_version *version,
Packit 6c4009
		  void *const reloc_addr_arg, int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  const int r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (r_type == R_MICROBLAZE_64_PCREL, 0))
Packit 6c4009
    PUT_REL_64 (reloc_addr, map->l_addr + reloc->r_addend);
Packit 6c4009
  else if (r_type == R_MICROBLAZE_REL)
Packit 6c4009
    *reloc_addr = map->l_addr + reloc->r_addend;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      const Elf32_Sym *const refsym = sym;
Packit 6c4009
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
      Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit 6c4009
Packit 6c4009
      value += reloc->r_addend;
Packit 6c4009
      if (r_type == R_MICROBLAZE_GLOB_DAT ||
Packit 6c4009
          r_type == R_MICROBLAZE_JUMP_SLOT ||
Packit 6c4009
          r_type == R_MICROBLAZE_32)
Packit 6c4009
	{
Packit 6c4009
	  *reloc_addr = value;
Packit 6c4009
	}
Packit 6c4009
      else if (r_type == R_MICROBLAZE_COPY)
Packit 6c4009
	{
Packit 6c4009
	  if (sym != NULL && (sym->st_size > refsym->st_size
Packit 6c4009
	      || (sym->st_size < refsym->st_size && GLRO (dl_verbose))) )
Packit 6c4009
	    {
Packit 6c4009
	      const char *strtab;
Packit 6c4009
Packit 6c4009
	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
Packit 6c4009
	      _dl_error_printf ("\
Packit 6c4009
%s: Symbol `%s' has different size in shared object, consider re-linking\n",
Packit 6c4009
				RTLD_PROGNAME, strtab + refsym->st_name);
Packit 6c4009
	    }
Packit 6c4009
	  memcpy (reloc_addr_arg, (void *) value,
Packit 6c4009
		  MIN (sym->st_size, refsym->st_size));
Packit 6c4009
	}
Packit 6c4009
      else if (r_type == R_MICROBLAZE_NONE)
Packit 6c4009
	{
Packit 6c4009
	}
Packit 6c4009
#if !defined RTLD_BOOTSTRAP
Packit 6c4009
      else if (r_type == R_MICROBLAZE_TLSDTPMOD32)
Packit 6c4009
	{
Packit 6c4009
	  if (sym_map != NULL)
Packit 6c4009
	    *reloc_addr = sym_map->l_tls_modid;
Packit 6c4009
	}
Packit 6c4009
      else if (r_type == R_MICROBLAZE_TLSDTPREL32)
Packit 6c4009
	{
Packit 6c4009
	  if (sym != NULL)
Packit 6c4009
	    *reloc_addr = sym->st_value + reloc->r_addend;
Packit 6c4009
	}
Packit 6c4009
      else if (r_type == R_MICROBLAZE_TLSTPREL32)
Packit 6c4009
	{
Packit 6c4009
	  if (sym != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
	      *reloc_addr = sym->st_value + sym_map->l_tls_offset + reloc->r_addend;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  _dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
Packit 6c4009
			   void *const reloc_addr_arg)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  PUT_REL_64 (reloc_addr, l_addr + reloc->r_addend);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
elf_machine_lazy_rel (struct link_map *map,
Packit 6c4009
		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
Packit 6c4009
		      int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
Packit 6c4009
  if (ELF32_R_TYPE (reloc->r_info) == R_MICROBLAZE_JUMP_SLOT)
Packit 6c4009
    *reloc_addr += l_addr;
Packit 6c4009
  else
Packit 6c4009
    _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* RESOLVE_MAP.  */