| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Machine-dependent ELF dynamic relocation inline functions.  IA-64 version. | 
 | 2 |    Copyright (C) 1995-2016 Free Software Foundation, Inc. | 
 | 3 |    This file is part of the GNU C Library. | 
 | 4 |  | 
 | 5 |    The GNU C Library is free software; you can redistribute it and/or | 
 | 6 |    modify it under the terms of the GNU Lesser General Public | 
 | 7 |    License as published by the Free Software Foundation; either | 
 | 8 |    version 2.1 of the License, or (at your option) any later version. | 
 | 9 |  | 
 | 10 |    The GNU C Library is distributed in the hope that it will be useful, | 
 | 11 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 12 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 13 |    Lesser General Public License for more details. | 
 | 14 |  | 
 | 15 |    You should have received a copy of the GNU Lesser General Public | 
 | 16 |    License along with the GNU C Library; if not, see | 
 | 17 |    <http://www.gnu.org/licenses/>.  */ | 
 | 18 |  | 
 | 19 | #ifndef dl_machine_h | 
 | 20 | #define dl_machine_h 1 | 
 | 21 |  | 
 | 22 | #define ELF_MACHINE_NAME "ia64" | 
 | 23 |  | 
 | 24 | #include <assert.h> | 
 | 25 | #include <string.h> | 
 | 26 | #include <link.h> | 
 | 27 | #include <errno.h> | 
 | 28 | #include <dl-fptr.h> | 
 | 29 | #include <tls.h> | 
 | 30 |  | 
 | 31 | /* Translate a processor specific dynamic tag to the index | 
 | 32 |    in l_info array.  */ | 
 | 33 | #define DT_IA_64(x) (DT_IA_64_##x - DT_LOPROC + DT_NUM) | 
 | 34 |  | 
 | 35 | static inline void __attribute__ ((always_inline)) | 
 | 36 | __ia64_init_bootstrap_fdesc_table (struct link_map *map) | 
 | 37 | { | 
 | 38 |   Elf64_Addr *boot_table; | 
 | 39 |  | 
 | 40 |   /* careful: this will be called before got has been relocated... */ | 
 | 41 |   asm (";; addl %0 = @gprel (_dl_boot_fptr_table), gp" : "=r"(boot_table)); | 
 | 42 |  | 
 | 43 |   map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN; | 
 | 44 |   map->l_mach.fptr_table = boot_table; | 
 | 45 | } | 
 | 46 |  | 
 | 47 | #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)		\ | 
 | 48 | 	__ia64_init_bootstrap_fdesc_table (&bootstrap_map); | 
 | 49 |  | 
 | 50 | /* Return nonzero iff ELF header is compatible with the running host.  */ | 
 | 51 | static inline int __attribute__ ((unused)) | 
 | 52 | elf_machine_matches_host (const Elf64_Ehdr *ehdr) | 
 | 53 | { | 
 | 54 |   return ehdr->e_machine == EM_IA_64; | 
 | 55 | } | 
 | 56 |  | 
 | 57 |  | 
 | 58 | /* Return the link-time address of _DYNAMIC.  */ | 
 | 59 | static inline Elf64_Addr __attribute__ ((unused, const)) | 
 | 60 | elf_machine_dynamic (void) | 
 | 61 | { | 
 | 62 |   Elf64_Addr *p; | 
 | 63 |  | 
 | 64 |   __asm__ ( | 
 | 65 | 	".section .sdata\n" | 
 | 66 | 	"	.type __dynamic_ltv#, @object\n" | 
 | 67 | 	"	.size __dynamic_ltv#, 8\n" | 
 | 68 | 	"__dynamic_ltv:\n" | 
 | 69 | 	"	data8	@ltv(_DYNAMIC#)\n" | 
 | 70 | 	".previous\n" | 
 | 71 | 	"	addl	%0 = @gprel(__dynamic_ltv#), gp ;;" | 
 | 72 | 	: "=r" (p)); | 
 | 73 |  | 
 | 74 |   return *p; | 
 | 75 | } | 
 | 76 |  | 
 | 77 |  | 
 | 78 | /* Return the run-time load address of the shared object.  */ | 
 | 79 | static inline Elf64_Addr __attribute__ ((unused)) | 
 | 80 | elf_machine_load_address (void) | 
 | 81 | { | 
 | 82 |   Elf64_Addr ip; | 
 | 83 |   int *p; | 
 | 84 |  | 
 | 85 |   __asm__ ( | 
 | 86 | 	"1:	mov %0 = ip\n" | 
 | 87 | 	".section .sdata\n" | 
 | 88 | 	"2:	data4	@ltv(1b)\n" | 
 | 89 | 	"       .align 8\n" | 
 | 90 | 	".previous\n" | 
 | 91 | 	"	addl	%1 = @gprel(2b), gp ;;" | 
 | 92 | 	: "=r" (ip), "=r" (p)); | 
 | 93 |  | 
 | 94 |   return ip - (Elf64_Addr) *p; | 
 | 95 | } | 
 | 96 |  | 
 | 97 | /* Set up the loaded object described by L so its unrelocated PLT | 
 | 98 |    entries will jump to the on-demand fixup code in dl-runtime.c.  */ | 
 | 99 |  | 
 | 100 | static inline int __attribute__ ((unused, always_inline)) | 
 | 101 | elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) | 
 | 102 | { | 
 | 103 |   extern void _dl_runtime_resolve (void); | 
 | 104 |   extern void _dl_runtime_profile (void); | 
 | 105 |  | 
 | 106 |   if (lazy) | 
 | 107 |     { | 
 | 108 |       register Elf64_Addr gp __asm__ ("gp"); | 
 | 109 |       Elf64_Addr *reserve, doit; | 
 | 110 |  | 
 | 111 |       /* | 
 | 112 |        * Careful with the typecast here or it will try to add l-l_addr | 
 | 113 |        * pointer elements | 
 | 114 |        */ | 
 | 115 |       reserve = ((Elf64_Addr *) | 
 | 116 | 		 (l->l_info[DT_IA_64 (PLT_RESERVE)]->d_un.d_ptr + l->l_addr)); | 
 | 117 |       /* Identify this shared object.  */ | 
 | 118 |       reserve[0] = (Elf64_Addr) l; | 
 | 119 |  | 
 | 120 |       /* This function will be called to perform the relocation.  */ | 
 | 121 |       if (!profile) | 
 | 122 | 	doit = (Elf64_Addr) ELF_PTR_TO_FDESC (&_dl_runtime_resolve)->ip; | 
 | 123 |       else | 
 | 124 | 	{ | 
 | 125 | 	  if (GLRO(dl_profile) != NULL | 
 | 126 | 	      && _dl_name_match_p (GLRO(dl_profile), l)) | 
 | 127 | 	    { | 
 | 128 | 	      /* This is the object we are looking for.  Say that we really | 
 | 129 | 		 want profiling and the timers are started.  */ | 
 | 130 | 	      GL(dl_profile_map) = l; | 
 | 131 | 	    } | 
 | 132 | 	  doit = (Elf64_Addr) ELF_PTR_TO_FDESC (&_dl_runtime_profile)->ip; | 
 | 133 | 	} | 
 | 134 |  | 
 | 135 |       reserve[1] = doit; | 
 | 136 |       reserve[2] = gp; | 
 | 137 |     } | 
 | 138 |  | 
 | 139 |   return lazy; | 
 | 140 | } | 
 | 141 |  | 
 | 142 | /* Names of the architecture-specific auditing callback functions.  */ | 
 | 143 | #define ARCH_LA_PLTENTER ia64_gnu_pltenter | 
 | 144 | #define ARCH_LA_PLTEXIT ia64_gnu_pltexit | 
 | 145 |  | 
 | 146 | /* Undo the adds out0 = 16, sp below to get at the value we want in | 
 | 147 |    __libc_stack_end.  */ | 
 | 148 | #define DL_STACK_END(cookie) \ | 
 | 149 |   ((void *) (((long) (cookie)) - 16)) | 
 | 150 |  | 
 | 151 | /* Initial entry point code for the dynamic linker. | 
 | 152 |    The C function `_dl_start' is the real entry point; | 
 | 153 |    its return value is the user program's entry point.  */ | 
 | 154 |  | 
 | 155 | #define RTLD_START asm (						      \ | 
 | 156 | ".text\n"								      \ | 
 | 157 | "	.global _start#\n"						      \ | 
 | 158 | "	.proc _start#\n"						      \ | 
 | 159 | "_start:\n"								      \ | 
 | 160 | "0:	{ .mii\n"							      \ | 
 | 161 | "	  .prologue\n"							      \ | 
 | 162 | "	  .save rp, r0\n"						      \ | 
 | 163 | "	  .body\n"							      \ | 
 | 164 | "	  .prologue\n"							      \ | 
 | 165 | "	  .save ar.pfs, r32\n"						      \ | 
 | 166 | "	  alloc loc0 = ar.pfs, 0, 3, 4, 0\n"				      \ | 
 | 167 | "	  .body\n"							      \ | 
 | 168 | "	  mov r2 = ip\n"						      \ | 
 | 169 | "	  addl r3 = @gprel(0b), r0\n"					      \ | 
 | 170 | "	  ;;\n"								      \ | 
 | 171 | "	}\n"								      \ | 
 | 172 | "	{ .mlx\n"							      \ | 
 | 173 | "	  /* Calculate the GP, and save a copy in loc1.  */\n"		      \ | 
 | 174 | "	  sub gp = r2, r3\n"						      \ | 
 | 175 | "	  movl r8 = 0x9804c0270033f\n"					      \ | 
 | 176 | "	  ;;\n"								      \ | 
 | 177 | "	}\n"								      \ | 
 | 178 | "	{ .mii\n"							      \ | 
 | 179 | "	  mov ar.fpsr = r8\n"						      \ | 
 | 180 | "	  sub loc1 = r2, r3\n"						      \ | 
 | 181 | "	  /* _dl_start wants a pointer to the pointer to the arg block and\n" \ | 
 | 182 | "	     the arg block starts with an integer, thus the magic 16. */\n"   \ | 
 | 183 | "	  adds out0 = 16, sp\n"						      \ | 
 | 184 | "	}\n"								      \ | 
 | 185 | "	{ .bbb\n"							      \ | 
 | 186 | "	  br.call.sptk.many b0 = _dl_start#\n"				      \ | 
 | 187 | "	  ;;\n"								      \ | 
 | 188 | "	}\n"								      \ | 
 | 189 | "	.endp _start#\n"						      \ | 
 | 190 | "	/* FALLTHRU */\n"						      \ | 
 | 191 | "	.global _dl_start_user#\n"					      \ | 
 | 192 | "	.proc _dl_start_user#\n"					      \ | 
 | 193 | "_dl_start_user:\n"							      \ | 
 | 194 | "	 .prologue\n"							      \ | 
 | 195 | "	 .save rp, r0\n"						      \ | 
 | 196 | "	  .body\n"							      \ | 
 | 197 | "	 .prologue\n"							      \ | 
 | 198 | "	 .save ar.pfs, r32\n"						      \ | 
 | 199 | "	 .body\n"							      \ | 
 | 200 | "	{ .mii\n"							      \ | 
 | 201 | "	  addl r3 = @gprel(_dl_skip_args), gp\n"			      \ | 
 | 202 | "	  adds r11 = 24, sp	/* Load the address of argv. */\n"	      \ | 
 | 203 | "	  /* Save the pointer to the user entry point fptr in loc2.  */\n"    \ | 
 | 204 | "	  mov loc2 = ret0\n"						      \ | 
 | 205 | "	  ;;\n"								      \ | 
 | 206 | "	}\n"								      \ | 
 | 207 | "	{ .mii\n"							      \ | 
 | 208 | "	  ld4 r3 = [r3]\n"						      \ | 
 | 209 | "	  adds r10 = 16, sp	/* Load the address of argc. */\n"	      \ | 
 | 210 | "	  mov out2 = r11\n"						      \ | 
 | 211 | "	  ;;\n"								      \ | 
 | 212 | "	  /* See if we were run as a command with the executable file\n"      \ | 
 | 213 | "	     name as an extra leading argument.  If so, adjust the argv\n"    \ | 
 | 214 | "	     pointer to skip _dl_skip_args words.\n"			      \ | 
 | 215 | "	     Note that _dl_skip_args is an integer, not a long - Jes\n"	      \ | 
 | 216 | "\n"									      \ | 
 | 217 | "	     The stack pointer has to be 16 byte aligned. We cannot simply\n" \ | 
 | 218 | "	     addjust the stack pointer. We have to move the whole argv and\n" \ | 
 | 219 | "	     envp and adjust _dl_argv by _dl_skip_args.  H.J.  */\n"	      \ | 
 | 220 | "	}\n"								      \ | 
 | 221 | "	{ .mib\n"							      \ | 
 | 222 | "	  ld8 out1 = [r10]	/* is argc actually stored as a long\n"	      \ | 
 | 223 | "				   or as an int? */\n"			      \ | 
 | 224 | "	  addl r2 = @ltoff(_dl_argv), gp\n"				      \ | 
 | 225 | "	  ;;\n"								      \ | 
 | 226 | "	}\n"								      \ | 
 | 227 | "	{ .mmi\n"							      \ | 
 | 228 | "	  ld8 r2 = [r2]		/* Get the address of _dl_argv. */\n"	      \ | 
 | 229 | "	  sub out1 = out1, r3	/* Get the new argc. */\n"		      \ | 
 | 230 | "	  shladd r3 = r3, 3, r0\n"					      \ | 
 | 231 | "	  ;;\n"								      \ | 
 | 232 | "	}\n"								      \ | 
 | 233 | "	{\n"								      \ | 
 | 234 | "	  .mib\n"							      \ | 
 | 235 | "	  ld8 r17 = [r2]	/* Get _dl_argv. */\n"			      \ | 
 | 236 | "	  add r15 = r11, r3	/* The address of the argv we move */\n"      \ | 
 | 237 | "	  ;;\n"								      \ | 
 | 238 | "	}\n"								      \ | 
 | 239 | "	/* ??? Could probably merge these two loops into 3 bundles.\n"	      \ | 
 | 240 | "	   using predication to control which set of copies we're on.  */\n"  \ | 
 | 241 | "1:	/* Copy argv. */\n"						      \ | 
 | 242 | "	{ .mfi\n"							      \ | 
 | 243 | "	  ld8 r16 = [r15], 8	/* Load the value in the old argv. */\n"      \ | 
 | 244 | "	  ;;\n"								      \ | 
 | 245 | "	}\n"								      \ | 
 | 246 | "	{ .mib\n"							      \ | 
 | 247 | "	  st8 [r11] = r16, 8	/* Store it in the new argv. */\n"	      \ | 
 | 248 | "	  cmp.ne p6, p7 = 0, r16\n"					      \ | 
 | 249 | "(p6)	  br.cond.dptk.few 1b\n"					      \ | 
 | 250 | "	  ;;\n"								      \ | 
 | 251 | "	}\n"								      \ | 
 | 252 | "	{ .mmi\n"							      \ | 
 | 253 | "	  mov out3 = r11\n"						      \ | 
 | 254 | "	  sub r17 = r17, r3	/* Substract _dl_skip_args. */\n"	      \ | 
 | 255 | "	  addl out0 = @gprel(_rtld_local), gp\n"			      \ | 
 | 256 | "	}\n"								      \ | 
 | 257 | "1:	/* Copy env. */\n"						      \ | 
 | 258 | "	{ .mfi\n"							      \ | 
 | 259 | "	  ld8 r16 = [r15], 8	/* Load the value in the old env. */\n"	      \ | 
 | 260 | "	  ;;\n"								      \ | 
 | 261 | "	}\n"								      \ | 
 | 262 | "	{ .mib\n"							      \ | 
 | 263 | "	  st8 [r11] = r16, 8	/* Store it in the new env. */\n"	      \ | 
 | 264 | "	  cmp.ne p6, p7 = 0, r16\n"					      \ | 
 | 265 | "(p6)	  br.cond.dptk.few 1b\n"					      \ | 
 | 266 | "	  ;;\n"								      \ | 
 | 267 | "	}\n"								      \ | 
 | 268 | "	{ .mmb\n"							      \ | 
 | 269 | "	  st8 [r10] = out1		/* Record the new argc. */\n"	      \ | 
 | 270 | "	  ld8 out0 = [out0]		/* get the linkmap */\n"	      \ | 
 | 271 | "	}\n"								      \ | 
 | 272 | "	{ .mmb\n"							      \ | 
 | 273 | "	  st8 [r2] = r17		/* Load the new _dl_argv. */\n"	      \ | 
 | 274 | "	  br.call.sptk.many b0 = _dl_init#\n"				      \ | 
 | 275 | "	  ;;\n"								      \ | 
 | 276 | "	}\n"								      \ | 
 | 277 | "	/* Pass our finalizer function to the user,\n"			      \ | 
 | 278 | "	   and jump to the user's entry point.  */\n"			      \ | 
 | 279 | "	{ .mmi\n"							      \ | 
 | 280 | "	  ld8 r3 = [loc2], 8\n"						      \ | 
 | 281 | "	  mov b0 = r0\n"						      \ | 
 | 282 | "	}\n"								      \ | 
 | 283 | "	{ .mmi\n"							      \ | 
 | 284 | "	  addl ret0 = @ltoff(@fptr(_dl_fini#)), gp\n"			      \ | 
 | 285 | "	  ;;\n"								      \ | 
 | 286 | "	  mov b6 = r3\n"						      \ | 
 | 287 | "	}\n"								      \ | 
 | 288 | "	{ .mmi\n"							      \ | 
 | 289 | "	  ld8 ret0 = [ret0]\n"						      \ | 
 | 290 | "	  ld8 gp = [loc2]\n"						      \ | 
 | 291 | "	  mov ar.pfs = loc0\n"						      \ | 
 | 292 | "	  ;;\n"								      \ | 
 | 293 | "	}\n"								      \ | 
 | 294 | "	{ .mfb\n"							      \ | 
 | 295 | "	  br.sptk.many b6\n"						      \ | 
 | 296 | "	  ;;\n"								      \ | 
 | 297 | "	}\n"								      \ | 
 | 298 | "	.endp _dl_start_user#\n"					      \ | 
 | 299 | ".previous\n"); | 
 | 300 |  | 
 | 301 |  | 
 | 302 | #ifndef RTLD_START_SPECIAL_INIT | 
 | 303 | #define RTLD_START_SPECIAL_INIT /* nothing */ | 
 | 304 | #endif | 
 | 305 |  | 
 | 306 | /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or TLS | 
 | 307 |    variable, so undefined references should not be allowed to define the | 
 | 308 |    value. | 
 | 309 |    ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one | 
 | 310 |    of the main executable's symbols, as for a COPY reloc, which we don't | 
 | 311 |    use.  */ | 
 | 312 | /* ??? Ignore *MSB for now.  */ | 
 | 313 | #define elf_machine_type_class(type) \ | 
 | 314 |   (((type) == R_IA64_IPLTLSB || (type) == R_IA64_DTPMOD64LSB		      \ | 
 | 315 |     || (type) == R_IA64_DTPREL64LSB || (type) == R_IA64_TPREL64LSB)	      \ | 
 | 316 |    * ELF_RTYPE_CLASS_PLT) | 
 | 317 |  | 
 | 318 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */ | 
 | 319 | #define ELF_MACHINE_JMP_SLOT	 R_IA64_IPLTLSB | 
 | 320 |  | 
 | 321 | /* According to the IA-64 specific documentation, Rela is always used.  */ | 
 | 322 | #define ELF_MACHINE_NO_REL 1 | 
 | 323 | #define ELF_MACHINE_NO_RELA 0 | 
 | 324 |  | 
 | 325 | /* Return the address of the entry point. */ | 
 | 326 | #define ELF_MACHINE_START_ADDRESS(map, start)			\ | 
 | 327 | ({								\ | 
 | 328 | 	ElfW(Addr) addr;					\ | 
 | 329 | 	DL_DT_FUNCTION_ADDRESS(map, start, static, addr)	\ | 
 | 330 | 	addr;							\ | 
 | 331 | }) | 
 | 332 |  | 
 | 333 | /* Fixup a PLT entry to bounce directly to the function at VALUE.  */ | 
 | 334 | static inline struct fdesc __attribute__ ((always_inline)) | 
 | 335 | elf_machine_fixup_plt (struct link_map *l, lookup_t t, | 
 | 336 | 		       const Elf64_Rela *reloc, | 
 | 337 | 		       Elf64_Addr *reloc_addr, struct fdesc value) | 
 | 338 | { | 
 | 339 |   /* l is the link_map for the caller, t is the link_map for the object | 
 | 340 |    * being called */ | 
 | 341 |   /* got has already been relocated in elf_get_dynamic_info() */ | 
 | 342 |   reloc_addr[1] = value.gp; | 
 | 343 |   /* we need a "release" here to ensure that the gp is visible before | 
 | 344 |      the code entry point is updated: */ | 
 | 345 |   ((volatile Elf64_Addr *) reloc_addr)[0] = value.ip; | 
 | 346 |   return value; | 
 | 347 | } | 
 | 348 |  | 
 | 349 | /* Return the final value of a plt relocation.  */ | 
 | 350 | static inline struct fdesc | 
 | 351 | elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, | 
 | 352 | 		       struct fdesc value) | 
 | 353 | { | 
 | 354 |   /* No need to handle rel vs rela since IA64 is rela only */ | 
 | 355 |   return (struct fdesc) { value.ip + reloc->r_addend, value.gp }; | 
 | 356 | } | 
 | 357 |  | 
 | 358 | #endif /* !dl_machine_h */ | 
 | 359 |  | 
 | 360 | #ifdef RESOLVE_MAP | 
 | 361 |  | 
 | 362 | #define R_IA64_TYPE(R)	 ((R) & -8) | 
 | 363 | #define R_IA64_FORMAT(R) ((R) & 7) | 
 | 364 |  | 
 | 365 | #define R_IA64_FORMAT_32MSB	4 | 
 | 366 | #define R_IA64_FORMAT_32LSB	5 | 
 | 367 | #define R_IA64_FORMAT_64MSB	6 | 
 | 368 | #define R_IA64_FORMAT_64LSB	7 | 
 | 369 |  | 
 | 370 |  | 
 | 371 | /* Perform the relocation specified by RELOC and SYM (which is fully | 
 | 372 |    resolved).  MAP is the object containing the reloc.  */ | 
 | 373 | auto inline void | 
 | 374 | __attribute ((always_inline)) | 
 | 375 | elf_machine_rela (struct link_map *map, | 
 | 376 | 		  const Elf64_Rela *reloc, | 
 | 377 | 		  const Elf64_Sym *sym, | 
 | 378 | 		  const struct r_found_version *version, | 
 | 379 | 		  void *const reloc_addr_arg, | 
 | 380 | 		  int skip_ifunc) | 
 | 381 | { | 
 | 382 |   Elf64_Addr *const reloc_addr = reloc_addr_arg; | 
 | 383 |   const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info); | 
 | 384 |   Elf64_Addr value; | 
 | 385 |  | 
 | 386 | #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED | 
 | 387 |   /* This is defined in rtld.c, but nowhere in the static libc.a; make the | 
 | 388 |      reference weak so static programs can still link.  This declaration | 
 | 389 |      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP) | 
 | 390 |      because rtld.c contains the common defn for _dl_rtld_map, which is | 
 | 391 |      incompatible with a weak decl in the same file.  */ | 
 | 392 |   weak_extern (_dl_rtld_map); | 
 | 393 | #endif | 
 | 394 |  | 
 | 395 |   /* We cannot use a switch here because we cannot locate the switch | 
 | 396 |      jump table until we've self-relocated.  */ | 
 | 397 |  | 
 | 398 | #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC | 
 | 399 |   if (__builtin_expect (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_REL64LSB), | 
 | 400 | 			0)) | 
 | 401 |     { | 
 | 402 |       assert (ELF64_R_TYPE (reloc->r_info) == R_IA64_REL64LSB); | 
 | 403 |       value = *reloc_addr; | 
 | 404 | # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC | 
 | 405 |       /* Already done in dynamic linker.  */ | 
 | 406 |       if (map != &GL(dl_rtld_map)) | 
 | 407 | # endif | 
 | 408 | 	value += map->l_addr; | 
 | 409 |     } | 
 | 410 |   else | 
 | 411 | #endif | 
 | 412 |     if (__builtin_expect (r_type == R_IA64_NONE, 0)) | 
 | 413 |       return; | 
 | 414 |   else | 
 | 415 |     { | 
 | 416 |       struct link_map *sym_map; | 
 | 417 |  | 
 | 418 |       /* RESOLVE_MAP() will return NULL if it fail to locate the symbol.  */ | 
 | 419 |       if ((sym_map = RESOLVE_MAP (&sym, version, r_type))) | 
 | 420 | 	{ | 
 | 421 | 	  value = sym_map->l_addr + sym->st_value + reloc->r_addend; | 
 | 422 |  | 
 | 423 | 	  if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DIR64LSB)) | 
 | 424 | 	    ;/* No adjustment.  */ | 
 | 425 | 	  else if (r_type == R_IA64_IPLTLSB) | 
 | 426 | 	    { | 
 | 427 | 	      elf_machine_fixup_plt (NULL, NULL, reloc, reloc_addr, | 
 | 428 | 				     DL_FIXUP_MAKE_VALUE (sym_map, value)); | 
 | 429 | 	      return; | 
 | 430 | 	    } | 
 | 431 | 	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_FPTR64LSB)) | 
 | 432 | 	    value = _dl_make_fptr (sym_map, sym, value); | 
 | 433 | 	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_PCREL64LSB)) | 
 | 434 | 	    value -= (Elf64_Addr) reloc_addr & -16; | 
 | 435 | 	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPMOD64LSB)) | 
 | 436 | #ifdef RTLD_BOOTSTRAP | 
 | 437 | 	    /* During startup the dynamic linker is always index 1.  */ | 
 | 438 | 	    value = 1; | 
 | 439 | #else | 
 | 440 | 	    /* Get the information from the link map returned by the | 
 | 441 | 	       resolv function.  */ | 
 | 442 | 	    value = sym_map->l_tls_modid; | 
 | 443 | 	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPREL64LSB)) | 
 | 444 | 	    value -= sym_map->l_addr; | 
 | 445 | #endif | 
 | 446 | 	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_TPREL64LSB)) | 
 | 447 | 	    { | 
 | 448 | #ifndef RTLD_BOOTSTRAP | 
 | 449 | 	      CHECK_STATIC_TLS (map, sym_map); | 
 | 450 | #endif | 
 | 451 | 	      value += sym_map->l_tls_offset - sym_map->l_addr; | 
 | 452 | 	    } | 
 | 453 | 	  else | 
 | 454 | 	    _dl_reloc_bad_type (map, r_type, 0); | 
 | 455 | 	} | 
 | 456 |       else | 
 | 457 | 	value = 0; | 
 | 458 |     } | 
 | 459 |  | 
 | 460 |   /* ??? Ignore MSB and Instruction format for now.  */ | 
 | 461 |   if (R_IA64_FORMAT (r_type) == R_IA64_FORMAT_64LSB) | 
 | 462 |     *reloc_addr = value; | 
 | 463 |   else if (R_IA64_FORMAT (r_type) == R_IA64_FORMAT_32LSB) | 
 | 464 |     *(int *) reloc_addr = value; | 
 | 465 |   else if (r_type == R_IA64_IPLTLSB) | 
 | 466 |     { | 
 | 467 |       reloc_addr[0] = 0; | 
 | 468 |       reloc_addr[1] = 0; | 
 | 469 |     } | 
 | 470 |   else | 
 | 471 |     _dl_reloc_bad_type (map, r_type, 0); | 
 | 472 | } | 
 | 473 |  | 
 | 474 | /* Let do-rel.h know that on IA-64 if l_addr is 0, all RELATIVE relocs | 
 | 475 |    can be skipped.  */ | 
 | 476 | #define ELF_MACHINE_REL_RELATIVE 1 | 
 | 477 |  | 
 | 478 | auto inline void | 
 | 479 | __attribute ((always_inline)) | 
 | 480 | elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, | 
 | 481 | 			   void *const reloc_addr_arg) | 
 | 482 | { | 
 | 483 |   Elf64_Addr *const reloc_addr = reloc_addr_arg; | 
 | 484 |   /* ??? Ignore MSB and Instruction format for now.  */ | 
 | 485 |   assert (ELF64_R_TYPE (reloc->r_info) == R_IA64_REL64LSB); | 
 | 486 |  | 
 | 487 |   *reloc_addr += l_addr; | 
 | 488 | } | 
 | 489 |  | 
 | 490 | /* Perform a RELATIVE reloc on the .got entry that transfers to the .plt.  */ | 
 | 491 | auto inline void | 
 | 492 | __attribute ((always_inline)) | 
 | 493 | elf_machine_lazy_rel (struct link_map *map, | 
 | 494 | 		      Elf64_Addr l_addr, const Elf64_Rela *reloc, | 
 | 495 | 		      int skip_ifunc) | 
 | 496 | { | 
 | 497 |   Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset); | 
 | 498 |   const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info); | 
 | 499 |  | 
 | 500 |   if (r_type == R_IA64_IPLTLSB) | 
 | 501 |     { | 
 | 502 |       reloc_addr[0] += l_addr; | 
 | 503 |       reloc_addr[1] += l_addr; | 
 | 504 |     } | 
 | 505 |   else if (r_type == R_IA64_NONE) | 
 | 506 |     return; | 
 | 507 |   else | 
 | 508 |     _dl_reloc_bad_type (map, r_type, 1); | 
 | 509 | } | 
 | 510 |  | 
 | 511 | #endif /* RESOLVE_MAP */ |