Blame sysdeps/nios2/dl-machine.h

Packit Service 82fcde
/* Machine-dependent ELF dynamic relocation inline functions.  Nios II version.
Packit Service 82fcde
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library.  If not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#ifndef dl_machine_h
Packit Service 82fcde
#define dl_machine_h
Packit Service 82fcde
Packit Service 82fcde
#define ELF_MACHINE_NAME "nios2"
Packit Service 82fcde
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <link.h>
Packit Service 82fcde
#include <dl-tls.h>
Packit Service 82fcde
Packit Service 82fcde
/* Return nonzero iff ELF header is compatible with the running host.  */
Packit Service 82fcde
static inline int
Packit Service 82fcde
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
Packit Service 82fcde
{
Packit Service 82fcde
  return ehdr->e_machine == EM_ALTERA_NIOS2;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
Packit Service 82fcde
   first element of the GOT.  */
Packit Service 82fcde
static inline Elf32_Addr
Packit Service 82fcde
elf_machine_dynamic (void)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *dynamic;
Packit Service 82fcde
  int tmp;
Packit Service 82fcde
  asm ("nextpc\t%0\n\t"
Packit Service 82fcde
       "1: movhi\t%1, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b)\n\t"
Packit Service 82fcde
       "addi\t%1, %1, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)\n\t"
Packit Service 82fcde
       "add\t%0, %0, %1\n"
Packit Service 82fcde
       : "=r" (dynamic), "=r" (tmp));
Packit Service 82fcde
  return *dynamic;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Return the run-time load address of the shared object.  */
Packit Service 82fcde
static inline Elf32_Addr
Packit Service 82fcde
elf_machine_load_address (void)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr result;
Packit Service 82fcde
  int tmp;
Packit Service 82fcde
  asm ("nextpc\t%0\n\t"
Packit Service 82fcde
       "1: movhi\t%1, %%hiadj(1b)\n\t"
Packit Service 82fcde
       "addi\t%1, %1, %%lo(1b)\n\t"
Packit Service 82fcde
       "sub\t%0, %0, %1\n"
Packit Service 82fcde
       : "=r" (result), "=r" (tmp));
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Set up the loaded object described by L so its unrelocated PLT
Packit Service 82fcde
   entries will jump to the on-demand fixup code in dl-runtime.c.  */
Packit Service 82fcde
Packit Service 82fcde
static inline int __attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
Packit Service 82fcde
{
Packit Service 82fcde
  extern void _dl_runtime_resolve (Elf32_Word);
Packit Service 82fcde
Packit Service 82fcde
  if (l->l_info[DT_JMPREL] && lazy)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The GOT entries for functions in the PLT have not yet been filled
Packit Service 82fcde
         in.  Their initial contents will arrange when called to load r15 with
Packit Service 82fcde
         an offset into the .got section, load r14 with
Packit Service 82fcde
	 _GLOBAL_OFFSET_TABLE_[1], and then jump to _GLOBAL_OFFSET_TABLE[2].
Packit Service 82fcde
      */
Packit Service 82fcde
      Elf32_Addr *got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
Packit Service 82fcde
      got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
Packit Service 82fcde
Packit Service 82fcde
      /* This function will get called to fix up the GOT entry indicated by
Packit Service 82fcde
	 the offset on the stack, and then jump to the resolved address.  */
Packit Service 82fcde
      got[2] = (Elf32_Addr) &_dl_runtime_resolve;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return lazy;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Initial entry point code for the dynamic linker.
Packit Service 82fcde
   The C function `_dl_start' is the real entry point;
Packit Service 82fcde
   its return value is the user program's entry point.  */
Packit Service 82fcde
Packit Service 82fcde
#define RTLD_START asm ("\
Packit Service 82fcde
.text\n\
Packit Service 82fcde
.globl _start\n\
Packit Service 82fcde
.type _start, %function\n\
Packit Service 82fcde
_start:\n\
Packit Service 82fcde
        /* At start time, all the args are on the stack.  */\n\
Packit Service 82fcde
        mov r4, sp\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Start the calculation of the GOT pointer.  */\n\
Packit Service 82fcde
        nextpc r22\n\
Packit Service 82fcde
1:      movhi r8, %hiadj(_gp_got - 1b)\n\
Packit Service 82fcde
        addi r8, r8, %lo(_gp_got - 1b)\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Figure out where _dl_start will need to return to.  */\n\
Packit Service 82fcde
        movhi ra, %hiadj(2f - 1b)\n\
Packit Service 82fcde
        addi ra, ra, %lo(2f - 1b)\n\
Packit Service 82fcde
        add ra, ra, r22\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Finish the calculation of the GOT pointer.  */\n\
Packit Service 82fcde
        add r22, r22, r8\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        br _dl_start\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Save the returned user entry point.  */\n\
Packit Service 82fcde
2:      mov r16, r2\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Initialize gp.  */\n\
Packit Service 82fcde
        ldw r4, %got(_rtld_local)(r22)\n\
Packit Service 82fcde
        ldw r4, 0(r4)\n\
Packit Service 82fcde
        ldw r8, %call(_dl_nios2_get_gp_value)(r22)\n\
Packit Service 82fcde
        callr r8\n\
Packit Service 82fcde
        mov gp, r2\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Find the number of arguments to skip.  */\n\
Packit Service 82fcde
        ldw r8, %got(_dl_skip_args)(r22)\n\
Packit Service 82fcde
        ldw r8, 0(r8)\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Find the main_map from the GOT.  */\n\
Packit Service 82fcde
        ldw r4, %got(_rtld_local)(r22)\n\
Packit Service 82fcde
        ldw r4, 0(r4)\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Find argc.  */\n\
Packit Service 82fcde
        ldw r5, 0(sp)\n\
Packit Service 82fcde
        sub r5, r5, r8\n\
Packit Service 82fcde
        stw r5, 0(sp)\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Find the first unskipped argument.  */\n\
Packit Service 82fcde
        slli r8, r8, 2\n\
Packit Service 82fcde
        addi r6, sp, 4\n\
Packit Service 82fcde
        add r9, r6, r8\n\
Packit Service 82fcde
        mov r10, r6\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Shuffle argv down.  */\n\
Packit Service 82fcde
3:      ldw r11, 0(r9)\n\
Packit Service 82fcde
        stw r11, 0(r10)\n\
Packit Service 82fcde
        addi r9, r9, 4\n\
Packit Service 82fcde
        addi r10, r10, 4\n\
Packit Service 82fcde
        bne r11, zero, 3b\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Shuffle envp down.  */\n\
Packit Service 82fcde
        mov r7, r10\n\
Packit Service 82fcde
4:      ldw r11, 0(r9)\n\
Packit Service 82fcde
        stw r11, 0(r10)\n\
Packit Service 82fcde
        addi r9, r9, 4\n\
Packit Service 82fcde
        addi r10, r10, 4\n\
Packit Service 82fcde
        bne r11, zero, 4b\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Shuffle auxv down.  */\n\
Packit Service 82fcde
5:      ldw r11, 4(r9)\n\
Packit Service 82fcde
        stw r11, 4(r10)\n\
Packit Service 82fcde
        ldw r11, 0(r9)\n\
Packit Service 82fcde
        stw r11, 0(r10)\n\
Packit Service 82fcde
        addi r9, r9, 8\n\
Packit Service 82fcde
        addi r10, r10, 8\n\
Packit Service 82fcde
        bne r11, zero, 5b\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Update _dl_argv.  */\n\
Packit Service 82fcde
        ldw r2, %got(_dl_argv)(r22)\n\
Packit Service 82fcde
        stw r6, 0(r2)\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Call _dl_init through the PLT.  */\n\
Packit Service 82fcde
        ldw r8, %call(_dl_init)(r22)\n\
Packit Service 82fcde
        callr r8\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Find the finalization function.  */\n\
Packit Service 82fcde
        ldw r4, %got(_dl_fini)(r22)\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
        /* Jump to the user's entry point.  */\n\
Packit Service 82fcde
        jmp r16\n\
Packit Service 82fcde
");
Packit Service 82fcde
Packit Service 82fcde
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
Packit Service 82fcde
   PLT entries should not be allowed to define the value.
Packit Service 82fcde
   ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
Packit Service 82fcde
   of the main executable's symbols, as for a COPY reloc.  */
Packit Service 82fcde
#define elf_machine_type_class(type)				\
Packit Service 82fcde
  ((((type) == R_NIOS2_JUMP_SLOT				\
Packit Service 82fcde
     || (type) == R_NIOS2_TLS_DTPMOD				\
Packit Service 82fcde
     || (type) == R_NIOS2_TLS_DTPREL				\
Packit Service 82fcde
     || (type) == R_NIOS2_TLS_TPREL) * ELF_RTYPE_CLASS_PLT)	\
Packit Service 82fcde
   | (((type) == R_NIOS2_COPY) * ELF_RTYPE_CLASS_COPY)		\
Packit Service 82fcde
   | (((type) == R_NIOS2_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
Packit Service 82fcde
Packit Service 82fcde
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
Packit Service 82fcde
#define ELF_MACHINE_JMP_SLOT  R_NIOS2_JUMP_SLOT
Packit Service 82fcde
Packit Service 82fcde
/* The Nios II never uses Elf32_Rel relocations.  */
Packit Service 82fcde
#define ELF_MACHINE_NO_REL 1
Packit Service 82fcde
#define ELF_MACHINE_NO_RELA 0
Packit Service 82fcde
Packit Service 82fcde
/* Fixup a PLT entry to bounce directly to the function at VALUE.  */
Packit Service 82fcde
Packit Service 82fcde
static inline Elf32_Addr
Packit Service 82fcde
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
Packit Service 82fcde
		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
Packit Service 82fcde
		       const Elf32_Rela *reloc,
Packit Service 82fcde
		       Elf32_Addr *reloc_addr, Elf32_Addr value)
Packit Service 82fcde
{
Packit Service 82fcde
  return *reloc_addr = value;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return the final value of a plt relocation.  */
Packit Service 82fcde
static inline Elf32_Addr
Packit Service 82fcde
elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
Packit Service 82fcde
                       Elf32_Addr value)
Packit Service 82fcde
{
Packit Service 82fcde
  return value;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Names of the architecture-specific auditing callback functions.  */
Packit Service 82fcde
#define ARCH_LA_PLTENTER nios2_gnu_pltenter
Packit Service 82fcde
#define ARCH_LA_PLTEXIT nios2_gnu_pltexit
Packit Service 82fcde
Packit Service 82fcde
#endif /* dl_machine_h */
Packit Service 82fcde
Packit Service 82fcde
#ifdef RESOLVE_MAP
Packit Service 82fcde
Packit Service 82fcde
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
Packit Service 82fcde
   LOADADDR is the load address of the object; INFO is an array indexed
Packit Service 82fcde
   by DT_* of the .dynamic section info.  */
Packit Service 82fcde
Packit Service 82fcde
auto inline void __attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
Packit Service 82fcde
                  const ElfW(Sym) *sym, const struct r_found_version *version,
Packit Service 82fcde
                  void *const reloc_addr_arg, int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit Service 82fcde
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_unlikely (r_type == R_NIOS2_RELATIVE))
Packit Service 82fcde
    *reloc_addr = map->l_addr + reloc->r_addend;
Packit Service 82fcde
  else if (__glibc_unlikely (r_type == R_NIOS2_NONE))
Packit Service 82fcde
    return;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      const Elf32_Sym *const refsym = sym;
Packit Service 82fcde
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit Service 82fcde
      Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit Service 82fcde
Packit Service 82fcde
      switch (r_type)
Packit Service 82fcde
	{
Packit Service 82fcde
        case R_NIOS2_COPY:
Packit Service 82fcde
          if (sym == NULL)
Packit Service 82fcde
            /* This can happen in trace mode if an object could not be
Packit Service 82fcde
               found.  */
Packit Service 82fcde
            break;
Packit Service 82fcde
          if (sym->st_size > refsym->st_size
Packit Service 82fcde
              || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
Packit Service 82fcde
            {
Packit Service 82fcde
              const char *strtab;
Packit Service 82fcde
Packit Service 82fcde
              strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
Packit Service 82fcde
              _dl_error_printf ("\
Packit Service 82fcde
%s: Symbol `%s' has different size in shared object, consider re-linking\n",
Packit Service 82fcde
				rtld_progname ?: "<program name unknown>",
Packit Service 82fcde
				strtab + refsym->st_name);
Packit Service 82fcde
            }
Packit Service 82fcde
          memcpy (reloc_addr_arg, (void *) value,
Packit Service 82fcde
                  MIN (sym->st_size, refsym->st_size));
Packit Service 82fcde
          break;
Packit Service 82fcde
	case R_NIOS2_GLOB_DAT:
Packit Service 82fcde
	case R_NIOS2_JUMP_SLOT:
Packit Service 82fcde
# ifdef RTLD_BOOTSTRAP
Packit Service 82fcde
          /* Fix weak undefined references.  */
Packit Service 82fcde
          if (sym != NULL && sym->st_value == 0)
Packit Service 82fcde
            *reloc_addr = 0;
Packit Service 82fcde
          else
Packit Service 82fcde
# endif
Packit Service 82fcde
            *reloc_addr = value;
Packit Service 82fcde
          break;
Packit Service 82fcde
#ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
        case R_NIOS2_TLS_DTPMOD:
Packit Service 82fcde
          /* Get the information from the link map returned by the
Packit Service 82fcde
             resolv function.  */
Packit Service 82fcde
          if (sym_map != NULL)
Packit Service 82fcde
            *reloc_addr = sym_map->l_tls_modid;
Packit Service 82fcde
          break;
Packit Service 82fcde
Packit Service 82fcde
        case R_NIOS2_TLS_DTPREL:
Packit Service 82fcde
          *reloc_addr = reloc->r_addend + TLS_DTPREL_VALUE(sym);
Packit Service 82fcde
          break;
Packit Service 82fcde
Packit Service 82fcde
        case R_NIOS2_TLS_TPREL:
Packit Service 82fcde
          if (sym != NULL)
Packit Service 82fcde
            {
Packit Service 82fcde
              CHECK_STATIC_TLS (map, sym_map);
Packit Service 82fcde
              *reloc_addr = reloc->r_addend + TLS_TPREL_VALUE(sym_map, sym);
Packit Service 82fcde
            }
Packit Service 82fcde
          break;
Packit Service 82fcde
#endif
Packit Service 82fcde
        case R_NIOS2_BFD_RELOC_32:
Packit Service 82fcde
          *reloc_addr = value + reloc->r_addend;
Packit Service 82fcde
          break;
Packit Service 82fcde
Packit Service 82fcde
	default:
Packit Service 82fcde
          _dl_reloc_bad_type (map, r_type, 0);
Packit Service 82fcde
          break;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
auto inline void __attribute__((always_inline))
Packit Service 82fcde
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
Packit Service 82fcde
			   void *const reloc_addr_arg)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit Service 82fcde
  *reloc_addr = l_addr + reloc->r_addend;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
auto inline void __attribute__((always_inline))
Packit Service 82fcde
elf_machine_lazy_rel (struct link_map *map,
Packit Service 82fcde
		      ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
Packit Service 82fcde
		      int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
Packit Service 82fcde
  if (ELF32_R_TYPE (reloc->r_info) == R_NIOS2_JUMP_SLOT)
Packit Service 82fcde
    *reloc_addr += l_addr;
Packit Service 82fcde
  else
Packit Service 82fcde
    _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#endif /* RESOLVE_MAP */