Blame sysdeps/powerpc/powerpc64/dl-machine.h

Packit 6c4009
/* Machine-dependent ELF dynamic relocation inline functions.
Packit 6c4009
   PowerPC64 version.
Packit 6c4009
   Copyright 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 Library General Public License as
Packit 6c4009
   published by the Free Software Foundation; either version 2 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
   Library General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Library General Public
Packit 6c4009
   License along with the GNU C Library; see the file COPYING.LIB.  If
Packit 6c4009
   not, see <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 "powerpc64"
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <dl-tls.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <hwcapinfo.h>
Packit 6c4009
#include <cpu-features.c>
Packit 6c4009
Packit 6c4009
/* Translate a processor specific dynamic tag to the index
Packit 6c4009
   in l_info array.  */
Packit 6c4009
#define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
Packit 6c4009
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
/* A PowerPC64 function descriptor.  The .plt (procedure linkage
Packit 6c4009
   table) and .opd (official procedure descriptor) sections are
Packit 6c4009
   arrays of these.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr fd_func;
Packit 6c4009
  Elf64_Addr fd_toc;
Packit 6c4009
  Elf64_Addr fd_aux;
Packit 6c4009
} Elf64_FuncDesc;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define ELF_MULT_MACHINES_SUPPORTED
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 Elf64_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  /* Verify that the binary matches our ABI version.  */
Packit 6c4009
  if ((ehdr->e_flags & EF_PPC64_ABI) != 0)
Packit 6c4009
    {
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
      if ((ehdr->e_flags & EF_PPC64_ABI) != 1)
Packit 6c4009
        return 0;
Packit 6c4009
#else
Packit 6c4009
      if ((ehdr->e_flags & EF_PPC64_ABI) != 2)
Packit 6c4009
        return 0;
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return ehdr->e_machine == EM_PPC64;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return nonzero iff ELF header is compatible with the running host,
Packit 6c4009
   but not this loader.  */
Packit 6c4009
static inline int
Packit 6c4009
elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  return ehdr->e_machine == EM_PPC;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return nonzero iff ELF header is compatible with the running host,
Packit 6c4009
   but not this loader.  */
Packit 6c4009
static inline int
Packit 6c4009
elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return the run-time load address of the shared object, assuming it
Packit 6c4009
   was originally linked at zero.  */
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_load_address (void) __attribute__ ((const));
Packit 6c4009
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr ret;
Packit 6c4009
Packit 6c4009
  /* The first entry in .got (and thus the first entry in .toc) is the
Packit 6c4009
     link-time TOC_base, ie. r2.  So the difference between that and
Packit 6c4009
     the current r2 set by the kernel is how far the shared lib has
Packit 6c4009
     moved.  */
Packit 6c4009
  asm (	"	ld	%0,-32768(2)\n"
Packit 6c4009
	"	subf	%0,%0,2\n"
Packit 6c4009
	: "=r"	(ret));
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the link-time address of _DYNAMIC.  */
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr runtime_dynamic;
Packit 6c4009
  /* It's easier to get the run-time address.  */
Packit 6c4009
  asm (	"	addis	%0,2,_DYNAMIC@toc@ha\n"
Packit 6c4009
	"	addi	%0,%0,_DYNAMIC@toc@l\n"
Packit 6c4009
	: "=b"	(runtime_dynamic));
Packit 6c4009
  /* Then subtract off the load address offset.  */
Packit 6c4009
  return runtime_dynamic - elf_machine_load_address() ;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
Packit 6c4009
Packit 6c4009
/* The PLT uses Elf64_Rela relocs.  */
Packit 6c4009
#define elf_machine_relplt elf_machine_rela
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef HAVE_INLINED_SYSCALLS
Packit 6c4009
/* We do not need _dl_starting_up.  */
Packit 6c4009
# define DL_STARTING_UP_DEF
Packit 6c4009
#else
Packit 6c4009
# define DL_STARTING_UP_DEF \
Packit 6c4009
".LC__dl_starting_up:\n"  \
Packit 6c4009
"	.tc __GI__dl_starting_up[TC],__GI__dl_starting_up\n"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Initial entry point code for the dynamic linker.  The C function
Packit 6c4009
   `_dl_start' is the real entry point; its return value is the user
Packit 6c4009
   program's entry point.  */
Packit 6c4009
#define RTLD_START \
Packit 6c4009
  asm (".pushsection \".text\"\n"					\
Packit 6c4009
"	.align	2\n"							\
Packit 6c4009
"	" ENTRY_2(_start) "\n"						\
Packit 6c4009
BODY_PREFIX "_start:\n"							\
Packit 6c4009
"	" LOCALENTRY(_start) "\n"						\
Packit 6c4009
/* We start with the following on the stack, from top:			\
Packit 6c4009
   argc (4 bytes);							\
Packit 6c4009
   arguments for program (terminated by NULL);				\
Packit 6c4009
   environment variables (terminated by NULL);				\
Packit 6c4009
   arguments for the program loader.  */				\
Packit 6c4009
"	mr	3,1\n"							\
Packit 6c4009
"	li	4,0\n"							\
Packit 6c4009
"	stdu	4,-128(1)\n"						\
Packit 6c4009
/* Call _dl_start with one parameter pointing at argc.  */		\
Packit 6c4009
"	bl	" DOT_PREFIX "_dl_start\n"				\
Packit 6c4009
"	nop\n"								\
Packit 6c4009
/* Transfer control to _dl_start_user!  */				\
Packit 6c4009
"	b	" DOT_PREFIX "_dl_start_user\n"				\
Packit 6c4009
".LT__start:\n"								\
Packit 6c4009
"	.long 0\n"							\
Packit 6c4009
"	.byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n"		\
Packit 6c4009
"	.long .LT__start-" BODY_PREFIX "_start\n"			\
Packit 6c4009
"	.short .LT__start_name_end-.LT__start_name_start\n"		\
Packit 6c4009
".LT__start_name_start:\n"						\
Packit 6c4009
"	.ascii \"_start\"\n"						\
Packit 6c4009
".LT__start_name_end:\n"						\
Packit 6c4009
"	.align 2\n"							\
Packit 6c4009
"	" END_2(_start) "\n"						\
Packit 6c4009
"	.pushsection	\".toc\",\"aw\"\n"				\
Packit 6c4009
DL_STARTING_UP_DEF							\
Packit 6c4009
".LC__rtld_local:\n"							\
Packit 6c4009
"	.tc _rtld_local[TC],_rtld_local\n"				\
Packit 6c4009
".LC__dl_argc:\n"							\
Packit 6c4009
"	.tc _dl_argc[TC],_dl_argc\n"					\
Packit 6c4009
".LC__dl_argv:\n"							\
Packit 6c4009
"	.tc __GI__dl_argv[TC],__GI__dl_argv\n"				\
Packit 6c4009
".LC__dl_fini:\n"							\
Packit 6c4009
"	.tc _dl_fini[TC],_dl_fini\n"					\
Packit 6c4009
"	.popsection\n"							\
Packit 6c4009
"	" ENTRY_2(_dl_start_user) "\n"					\
Packit 6c4009
/* Now, we do our main work of calling initialisation procedures.	\
Packit 6c4009
   The ELF ABI doesn't say anything about parameters for these,		\
Packit 6c4009
   so we just pass argc, argv, and the environment.			\
Packit 6c4009
   Changing these is strongly discouraged (not least because argc is	\
Packit 6c4009
   passed by value!).  */						\
Packit 6c4009
BODY_PREFIX "_dl_start_user:\n"						\
Packit 6c4009
"	" LOCALENTRY(_dl_start_user) "\n"				\
Packit 6c4009
/* the address of _start in r30.  */					\
Packit 6c4009
"	mr	30,3\n"							\
Packit 6c4009
/* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28.  */		\
Packit 6c4009
"	ld	28,.LC__rtld_local@toc(2)\n"				\
Packit 6c4009
"	ld	29,.LC__dl_argc@toc(2)\n"				\
Packit 6c4009
"	ld	27,.LC__dl_argv@toc(2)\n"				\
Packit 6c4009
/* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1).  */	\
Packit 6c4009
"	ld	3,0(28)\n"						\
Packit 6c4009
"	lwa	4,0(29)\n"						\
Packit 6c4009
"	ld	5,0(27)\n"						\
Packit 6c4009
"	sldi	6,4,3\n"						\
Packit 6c4009
"	add	6,5,6\n"						\
Packit 6c4009
"	addi	6,6,8\n"						\
Packit 6c4009
"	bl	" DOT_PREFIX "_dl_init\n"				\
Packit 6c4009
"	nop\n"								\
Packit 6c4009
/* Now, to conform to the ELF ABI, we have to:				\
Packit 6c4009
   Pass argc (actually _dl_argc) in r3;  */				\
Packit 6c4009
"	lwa	3,0(29)\n"						\
Packit 6c4009
/* Pass argv (actually _dl_argv) in r4;  */				\
Packit 6c4009
"	ld	4,0(27)\n"						\
Packit 6c4009
/* Pass argv+argc+1 in r5;  */						\
Packit 6c4009
"	sldi	5,3,3\n"						\
Packit 6c4009
"	add	6,4,5\n"						\
Packit 6c4009
"	addi	5,6,8\n"						\
Packit 6c4009
/* Pass the auxiliary vector in r6. This is passed to us just after	\
Packit 6c4009
   _envp.  */								\
Packit 6c4009
"2:	ldu	0,8(6)\n"						\
Packit 6c4009
"	cmpdi	0,0\n"							\
Packit 6c4009
"	bne	2b\n"							\
Packit 6c4009
"	addi	6,6,8\n"						\
Packit 6c4009
/* Pass a termination function pointer (in this case _dl_fini) in	\
Packit 6c4009
   r7.  */								\
Packit 6c4009
"	ld	7,.LC__dl_fini@toc(2)\n"				\
Packit 6c4009
/* Pass the stack pointer in r1 (so far so good), pointing to a NULL	\
Packit 6c4009
   value.  This lets our startup code distinguish between a program	\
Packit 6c4009
   linked statically, which linux will call with argc on top of the	\
Packit 6c4009
   stack which will hopefully never be zero, and a dynamically linked	\
Packit 6c4009
   program which will always have a NULL on the top of the stack.	\
Packit 6c4009
   Take the opportunity to clear LR, so anyone who accidentally		\
Packit 6c4009
   returns from _start gets SEGV.  Also clear the next few words of	\
Packit 6c4009
   the stack.  */							\
Packit 6c4009
"	li	31,0\n"							\
Packit 6c4009
"	std	31,0(1)\n"						\
Packit 6c4009
"	mtlr	31\n"							\
Packit 6c4009
"	std	31,8(1)\n"						\
Packit 6c4009
"	std	31,16(1)\n"						\
Packit 6c4009
"	std	31,24(1)\n"						\
Packit 6c4009
/* Now, call the start function descriptor at r30...  */		\
Packit 6c4009
"	.globl	._dl_main_dispatch\n"					\
Packit 6c4009
"._dl_main_dispatch:\n"							\
Packit 6c4009
"	" PPC64_LOAD_FUNCPTR(30) "\n"					\
Packit 6c4009
"	bctr\n"								\
Packit 6c4009
".LT__dl_start_user:\n"							\
Packit 6c4009
"	.long 0\n"							\
Packit 6c4009
"	.byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n"		\
Packit 6c4009
"	.long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n"	\
Packit 6c4009
"	.short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
Packit 6c4009
".LT__dl_start_user_name_start:\n"					\
Packit 6c4009
"	.ascii \"_dl_start_user\"\n"					\
Packit 6c4009
".LT__dl_start_user_name_end:\n"					\
Packit 6c4009
"	.align 2\n"							\
Packit 6c4009
"	" END_2(_dl_start_user) "\n"					\
Packit 6c4009
"	.popsection");
Packit 6c4009
Packit 6c4009
/* ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to
Packit 6c4009
   one of the main executable's symbols, as for a COPY reloc.
Packit 6c4009
Packit 6c4009
   To make function pointer comparisons work on most targets, the
Packit 6c4009
   relevant ABI states that the address of a non-local function in a
Packit 6c4009
   dynamically linked executable is the address of the PLT entry for
Packit 6c4009
   that function.  This is quite reasonable since using the real
Packit 6c4009
   function address in a non-PIC executable would typically require
Packit 6c4009
   dynamic relocations in .text, something to be avoided.  For such
Packit 6c4009
   functions, the linker emits a SHN_UNDEF symbol in the executable
Packit 6c4009
   with value equal to the PLT entry address.  Normally, SHN_UNDEF
Packit 6c4009
   symbols have a value of zero, so this is a clue to ld.so that it
Packit 6c4009
   should treat these symbols specially.  For relocations not in
Packit 6c4009
   ELF_RTYPE_CLASS_PLT (eg. those on function pointers), ld.so should
Packit 6c4009
   use the value of the executable SHN_UNDEF symbol, ie. the PLT entry
Packit 6c4009
   address.  For relocations in ELF_RTYPE_CLASS_PLT (eg. the relocs in
Packit 6c4009
   the PLT itself), ld.so should use the value of the corresponding
Packit 6c4009
   defined symbol in the object that defines the function, ie. the
Packit 6c4009
   real function address.  This complicates ld.so in that there are
Packit 6c4009
   now two possible values for a given symbol, and it gets even worse
Packit 6c4009
   because protected symbols need yet another set of rules.
Packit 6c4009
Packit 6c4009
   On PowerPC64 we don't need any of this.  The linker won't emit
Packit 6c4009
   SHN_UNDEF symbols with non-zero values.  ld.so can make all
Packit 6c4009
   relocations behave "normally", ie. always use the real address
Packit 6c4009
   like PLT relocations.  So always set ELF_RTYPE_CLASS_PLT.  */
Packit 6c4009
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
#define elf_machine_type_class(type) \
Packit 6c4009
  (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
Packit 6c4009
#else
Packit 6c4009
/* And now that you have read that large comment, you can disregard it
Packit 6c4009
   all for ELFv2.  ELFv2 does need the special SHN_UNDEF treatment.  */
Packit 6c4009
#define IS_PPC64_TLS_RELOC(R)						\
Packit 6c4009
  (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA)		\
Packit 6c4009
   || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
Packit 6c4009
Packit 6c4009
#define elf_machine_type_class(type) \
Packit 6c4009
  ((((type) == R_PPC64_JMP_SLOT					\
Packit 6c4009
     || (type) == R_PPC64_ADDR24				\
Packit 6c4009
     || IS_PPC64_TLS_RELOC (type)) * ELF_RTYPE_CLASS_PLT)	\
Packit 6c4009
   | (((type) == R_PPC64_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_PPC64_JMP_SLOT
Packit 6c4009
Packit 6c4009
/* The PowerPC never uses REL relocations.  */
Packit 6c4009
#define ELF_MACHINE_NO_REL 1
Packit 6c4009
#define ELF_MACHINE_NO_RELA 0
Packit 6c4009
Packit 6c4009
/* We define an initialization function to initialize HWCAP/HWCAP2 and
Packit 6c4009
   platform data so it can be copied into the TCB later.  This is called
Packit 6c4009
   very early in _dl_sysdep_start for dynamically linked binaries.  */
Packit 6c4009
#if defined(SHARED) && IS_IN (rtld)
Packit 6c4009
# define DL_PLATFORM_INIT dl_platform_init ()
Packit 6c4009
Packit 6c4009
static inline void __attribute__ ((unused))
Packit 6c4009
dl_platform_init (void)
Packit 6c4009
{
Packit 6c4009
  __tcb_parse_hwcap_and_convert_at_platform ();
Packit 6c4009
  init_cpu_features (&GLRO(dl_powerpc_cpu_features));
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Stuff for the PLT.  */
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
#define PLT_INITIAL_ENTRY_WORDS 3
Packit 6c4009
#define PLT_ENTRY_WORDS 3
Packit 6c4009
#define GLINK_INITIAL_ENTRY_WORDS 8
Packit 6c4009
/* The first 32k entries of glink can set an index and branch using two
Packit 6c4009
   instructions; past that point, glink uses three instructions.  */
Packit 6c4009
#define GLINK_ENTRY_WORDS(I) (((I) < 0x8000)? 2 : 3)
Packit 6c4009
#else
Packit 6c4009
#define PLT_INITIAL_ENTRY_WORDS 2
Packit 6c4009
#define PLT_ENTRY_WORDS 1
Packit 6c4009
#define GLINK_INITIAL_ENTRY_WORDS 8
Packit 6c4009
#define GLINK_ENTRY_WORDS(I) 1
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
Packit 6c4009
#define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
Packit 6c4009
#define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory")
Packit 6c4009
#define PPC_SYNC asm volatile ("sync" : : : "memory")
Packit 6c4009
#define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
Packit 6c4009
#define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
Packit 6c4009
#define PPC_DIE asm volatile ("tweq 0,0")
Packit 6c4009
/* Use this when you've modified some code, but it won't be in the
Packit 6c4009
   instruction fetch queue (or when it doesn't matter if it is). */
Packit 6c4009
#define MODIFIED_CODE_NOQUEUE(where) \
Packit 6c4009
     do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
Packit 6c4009
/* Use this when it might be in the instruction queue. */
Packit 6c4009
#define MODIFIED_CODE(where) \
Packit 6c4009
     do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
Packit 6c4009
Packit 6c4009
/* Set up the loaded object described by MAP so its unrelocated PLT
Packit 6c4009
   entries will jump to the on-demand fixup code in dl-runtime.c.  */
Packit 6c4009
static inline int __attribute__ ((always_inline))
Packit 6c4009
elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
Packit 6c4009
{
Packit 6c4009
  if (map->l_info[DT_JMPREL])
Packit 6c4009
    {
Packit 6c4009
      Elf64_Word i;
Packit 6c4009
      Elf64_Word *glink = NULL;
Packit 6c4009
      Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
Packit 6c4009
      Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
Packit 6c4009
				    / sizeof (Elf64_Rela));
Packit 6c4009
      Elf64_Addr l_addr = map->l_addr;
Packit 6c4009
      Elf64_Dyn **info = map->l_info;
Packit 6c4009
      char *p;
Packit 6c4009
Packit 6c4009
      extern void _dl_runtime_resolve (void);
Packit 6c4009
      extern void _dl_profile_resolve (void);
Packit 6c4009
Packit 6c4009
      /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
Packit 6c4009
	 elf_get_dynamic_info takes care of the standard entries but
Packit 6c4009
	 doesn't know exactly what to do with processor specific
Packit 6c4009
	 entries.  */
Packit 6c4009
      if (info[DT_PPC64(GLINK)] != NULL)
Packit 6c4009
	info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
Packit 6c4009
Packit 6c4009
      if (lazy)
Packit 6c4009
	{
Packit 6c4009
	  Elf64_Word glink_offset;
Packit 6c4009
	  Elf64_Word offset;
Packit 6c4009
	  Elf64_Addr dlrr;
Packit 6c4009
Packit 6c4009
	  dlrr = (Elf64_Addr) (profile ? _dl_profile_resolve
Packit 6c4009
				       : _dl_runtime_resolve);
Packit 6c4009
	  if (profile && GLRO(dl_profile) != NULL
Packit 6c4009
	      && _dl_name_match_p (GLRO(dl_profile), map))
Packit 6c4009
	    /* This is the object we are looking for.  Say that we really
Packit 6c4009
	       want profiling and the timers are started.  */
Packit 6c4009
	    GL(dl_profile_map) = map;
Packit 6c4009
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
	  /* We need to stuff the address/TOC of _dl_runtime_resolve
Packit 6c4009
	     into doublewords 0 and 1 of plt_reserve.  Then we need to
Packit 6c4009
	     stuff the map address into doubleword 2 of plt_reserve.
Packit 6c4009
	     This allows the GLINK0 code to transfer control to the
Packit 6c4009
	     correct trampoline which will transfer control to fixup
Packit 6c4009
	     in dl-machine.c.  */
Packit 6c4009
	  {
Packit 6c4009
	    /* The plt_reserve area is the 1st 3 doublewords of the PLT.  */
Packit 6c4009
	    Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
Packit 6c4009
	    Elf64_FuncDesc *resolve_fd = (Elf64_FuncDesc *) dlrr;
Packit 6c4009
	    plt_reserve->fd_func = resolve_fd->fd_func;
Packit 6c4009
	    plt_reserve->fd_toc  = resolve_fd->fd_toc;
Packit 6c4009
	    plt_reserve->fd_aux  = (Elf64_Addr) map;
Packit 6c4009
#ifdef RTLD_BOOTSTRAP
Packit 6c4009
	    /* When we're bootstrapping, the opd entry will not have
Packit 6c4009
	       been relocated yet.  */
Packit 6c4009
	    plt_reserve->fd_func += l_addr;
Packit 6c4009
	    plt_reserve->fd_toc  += l_addr;
Packit 6c4009
#endif
Packit 6c4009
	  }
Packit 6c4009
#else
Packit 6c4009
	  /* When we don't have function descriptors, the first doubleword
Packit 6c4009
	     of the PLT holds the address of _dl_runtime_resolve, and the
Packit 6c4009
	     second doubleword holds the map address.  */
Packit 6c4009
	  plt[0] = dlrr;
Packit 6c4009
	  plt[1] = (Elf64_Addr) map;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  /* Set up the lazy PLT entries.  */
Packit 6c4009
	  glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
Packit 6c4009
	  offset = PLT_INITIAL_ENTRY_WORDS;
Packit 6c4009
	  glink_offset = GLINK_INITIAL_ENTRY_WORDS;
Packit 6c4009
	  for (i = 0; i < num_plt_entries; i++)
Packit 6c4009
	    {
Packit 6c4009
Packit 6c4009
	      plt[offset] = (Elf64_Xword) &glink[glink_offset];
Packit 6c4009
	      offset += PLT_ENTRY_WORDS;
Packit 6c4009
	      glink_offset += GLINK_ENTRY_WORDS (i);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Now, we've modified data.  We need to write the changes from
Packit 6c4009
	     the data cache to a second-level unified cache, then make
Packit 6c4009
	     sure that stale data in the instruction cache is removed.
Packit 6c4009
	     (In a multiprocessor system, the effect is more complex.)
Packit 6c4009
	     Most of the PLT shouldn't be in the instruction cache, but
Packit 6c4009
	     there may be a little overlap at the start and the end.
Packit 6c4009
Packit 6c4009
	     Assumes that dcbst and icbi apply to lines of 16 bytes or
Packit 6c4009
	     more.  Current known line sizes are 16, 32, and 128 bytes.  */
Packit 6c4009
Packit 6c4009
	  for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
Packit 6c4009
	    PPC_DCBST (p);
Packit 6c4009
	  PPC_SYNC;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return lazy;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if _CALL_ELF == 2
Packit 6c4009
extern void attribute_hidden _dl_error_localentry (struct link_map *map,
Packit 6c4009
						   const Elf64_Sym *refsym);
Packit 6c4009
Packit 6c4009
/* If the PLT entry resolves to a function in the same object, return
Packit 6c4009
   the target function's local entry point offset if usable.  */
Packit 6c4009
static inline Elf64_Addr __attribute__ ((always_inline))
Packit 6c4009
ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map,
Packit 6c4009
			  const ElfW(Sym) *refsym, const ElfW(Sym) *sym)
Packit 6c4009
{
Packit 6c4009
  /* If the target function is in a different object, we cannot
Packit 6c4009
     use the local entry point.  */
Packit 6c4009
  if (sym_map != map)
Packit 6c4009
    {
Packit 6c4009
      /* Check that optimized plt call stubs for localentry:0 functions
Packit 6c4009
	 are not being satisfied by a non-zero localentry symbol.  */
Packit 6c4009
      if (map->l_info[DT_PPC64(OPT)]
Packit 6c4009
	  && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_LOCALENTRY) != 0
Packit 6c4009
	  && refsym->st_info == ELFW(ST_INFO) (STB_GLOBAL, STT_FUNC)
Packit 6c4009
	  && (STO_PPC64_LOCAL_MASK & refsym->st_other) == 0
Packit 6c4009
	  && (STO_PPC64_LOCAL_MASK & sym->st_other) != 0)
Packit 6c4009
	_dl_error_localentry (map, refsym);
Packit 6c4009
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* If the linker inserted multiple TOCs, we cannot use the
Packit 6c4009
     local entry point.  */
Packit 6c4009
  if (map->l_info[DT_PPC64(OPT)]
Packit 6c4009
      && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_MULTI_TOC))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* If the target function is an ifunc then the local entry offset is
Packit 6c4009
     for the resolver, not the final destination.  */
Packit 6c4009
  if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* Otherwise, we can use the local entry point.  Retrieve its offset
Packit 6c4009
     from the symbol's ELF st_other field.  */
Packit 6c4009
  return PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Change the PLT entry whose reloc is 'reloc' to call the actual
Packit 6c4009
   routine.  */
Packit 6c4009
static inline Elf64_Addr __attribute__ ((always_inline))
Packit 6c4009
elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
Packit 6c4009
		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
Packit 6c4009
		       const Elf64_Rela *reloc,
Packit 6c4009
		       Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
Packit 6c4009
{
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
  Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
Packit 6c4009
  Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
Packit 6c4009
  Elf64_Addr offset = 0;
Packit 6c4009
  Elf64_FuncDesc zero_fd = {0, 0, 0};
Packit 6c4009
Packit 6c4009
  PPC_DCBT (&plt->fd_aux);
Packit 6c4009
  PPC_DCBT (&plt->fd_func);
Packit 6c4009
Packit 6c4009
  /* If sym_map is NULL, it's a weak undefined sym;  Set the plt to
Packit 6c4009
     zero.  finaladdr should be zero already in this case, but guard
Packit 6c4009
     against invalid plt relocations with non-zero addends.  */
Packit 6c4009
  if (sym_map == NULL)
Packit 6c4009
    finaladdr = 0;
Packit 6c4009
Packit 6c4009
  /* Don't die here if finaladdr is zero, die if this plt entry is
Packit 6c4009
     actually called.  Makes a difference when LD_BIND_NOW=1.
Packit 6c4009
     finaladdr may be zero for a weak undefined symbol, or when an
Packit 6c4009
     ifunc resolver returns zero.  */
Packit 6c4009
  if (finaladdr == 0)
Packit 6c4009
    rel = &zero_fd;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      PPC_DCBT (&rel->fd_aux);
Packit 6c4009
      PPC_DCBT (&rel->fd_func);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* If the opd entry is not yet relocated (because it's from a shared
Packit 6c4009
     object that hasn't been processed yet), then manually reloc it.  */
Packit 6c4009
  if (finaladdr != 0 && map != sym_map && !sym_map->l_relocated
Packit 6c4009
#if !defined RTLD_BOOTSTRAP && defined SHARED
Packit 6c4009
      /* Bootstrap map doesn't have l_relocated set for it.  */
Packit 6c4009
      && sym_map != &GL(dl_rtld_map)
Packit 6c4009
#endif
Packit 6c4009
      )
Packit 6c4009
    offset = sym_map->l_addr;
Packit 6c4009
Packit 6c4009
  /* For PPC64, fixup_plt copies the function descriptor from opd
Packit 6c4009
     over the corresponding PLT entry.
Packit 6c4009
     Initially, PLT Entry[i] is set up for lazy linking, or is zero.
Packit 6c4009
     For lazy linking, the fd_toc and fd_aux entries are irrelevant,
Packit 6c4009
     so for thread safety we write them before changing fd_func.  */
Packit 6c4009
Packit 6c4009
  plt->fd_aux = rel->fd_aux + offset;
Packit 6c4009
  plt->fd_toc = rel->fd_toc + offset;
Packit 6c4009
  PPC_DCBF (&plt->fd_toc);
Packit 6c4009
  PPC_ISYNC;
Packit 6c4009
Packit 6c4009
  plt->fd_func = rel->fd_func + offset;
Packit 6c4009
  PPC_DCBST (&plt->fd_func);
Packit 6c4009
  PPC_ISYNC;
Packit 6c4009
#else
Packit 6c4009
  finaladdr += ppc64_local_entry_offset (map, sym_map, refsym, sym);
Packit 6c4009
  *reloc_addr = finaladdr;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  return finaladdr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void __attribute__ ((always_inline))
Packit 6c4009
elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map,
Packit 6c4009
			  const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
Packit 6c4009
			  const Elf64_Rela *reloc,
Packit 6c4009
			  Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
Packit 6c4009
{
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
  Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
Packit 6c4009
  Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
Packit 6c4009
  Elf64_FuncDesc zero_fd = {0, 0, 0};
Packit 6c4009
Packit 6c4009
  if (sym_map == NULL)
Packit 6c4009
    finaladdr = 0;
Packit 6c4009
Packit 6c4009
  if (finaladdr == 0)
Packit 6c4009
    rel = &zero_fd;
Packit 6c4009
Packit 6c4009
  plt->fd_func = rel->fd_func;
Packit 6c4009
  plt->fd_aux = rel->fd_aux;
Packit 6c4009
  plt->fd_toc = rel->fd_toc;
Packit 6c4009
  PPC_DCBST (&plt->fd_func);
Packit 6c4009
  PPC_DCBST (&plt->fd_aux);
Packit 6c4009
  PPC_DCBST (&plt->fd_toc);
Packit 6c4009
  PPC_SYNC;
Packit 6c4009
#else
Packit 6c4009
  finaladdr += ppc64_local_entry_offset (map, sym_map, refsym, sym);
Packit 6c4009
  *reloc_addr = finaladdr;
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the final value of a plt relocation.  */
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
Packit 6c4009
		       Elf64_Addr value)
Packit 6c4009
{
Packit 6c4009
  return value + reloc->r_addend;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Names of the architecture-specific auditing callback functions.  */
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
#define ARCH_LA_PLTENTER ppc64_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
Packit 6c4009
#else
Packit 6c4009
#define ARCH_LA_PLTENTER ppc64v2_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT ppc64v2_gnu_pltexit
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#endif /* dl_machine_h */
Packit 6c4009
Packit 6c4009
#ifdef RESOLVE_MAP
Packit 6c4009
Packit 6c4009
#define PPC_LO(v) ((v) & 0xffff)
Packit 6c4009
#define PPC_HI(v) (((v) >> 16) & 0xffff)
Packit 6c4009
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
Packit 6c4009
#define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
Packit 6c4009
#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
Packit 6c4009
#define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
Packit 6c4009
#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
Packit 6c4009
#define BIT_INSERT(var, val, mask) \
Packit 6c4009
  ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
Packit 6c4009
Packit 6c4009
#define dont_expect(X) __builtin_expect ((X), 0)
Packit 6c4009
Packit 6c4009
extern void attribute_hidden _dl_reloc_overflow (struct link_map *map,
Packit 6c4009
						 const char *name,
Packit 6c4009
						 Elf64_Addr *const reloc_addr,
Packit 6c4009
						 const Elf64_Sym *refsym);
Packit 6c4009
Packit 6c4009
auto inline void __attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
Packit 6c4009
			   void *const reloc_addr_arg)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  *reloc_addr = l_addr + reloc->r_addend;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This computes the value used by TPREL* relocs.  */
Packit 6c4009
auto inline Elf64_Addr __attribute__ ((always_inline, const))
Packit 6c4009
elf_machine_tprel (struct link_map *map,
Packit 6c4009
		   struct link_map *sym_map,
Packit 6c4009
		   const Elf64_Sym *sym,
Packit 6c4009
		   const Elf64_Rela *reloc)
Packit 6c4009
{
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
  if (sym_map)
Packit 6c4009
    {
Packit 6c4009
      CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
#endif
Packit 6c4009
      return TLS_TPREL_VALUE (sym_map, sym, reloc);
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Call function at address VALUE (an OPD entry) to resolve ifunc relocs.  */
Packit 6c4009
auto inline Elf64_Addr __attribute__ ((always_inline))
Packit 6c4009
resolve_ifunc (Elf64_Addr value,
Packit 6c4009
	       const struct link_map *map, const struct link_map *sym_map)
Packit 6c4009
{
Packit 6c4009
#if _CALL_ELF != 2
Packit 6c4009
#ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
  /* The function we are calling may not yet have its opd entry relocated.  */
Packit 6c4009
  Elf64_FuncDesc opd;
Packit 6c4009
  if (map != sym_map
Packit 6c4009
# if !defined RTLD_BOOTSTRAP && defined SHARED
Packit 6c4009
      /* Bootstrap map doesn't have l_relocated set for it.  */
Packit 6c4009
      && sym_map != &GL(dl_rtld_map)
Packit 6c4009
# endif
Packit 6c4009
      && !sym_map->l_relocated)
Packit 6c4009
    {
Packit 6c4009
      Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
Packit 6c4009
      opd.fd_func = func->fd_func + sym_map->l_addr;
Packit 6c4009
      opd.fd_toc = func->fd_toc + sym_map->l_addr;
Packit 6c4009
      opd.fd_aux = func->fd_aux;
Packit 6c4009
      /* GCC 4.9+ eliminates the branch as dead code, force the odp set
Packit 6c4009
         dependency.  */
Packit 6c4009
      asm ("" : "=r" (value) : "0" (&opd), "X" (opd));
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
#endif
Packit 6c4009
  return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Perform the relocation specified by RELOC and SYM (which is fully
Packit 6c4009
   resolved).  MAP is the object containing the reloc.  */
Packit 6c4009
auto inline void __attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela (struct link_map *map,
Packit 6c4009
		  const Elf64_Rela *reloc,
Packit 6c4009
		  const Elf64_Sym *sym,
Packit 6c4009
		  const struct r_found_version *version,
Packit 6c4009
		  void *const reloc_addr_arg,
Packit 6c4009
		  int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  const int r_type = ELF64_R_TYPE (reloc->r_info);
Packit 6c4009
  const Elf64_Sym *const refsym = sym;
Packit 6c4009
  union unaligned
Packit 6c4009
    {
Packit 6c4009
      uint16_t u2;
Packit 6c4009
      uint32_t u4;
Packit 6c4009
      uint64_t u8;
Packit 6c4009
    } __attribute__ ((__packed__));
Packit 6c4009
Packit 6c4009
  if (r_type == R_PPC64_RELATIVE)
Packit 6c4009
    {
Packit 6c4009
      *reloc_addr = map->l_addr + reloc->r_addend;
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (r_type == R_PPC64_NONE))
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
Packit 6c4009
     and STT_GNU_IFUNC.  */
Packit 6c4009
  struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
  Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
Packit 6c4009
Packit 6c4009
  if (sym != NULL
Packit 6c4009
      && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
Packit 6c4009
      && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
Packit 6c4009
      && __builtin_expect (!skip_ifunc, 1))
Packit 6c4009
    value = resolve_ifunc (value, map, sym_map);
Packit 6c4009
Packit 6c4009
  /* For relocs that don't edit code, return.
Packit 6c4009
     For relocs that might edit instructions, break from the switch.  */
Packit 6c4009
  switch (r_type)
Packit 6c4009
    {
Packit 6c4009
    case R_PPC64_ADDR64:
Packit 6c4009
    case R_PPC64_GLOB_DAT:
Packit 6c4009
      *reloc_addr = value;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_IRELATIVE:
Packit 6c4009
      if (__glibc_likely (!skip_ifunc))
Packit 6c4009
	value = resolve_ifunc (value, map, sym_map);
Packit 6c4009
      *reloc_addr = value;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_JMP_IREL:
Packit 6c4009
      if (__glibc_likely (!skip_ifunc))
Packit 6c4009
	value = resolve_ifunc (value, map, sym_map);
Packit 6c4009
      /* Fall thru */
Packit 6c4009
    case R_PPC64_JMP_SLOT:
Packit 6c4009
#ifdef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
      elf_machine_plt_conflict (map, sym_map, refsym, sym,
Packit 6c4009
				reloc, reloc_addr, value);
Packit 6c4009
#else
Packit 6c4009
      elf_machine_fixup_plt (map, sym_map, refsym, sym,
Packit 6c4009
			     reloc, reloc_addr, value);
Packit 6c4009
#endif
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_DTPMOD64:
Packit 6c4009
      if (map->l_info[DT_PPC64(OPT)]
Packit 6c4009
	  && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_TLS))
Packit 6c4009
	{
Packit 6c4009
#ifdef RTLD_BOOTSTRAP
Packit 6c4009
	  reloc_addr[0] = 0;
Packit 6c4009
	  reloc_addr[1] = (sym_map->l_tls_offset - TLS_TP_OFFSET
Packit 6c4009
			   + TLS_DTV_OFFSET);
Packit 6c4009
	  return;
Packit 6c4009
#else
Packit 6c4009
	  if (sym_map != NULL)
Packit 6c4009
	    {
Packit 6c4009
# ifndef SHARED
Packit 6c4009
	      CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
# else
Packit 6c4009
	      if (TRY_STATIC_TLS (map, sym_map))
Packit 6c4009
# endif
Packit 6c4009
		{
Packit 6c4009
		  reloc_addr[0] = 0;
Packit 6c4009
		  /* Set up for local dynamic.  */
Packit 6c4009
		  reloc_addr[1] = (sym_map->l_tls_offset - TLS_TP_OFFSET
Packit 6c4009
				   + TLS_DTV_OFFSET);
Packit 6c4009
		  return;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	}
Packit 6c4009
#ifdef RTLD_BOOTSTRAP
Packit 6c4009
      /* During startup the dynamic linker is always index 1.  */
Packit 6c4009
      *reloc_addr = 1;
Packit 6c4009
#else
Packit 6c4009
      /* Get the information from the link map returned by the
Packit 6c4009
	 resolve function.  */
Packit 6c4009
      if (sym_map != NULL)
Packit 6c4009
	*reloc_addr = sym_map->l_tls_modid;
Packit 6c4009
#endif
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_DTPREL64:
Packit 6c4009
      if (map->l_info[DT_PPC64(OPT)]
Packit 6c4009
	  && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_TLS))
Packit 6c4009
	{
Packit 6c4009
#ifdef RTLD_BOOTSTRAP
Packit 6c4009
	  *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
Packit 6c4009
	  return;
Packit 6c4009
#else
Packit 6c4009
	  if (sym_map != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /* This reloc is always preceded by R_PPC64_DTPMOD64.  */
Packit 6c4009
# ifndef SHARED
Packit 6c4009
	      assert (HAVE_STATIC_TLS (map, sym_map));
Packit 6c4009
# else
Packit 6c4009
	      if (HAVE_STATIC_TLS (map, sym_map))
Packit 6c4009
#  endif
Packit 6c4009
		{
Packit 6c4009
		  *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
Packit 6c4009
		  return;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	}
Packit 6c4009
      /* During relocation all TLS symbols are defined and used.
Packit 6c4009
	 Therefore the offset is already correct.  */
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
      if (sym_map != NULL)
Packit 6c4009
	*reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
Packit 6c4009
#endif
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL64:
Packit 6c4009
      *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_LO_DS:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      if (dont_expect ((value & 3) != 0))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
Packit 6c4009
      BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_DS:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
Packit 6c4009
      BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      if (dont_expect ((value + 0x8000) >= 0x10000))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_LO (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_LO:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_LO (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HI:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      if (dont_expect (value + 0x80000000 >= 0x100000000LL))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_TPREL16_HI", reloc_addr, refsym);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HI (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HIGH:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HI (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HA:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      if (dont_expect (value + 0x80008000 >= 0x100000000LL))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_TPREL16_HA", reloc_addr, refsym);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HIGHA:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HIGHER:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HIGHEST:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HIGHERA:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_TPREL16_HIGHESTA:
Packit 6c4009
      value = elf_machine_tprel (map, sym_map, sym, reloc);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
#ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
Packit 6c4009
    case R_PPC64_ADDR16_LO_DS:
Packit 6c4009
      if (dont_expect ((value & 3) != 0))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
Packit 6c4009
      BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_LO:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_LO (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_HI:
Packit 6c4009
      if (dont_expect (value + 0x80000000 >= 0x100000000LL))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR16_HI", reloc_addr, refsym);
Packit 6c4009
    case R_PPC64_ADDR16_HIGH:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HI (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_HA:
Packit 6c4009
      if (dont_expect (value + 0x80008000 >= 0x100000000LL))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR16_HA", reloc_addr, refsym);
Packit 6c4009
    case R_PPC64_ADDR16_HIGHA:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR30:
Packit 6c4009
      {
Packit 6c4009
	Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
Packit 6c4009
	if (dont_expect ((delta + 0x80000000) >= 0x100000000LL
Packit 6c4009
			 || (delta & 3) != 0))
Packit 6c4009
	  _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
Packit 6c4009
	BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_COPY:
Packit 6c4009
      if (dont_expect (sym == NULL))
Packit 6c4009
	/* This can happen in trace mode when an object could not be found. */
Packit 6c4009
	return;
Packit 6c4009
      if (dont_expect (sym->st_size > refsym->st_size
Packit 6c4009
		       || (GLRO(dl_verbose)
Packit 6c4009
			   && sym->st_size < refsym->st_size)))
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 ("%s: Symbol `%s' has different size" \
Packit 6c4009
			    " in shared object," \
Packit 6c4009
			    " consider re-linking\n",
Packit 6c4009
			    RTLD_PROGNAME, strtab + refsym->st_name);
Packit 6c4009
	}
Packit 6c4009
      memcpy (reloc_addr_arg, (char *) value,
Packit 6c4009
	      MIN (sym->st_size, refsym->st_size));
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_UADDR64:
Packit 6c4009
      ((union unaligned *) reloc_addr)->u8 = value;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_UADDR32:
Packit 6c4009
      ((union unaligned *) reloc_addr)->u4 = value;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR32:
Packit 6c4009
      if (dont_expect ((value + 0x80000000) >= 0x100000000LL))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
Packit 6c4009
      *(Elf64_Word *) reloc_addr = value;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR24:
Packit 6c4009
      if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
Packit 6c4009
      BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16:
Packit 6c4009
      if (dont_expect ((value + 0x8000) >= 0x10000))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
Packit 6c4009
      *(Elf64_Half *) reloc_addr = value;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_UADDR16:
Packit 6c4009
      if (dont_expect ((value + 0x8000) >= 0x10000))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
Packit 6c4009
      ((union unaligned *) reloc_addr)->u2 = value;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_DS:
Packit 6c4009
      if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
Packit 6c4009
	_dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
Packit 6c4009
      BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_HIGHER:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_HIGHEST:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_HIGHERA:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR16_HIGHESTA:
Packit 6c4009
      *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_ADDR14:
Packit 6c4009
    case R_PPC64_ADDR14_BRTAKEN:
Packit 6c4009
    case R_PPC64_ADDR14_BRNTAKEN:
Packit 6c4009
      {
Packit 6c4009
	if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
Packit 6c4009
	  _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
Packit 6c4009
	Elf64_Word insn = *(Elf64_Word *) reloc_addr;
Packit 6c4009
	BIT_INSERT (insn, value, 0xfffc);
Packit 6c4009
	if (r_type != R_PPC64_ADDR14)
Packit 6c4009
	  {
Packit 6c4009
	    insn &= ~(1 << 21);
Packit 6c4009
	    if (r_type == R_PPC64_ADDR14_BRTAKEN)
Packit 6c4009
	      insn |= 1 << 21;
Packit 6c4009
	    if ((insn & (0x14 << 21)) == (0x04 << 21))
Packit 6c4009
	      insn |= 0x02 << 21;
Packit 6c4009
	    else if ((insn & (0x14 << 21)) == (0x10 << 21))
Packit 6c4009
	      insn |= 0x08 << 21;
Packit 6c4009
	  }
Packit 6c4009
	*(Elf64_Word *) reloc_addr = insn;
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PPC64_REL32:
Packit 6c4009
      *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PPC64_REL64:
Packit 6c4009
      *reloc_addr = value - (Elf64_Addr) reloc_addr;
Packit 6c4009
      return;
Packit 6c4009
#endif /* !RTLD_BOOTSTRAP */
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      _dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  MODIFIED_CODE_NOQUEUE (reloc_addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
auto inline void __attribute__ ((always_inline))
Packit 6c4009
elf_machine_lazy_rel (struct link_map *map,
Packit 6c4009
		      Elf64_Addr l_addr, const Elf64_Rela *reloc,
Packit 6c4009
		      int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  /* elf_machine_runtime_setup handles this.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#endif /* RESOLVE */