lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 1 | /* Machine-dependent ELF dynamic relocation inline functions. IA-64 version. |
| 2 | Copyright (C) 1995-2015 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 */ |