| 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 */ |