Blame sysdeps/riscv/dl-machine.h

Packit Service 82fcde
/* Machine-dependent ELF dynamic relocation inline functions.  RISC-V version.
Packit Service 82fcde
   Copyright (C) 2011-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 "RISC-V"
Packit Service 82fcde
Packit Service 82fcde
#include <entry.h>
Packit Service 82fcde
#include <elf/elf.h>
Packit Service 82fcde
#include <sys/asm.h>
Packit Service 82fcde
#include <dl-tls.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef _RTLD_PROLOGUE
Packit Service 82fcde
# define _RTLD_PROLOGUE(entry)						\
Packit Service 82fcde
	".globl\t" __STRING (entry) "\n\t"				\
Packit Service 82fcde
	".type\t" __STRING (entry) ", @function\n"			\
Packit Service 82fcde
	__STRING (entry) ":\n\t"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef _RTLD_EPILOGUE
Packit Service 82fcde
# define _RTLD_EPILOGUE(entry)						\
Packit Service 82fcde
	".size\t" __STRING (entry) ", . - " __STRING (entry) "\n\t"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#define ELF_MACHINE_JMP_SLOT R_RISCV_JUMP_SLOT
Packit Service 82fcde
Packit Service 82fcde
#define elf_machine_type_class(type)				\
Packit Service 82fcde
  ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT	\
Packit Service 82fcde
     || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPREL32)	\
Packit Service 82fcde
     || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPMOD32)	\
Packit Service 82fcde
     || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_TPREL32)	\
Packit Service 82fcde
     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPREL64)	\
Packit Service 82fcde
     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPMOD64)	\
Packit Service 82fcde
     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64)))	\
Packit Service 82fcde
   | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
Packit Service 82fcde
Packit Service 82fcde
#define ELF_MACHINE_NO_REL 1
Packit Service 82fcde
#define ELF_MACHINE_NO_RELA 0
Packit Service 82fcde
Packit Service 82fcde
/* Return nonzero iff ELF header is compatible with the running host.  */
Packit Service 82fcde
static inline int __attribute_used__
Packit Service 82fcde
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We can only run RISC-V binaries.  */
Packit Service 82fcde
  if (ehdr->e_machine != EM_RISCV)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Ensure the library's floating-point ABI matches that of the running
Packit Service 82fcde
     system.  For now we don't support mixing XLEN, so there's no need (or way)
Packit Service 82fcde
     to check it matches.  */
Packit Service 82fcde
#ifdef __riscv_float_abi_double
Packit Service 82fcde
  if ((ehdr->e_flags & EF_RISCV_FLOAT_ABI) != EF_RISCV_FLOAT_ABI_DOUBLE)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
#else
Packit Service 82fcde
  if ((ehdr->e_flags & EF_RISCV_FLOAT_ABI) != EF_RISCV_FLOAT_ABI_SOFT)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  return 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return the link-time address of _DYNAMIC.  */
Packit Service 82fcde
static inline ElfW(Addr)
Packit Service 82fcde
elf_machine_dynamic (void)
Packit Service 82fcde
{
Packit Service 82fcde
  extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__ ((visibility ("hidden")));
Packit Service 82fcde
  return _GLOBAL_OFFSET_TABLE_;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#define STRINGXP(X) __STRING (X)
Packit Service 82fcde
#define STRINGXV(X) STRINGV_ (X)
Packit Service 82fcde
#define STRINGV_(...) # __VA_ARGS__
Packit Service 82fcde
Packit Service 82fcde
/* Return the run-time load address of the shared object.  */
Packit Service 82fcde
static inline ElfW(Addr)
Packit Service 82fcde
elf_machine_load_address (void)
Packit Service 82fcde
{
Packit Service 82fcde
  ElfW(Addr) load_addr;
Packit Service 82fcde
  asm ("lla %0, _DYNAMIC" : "=r" (load_addr));
Packit Service 82fcde
  return load_addr - elf_machine_dynamic ();
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
	" _RTLD_PROLOGUE (ENTRY_POINT) "\
Packit Service 82fcde
	mv a0, sp\n\
Packit Service 82fcde
	jal _dl_start\n\
Packit Service 82fcde
	# Stash user entry point in s0.\n\
Packit Service 82fcde
	mv s0, a0\n\
Packit Service 82fcde
	# See if we were run as a command with the executable file\n\
Packit Service 82fcde
	# name as an extra leading argument.\n\
Packit Service 82fcde
	lw a0, _dl_skip_args\n\
Packit Service 82fcde
	# Load the original argument count.\n\
Packit Service 82fcde
	" STRINGXP (REG_L) " a1, 0(sp)\n\
Packit Service 82fcde
	# Subtract _dl_skip_args from it.\n\
Packit Service 82fcde
	sub a1, a1, a0\n\
Packit Service 82fcde
	# Adjust the stack pointer to skip _dl_skip_args words.\n\
Packit Service 82fcde
	sll a0, a0, " STRINGXP (PTRLOG) "\n\
Packit Service 82fcde
	add sp, sp, a0\n\
Packit Service 82fcde
	# Save back the modified argument count.\n\
Packit Service 82fcde
	" STRINGXP (REG_S) " a1, 0(sp)\n\
Packit Service 82fcde
	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
Packit Service 82fcde
	" STRINGXP (REG_L) " a0, _rtld_local\n\
Packit Service 82fcde
	add a2, sp, " STRINGXP (SZREG) "\n\
Packit Service 82fcde
	sll a3, a1, " STRINGXP (PTRLOG) "\n\
Packit Service 82fcde
	add a3, a3, a2\n\
Packit Service 82fcde
	add a3, a3, " STRINGXP (SZREG) "\n\
Packit Service 82fcde
	# Call the function to run the initializers.\n\
Packit Service 82fcde
	jal _dl_init\n\
Packit Service 82fcde
	# Pass our finalizer function to _start.\n\
Packit Service 82fcde
	lla a0, _dl_fini\n\
Packit Service 82fcde
	# Jump to the user entry point.\n\
Packit Service 82fcde
	jr s0\n\
Packit Service 82fcde
	" _RTLD_EPILOGUE (ENTRY_POINT) "\
Packit Service 82fcde
	.previous" \
Packit Service 82fcde
);
Packit Service 82fcde
Packit Service 82fcde
/* Names of the architecture-specific auditing callback functions.  */
Packit Service 82fcde
#define ARCH_LA_PLTENTER riscv_gnu_pltenter
Packit Service 82fcde
#define ARCH_LA_PLTEXIT riscv_gnu_pltexit
Packit Service 82fcde
Packit Service 82fcde
/* Bias .got.plt entry by the offset requested by the PLT header.  */
Packit Service 82fcde
#define elf_machine_plt_value(map, reloc, value) (value)
Packit Service 82fcde
Packit Service 82fcde
static inline ElfW(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 ElfW(Rela) *reloc,
Packit Service 82fcde
		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
Packit Service 82fcde
{
Packit Service 82fcde
  return *reloc_addr = value;
Packit Service 82fcde
}
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 a relocation described by R_INFO at the location pointed to
Packit Service 82fcde
   by RELOC_ADDR.  SYM is the relocation symbol specified by R_INFO and
Packit Service 82fcde
   MAP is the object containing the reloc.  */
Packit Service 82fcde
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__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, int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  ElfW(Addr) r_info = reloc->r_info;
Packit Service 82fcde
  const unsigned long int r_type = ELFW (R_TYPE) (r_info);
Packit Service 82fcde
  ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
Packit Service 82fcde
  const ElfW(Sym) *const __attribute__ ((unused)) refsym = sym;
Packit Service 82fcde
  struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit Service 82fcde
  ElfW(Addr) value = 0;
Packit Service 82fcde
  if (sym_map != NULL)
Packit Service 82fcde
    value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
Packit Service 82fcde
Packit Service 82fcde
  switch (r_type)
Packit Service 82fcde
    {
Packit Service 82fcde
#ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
    case __WORDSIZE == 64 ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32:
Packit Service 82fcde
      if (sym_map)
Packit Service 82fcde
	*addr_field = sym_map->l_tls_modid;
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    case __WORDSIZE == 64 ? R_RISCV_TLS_DTPREL64 : R_RISCV_TLS_DTPREL32:
Packit Service 82fcde
      if (sym != NULL)
Packit Service 82fcde
	*addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    case __WORDSIZE == 64 ? R_RISCV_TLS_TPREL64 : R_RISCV_TLS_TPREL32:
Packit Service 82fcde
      if (sym != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  CHECK_STATIC_TLS (map, sym_map);
Packit Service 82fcde
	  *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
Packit Service 82fcde
	}
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    case R_RISCV_COPY:
Packit Service 82fcde
      {
Packit Service 82fcde
	if (__glibc_unlikely (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
Packit Service 82fcde
	/* Handle TLS copy relocations.  */
Packit Service 82fcde
	if (__glibc_unlikely (ELFW (ST_TYPE) (sym->st_info) == STT_TLS))
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* There's nothing to do if the symbol is in .tbss.  */
Packit Service 82fcde
	    if (__glibc_likely (sym->st_value >= sym_map->l_tls_initimage_size))
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    value += (ElfW(Addr)) sym_map->l_tls_initimage - sym_map->l_addr;
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
	size_t size = sym->st_size;
Packit Service 82fcde
	if (__glibc_unlikely (sym->st_size != refsym->st_size))
Packit Service 82fcde
	  {
Packit Service 82fcde
	    const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
Packit Service 82fcde
	    if (sym->st_size > refsym->st_size)
Packit Service 82fcde
	      size = refsym->st_size;
Packit Service 82fcde
	    if (sym->st_size > refsym->st_size || GLRO(dl_verbose))
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
Packit Service 82fcde
	memcpy (reloc_addr, (void *)value, size);
Packit Service 82fcde
	break;
Packit Service 82fcde
      }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
Packit Service 82fcde
    case R_RISCV_RELATIVE:
Packit Service 82fcde
      {
Packit Service 82fcde
# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
Packit Service 82fcde
	/* This is defined in rtld.c, but nowhere in the static libc.a;
Packit Service 82fcde
	   make the reference weak so static programs can still link.
Packit Service 82fcde
	   This declaration cannot be done when compiling rtld.c
Packit Service 82fcde
	   (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
Packit Service 82fcde
	   common defn for _dl_rtld_map, which is incompatible with a
Packit Service 82fcde
	   weak decl in the same file.  */
Packit Service 82fcde
#  ifndef SHARED
Packit Service 82fcde
	weak_extern (GL(dl_rtld_map));
Packit Service 82fcde
#  endif
Packit Service 82fcde
	if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
Packit Service 82fcde
# endif
Packit Service 82fcde
	  *addr_field = map->l_addr + reloc->r_addend;
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
    case R_RISCV_JUMP_SLOT:
Packit Service 82fcde
    case __WORDSIZE == 64 ? R_RISCV_64 : R_RISCV_32:
Packit Service 82fcde
      *addr_field = value;
Packit Service 82fcde
      break;
Packit Service 82fcde
Packit Service 82fcde
    case R_RISCV_NONE:
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
auto inline void
Packit Service 82fcde
__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)
Packit Service 82fcde
{
Packit Service 82fcde
  *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_lazy_rel (struct link_map *map, ElfW(Addr) l_addr,
Packit Service 82fcde
		      const ElfW(Rela) *reloc, int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
Packit Service 82fcde
  const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
Packit Service 82fcde
Packit Service 82fcde
  /* Check for unexpected PLT reloc type.  */
Packit Service 82fcde
  if (__glibc_likely (r_type == R_RISCV_JUMP_SLOT))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__glibc_unlikely (map->l_mach.plt == 0))
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (l_addr)
Packit Service 82fcde
	    *reloc_addr += l_addr;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	*reloc_addr = map->l_mach.plt;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    _dl_reloc_bad_type (map, r_type, 1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Set up the loaded object described by L so its stub function
Packit Service 82fcde
   will jump to the on-demand fixup code __dl_runtime_resolve.  */
Packit Service 82fcde
Packit Service 82fcde
auto inline int
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
Packit Service 82fcde
{
Packit Service 82fcde
#ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
  /* If using PLTs, fill in the first two entries of .got.plt.  */
Packit Service 82fcde
  if (l->l_info[DT_JMPREL])
Packit Service 82fcde
    {
Packit Service 82fcde
      extern void _dl_runtime_resolve (void) __attribute__ ((visibility ("hidden")));
Packit Service 82fcde
      ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
Packit Service 82fcde
      /* If a library is prelinked but we have to relocate anyway,
Packit Service 82fcde
	 we have to be able to undo the prelinking of .got.plt.
Packit Service 82fcde
	 The prelinker saved the address of .plt for us here.  */
Packit Service 82fcde
      if (gotplt[1])
Packit Service 82fcde
	l->l_mach.plt = gotplt[1] + l->l_addr;
Packit Service 82fcde
      gotplt[0] = (ElfW(Addr)) &_dl_runtime_resolve;
Packit Service 82fcde
      gotplt[1] = (ElfW(Addr)) l;
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  return lazy;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#endif /* RESOLVE_MAP */