| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Machine-dependent ELF dynamic relocation inline functions.  Alpha version. | 
|  | 2 | Copyright (C) 1996-2016 Free Software Foundation, Inc. | 
|  | 3 | This file is part of the GNU C Library. | 
|  | 4 | Contributed by Richard Henderson <rth@tamu.edu>. | 
|  | 5 |  | 
|  | 6 | The GNU C Library is free software; you can redistribute it and/or | 
|  | 7 | modify it under the terms of the GNU Lesser General Public | 
|  | 8 | License as published by the Free Software Foundation; either | 
|  | 9 | version 2.1 of the License, or (at your option) any later version. | 
|  | 10 |  | 
|  | 11 | The GNU C Library is distributed in the hope that it will be useful, | 
|  | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 14 | Lesser General Public License for more details. | 
|  | 15 |  | 
|  | 16 | You should have received a copy of the GNU Lesser General Public | 
|  | 17 | License along with the GNU C Library.  If not, see | 
|  | 18 | <http://www.gnu.org/licenses/>.  */ | 
|  | 19 |  | 
|  | 20 | /* This was written in the absence of an ABI -- don't expect | 
|  | 21 | it to remain unchanged.  */ | 
|  | 22 |  | 
|  | 23 | #ifndef dl_machine_h | 
|  | 24 | #define dl_machine_h 1 | 
|  | 25 |  | 
|  | 26 | #define ELF_MACHINE_NAME "alpha" | 
|  | 27 |  | 
|  | 28 | #include <string.h> | 
|  | 29 |  | 
|  | 30 |  | 
|  | 31 | /* Mask identifying addresses reserved for the user program, | 
|  | 32 | where the dynamic linker should not map anything.  */ | 
|  | 33 | #define ELF_MACHINE_USER_ADDRESS_MASK	0x120000000UL | 
|  | 34 |  | 
|  | 35 | /* Translate a processor specific dynamic tag to the index in l_info array.  */ | 
|  | 36 | #define DT_ALPHA(x) (DT_ALPHA_##x - DT_LOPROC + DT_NUM) | 
|  | 37 |  | 
|  | 38 | /* Return nonzero iff ELF header is compatible with the running host.  */ | 
|  | 39 | static inline int | 
|  | 40 | elf_machine_matches_host (const Elf64_Ehdr *ehdr) | 
|  | 41 | { | 
|  | 42 | return ehdr->e_machine == EM_ALPHA; | 
|  | 43 | } | 
|  | 44 |  | 
|  | 45 | /* Return the link-time address of _DYNAMIC.  The multiple-got-capable | 
|  | 46 | linker no longer allocates the first .got entry for this.  But not to | 
|  | 47 | worry, no special tricks are needed.  */ | 
|  | 48 | static inline Elf64_Addr | 
|  | 49 | elf_machine_dynamic (void) | 
|  | 50 | { | 
|  | 51 | #ifndef NO_AXP_MULTI_GOT_LD | 
|  | 52 | return (Elf64_Addr) &_DYNAMIC; | 
|  | 53 | #else | 
|  | 54 | register Elf64_Addr *gp __asm__ ("$29"); | 
|  | 55 | return gp[-4096]; | 
|  | 56 | #endif | 
|  | 57 | } | 
|  | 58 |  | 
|  | 59 | /* Return the run-time load address of the shared object.  */ | 
|  | 60 |  | 
|  | 61 | static inline Elf64_Addr | 
|  | 62 | elf_machine_load_address (void) | 
|  | 63 | { | 
|  | 64 | /* This relies on the compiler using gp-relative addresses for static symbols.  */ | 
|  | 65 | static void *dot = ˙ | 
|  | 66 | return (void *)&dot - dot; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | /* Set up the loaded object described by L so its unrelocated PLT | 
|  | 70 | entries will jump to the on-demand fixup code in dl-runtime.c.  */ | 
|  | 71 |  | 
|  | 72 | static inline int | 
|  | 73 | elf_machine_runtime_setup (struct link_map *map, int lazy, int profile) | 
|  | 74 | { | 
|  | 75 | extern char _dl_runtime_resolve_new[] attribute_hidden; | 
|  | 76 | extern char _dl_runtime_profile_new[] attribute_hidden; | 
|  | 77 | extern char _dl_runtime_resolve_old[] attribute_hidden; | 
|  | 78 | extern char _dl_runtime_profile_old[] attribute_hidden; | 
|  | 79 |  | 
|  | 80 | struct pltgot { | 
|  | 81 | char *resolve; | 
|  | 82 | struct link_map *link; | 
|  | 83 | }; | 
|  | 84 |  | 
|  | 85 | struct pltgot *pg; | 
|  | 86 | long secureplt; | 
|  | 87 | char *resolve; | 
|  | 88 |  | 
|  | 89 | if (map->l_info[DT_JMPREL] == 0 || !lazy) | 
|  | 90 | return lazy; | 
|  | 91 |  | 
|  | 92 | /* Check to see if we're using the read-only plt form.  */ | 
|  | 93 | secureplt = map->l_info[DT_ALPHA(PLTRO)] != 0; | 
|  | 94 |  | 
|  | 95 | /* If the binary uses the read-only secure plt format, PG points to | 
|  | 96 | the .got.plt section, which is the right place for ld.so to place | 
|  | 97 | its hooks.  Otherwise, PG is currently pointing at the start of | 
|  | 98 | the plt; the hooks go at offset 16.  */ | 
|  | 99 | pg = (struct pltgot *) D_PTR (map, l_info[DT_PLTGOT]); | 
|  | 100 | pg += !secureplt; | 
|  | 101 |  | 
|  | 102 | /* This function will be called to perform the relocation.  They're | 
|  | 103 | not declared as functions to convince the compiler to use gp | 
|  | 104 | relative relocations for them.  */ | 
|  | 105 | if (secureplt) | 
|  | 106 | resolve = _dl_runtime_resolve_new; | 
|  | 107 | else | 
|  | 108 | resolve = _dl_runtime_resolve_old; | 
|  | 109 |  | 
|  | 110 | if (__builtin_expect (profile, 0)) | 
|  | 111 | { | 
|  | 112 | if (secureplt) | 
|  | 113 | resolve = _dl_runtime_profile_new; | 
|  | 114 | else | 
|  | 115 | resolve = _dl_runtime_profile_old; | 
|  | 116 |  | 
|  | 117 | if (GLRO(dl_profile) && _dl_name_match_p (GLRO(dl_profile), map)) | 
|  | 118 | { | 
|  | 119 | /* This is the object we are looking for.  Say that we really | 
|  | 120 | want profiling and the timers are started.  */ | 
|  | 121 | GL(dl_profile_map) = map; | 
|  | 122 | } | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | pg->resolve = resolve; | 
|  | 126 | pg->link = map; | 
|  | 127 |  | 
|  | 128 | return lazy; | 
|  | 129 | } | 
|  | 130 |  | 
|  | 131 | /* Initial entry point code for the dynamic linker. | 
|  | 132 | The C function `_dl_start' is the real entry point; | 
|  | 133 | its return value is the user program's entry point.  */ | 
|  | 134 |  | 
|  | 135 | #define RTLD_START asm ("\ | 
|  | 136 | .section .text						\n\ | 
|  | 137 | .set at							\n\ | 
|  | 138 | .globl _start						\n\ | 
|  | 139 | .ent _start						\n\ | 
|  | 140 | _start:								\n\ | 
|  | 141 | .frame $31,0,$31,0					\n\ | 
|  | 142 | br	$gp, 0f						\n\ | 
|  | 143 | 0:	ldgp	$gp, 0($gp)					\n\ | 
|  | 144 | .prologue 0						\n\ | 
|  | 145 | /* Pass pointer to argument block to _dl_start.  */	\n\ | 
|  | 146 | mov	$sp, $16					\n\ | 
|  | 147 | bsr	$26, _dl_start		!samegp			\n\ | 
|  | 148 | .end _start						\n\ | 
|  | 149 | /* FALLTHRU */						\n\ | 
|  | 150 | .globl _dl_start_user					\n\ | 
|  | 151 | .ent _dl_start_user					\n\ | 
|  | 152 | _dl_start_user:							\n\ | 
|  | 153 | .frame $31,0,$31,0					\n\ | 
|  | 154 | .prologue 0						\n\ | 
|  | 155 | /* Save the user entry point address in s0.  */		\n\ | 
|  | 156 | mov	$0, $9						\n\ | 
|  | 157 | /* See if we were run as a command with the executable	\n\ | 
|  | 158 | file name as an extra leading argument.  */		\n\ | 
|  | 159 | ldah	$1, _dl_skip_args($gp)	!gprelhigh		\n\ | 
|  | 160 | ldl	$1, _dl_skip_args($1)	!gprellow		\n\ | 
|  | 161 | bne	$1, $fixup_stack				\n\ | 
|  | 162 | $fixup_stack_ret:						\n\ | 
|  | 163 | /* The special initializer gets called with the stack	\n\ | 
|  | 164 | just as the application's entry point will see it;	\n\ | 
|  | 165 | it can switch stacks if it moves these contents	\n\ | 
|  | 166 | over.  */						\n\ | 
|  | 167 | " RTLD_START_SPECIAL_INIT "					\n\ | 
|  | 168 | /* Call _dl_init(_dl_loaded, argc, argv, envp) to run	\n\ | 
|  | 169 | initializers.  */					\n\ | 
|  | 170 | ldah	$16, _rtld_local($gp)	!gprelhigh		\n\ | 
|  | 171 | ldq	$16, _rtld_local($16)	!gprellow		\n\ | 
|  | 172 | ldq	$17, 0($sp)					\n\ | 
|  | 173 | lda	$18, 8($sp)					\n\ | 
|  | 174 | s8addq	$17, 8, $19					\n\ | 
|  | 175 | addq	$19, $18, $19					\n\ | 
|  | 176 | bsr	$26, _dl_init		!samegp			\n\ | 
|  | 177 | /* Pass our finalizer function to the user in $0. */	\n\ | 
|  | 178 | ldah	$0, _dl_fini($gp)	!gprelhigh		\n\ | 
|  | 179 | lda	$0, _dl_fini($0)	!gprellow		\n\ | 
|  | 180 | /* Jump to the user's entry point.  */			\n\ | 
|  | 181 | mov	$9, $27						\n\ | 
|  | 182 | jmp	($9)						\n\ | 
|  | 183 | $fixup_stack:							\n\ | 
|  | 184 | /* Adjust the stack pointer to skip _dl_skip_args words.\n\ | 
|  | 185 | This involves copying everything down, since the	\n\ | 
|  | 186 | stack pointer must always be 16-byte aligned.  */	\n\ | 
|  | 187 | ldah	$7, __GI__dl_argv($gp) !gprelhigh		\n\ | 
|  | 188 | ldq	$2, 0($sp)					\n\ | 
|  | 189 | ldq	$5, __GI__dl_argv($7) !gprellow			\n\ | 
|  | 190 | subq	$31, $1, $6					\n\ | 
|  | 191 | subq	$2, $1, $2					\n\ | 
|  | 192 | s8addq	$6, $5, $5					\n\ | 
|  | 193 | mov	$sp, $4						\n\ | 
|  | 194 | s8addq	$1, $sp, $3					\n\ | 
|  | 195 | stq	$2, 0($sp)					\n\ | 
|  | 196 | stq	$5, __GI__dl_argv($7) !gprellow			\n\ | 
|  | 197 | /* Copy down argv.  */					\n\ | 
|  | 198 | 0:	ldq	$5, 8($3)					\n\ | 
|  | 199 | addq	$4, 8, $4					\n\ | 
|  | 200 | addq	$3, 8, $3					\n\ | 
|  | 201 | stq	$5, 0($4)					\n\ | 
|  | 202 | bne	$5, 0b						\n\ | 
|  | 203 | /* Copy down envp.  */					\n\ | 
|  | 204 | 1:	ldq	$5, 8($3)					\n\ | 
|  | 205 | addq	$4, 8, $4					\n\ | 
|  | 206 | addq	$3, 8, $3					\n\ | 
|  | 207 | stq	$5, 0($4)					\n\ | 
|  | 208 | bne	$5, 1b						\n\ | 
|  | 209 | /* Copy down auxiliary table.  */			\n\ | 
|  | 210 | 2:	ldq	$5, 8($3)					\n\ | 
|  | 211 | ldq	$6, 16($3)					\n\ | 
|  | 212 | addq	$4, 16, $4					\n\ | 
|  | 213 | addq	$3, 16, $3					\n\ | 
|  | 214 | stq	$5, -8($4)					\n\ | 
|  | 215 | stq	$6, 0($4)					\n\ | 
|  | 216 | bne	$5, 2b						\n\ | 
|  | 217 | br	$fixup_stack_ret				\n\ | 
|  | 218 | .end _dl_start_user					\n\ | 
|  | 219 | .set noat						\n\ | 
|  | 220 | .previous"); | 
|  | 221 |  | 
|  | 222 | #ifndef RTLD_START_SPECIAL_INIT | 
|  | 223 | #define RTLD_START_SPECIAL_INIT /* nothing */ | 
|  | 224 | #endif | 
|  | 225 |  | 
|  | 226 | /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry | 
|  | 227 | or TLS variables, so undefined references should not be allowed | 
|  | 228 | to define the value. | 
|  | 229 |  | 
|  | 230 | ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve | 
|  | 231 | to one of the main executable's symbols, as for a COPY reloc. | 
|  | 232 | This is unused on Alpha.  */ | 
|  | 233 |  | 
|  | 234 | # define elf_machine_type_class(type)	\ | 
|  | 235 | (((type) == R_ALPHA_JMP_SLOT		\ | 
|  | 236 | || (type) == R_ALPHA_DTPMOD64	\ | 
|  | 237 | || (type) == R_ALPHA_DTPREL64	\ | 
|  | 238 | || (type) == R_ALPHA_TPREL64) * ELF_RTYPE_CLASS_PLT) | 
|  | 239 |  | 
|  | 240 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */ | 
|  | 241 | #define ELF_MACHINE_JMP_SLOT	 R_ALPHA_JMP_SLOT | 
|  | 242 |  | 
|  | 243 | /* The alpha never uses Elf64_Rel relocations.  */ | 
|  | 244 | #define ELF_MACHINE_NO_REL 1 | 
|  | 245 | #define ELF_MACHINE_NO_RELA 0 | 
|  | 246 |  | 
|  | 247 | /* We define an initialization functions.  This is called very early in | 
|  | 248 | *    _dl_sysdep_start.  */ | 
|  | 249 | #define DL_PLATFORM_INIT dl_platform_init () | 
|  | 250 |  | 
|  | 251 | static inline void __attribute__ ((unused)) | 
|  | 252 | dl_platform_init (void) | 
|  | 253 | { | 
|  | 254 | if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') | 
|  | 255 | /* Avoid an empty string which would disturb us.  */ | 
|  | 256 | GLRO(dl_platform) = NULL; | 
|  | 257 | } | 
|  | 258 |  | 
|  | 259 | /* Fix up the instructions of a PLT entry to invoke the function | 
|  | 260 | rather than the dynamic linker.  */ | 
|  | 261 | static inline Elf64_Addr | 
|  | 262 | elf_machine_fixup_plt (struct link_map *map, lookup_t t, | 
|  | 263 | const Elf64_Rela *reloc, | 
|  | 264 | Elf64_Addr *got_addr, Elf64_Addr value) | 
|  | 265 | { | 
|  | 266 | const Elf64_Rela *rela_plt; | 
|  | 267 | Elf64_Word *plte; | 
|  | 268 | long int edisp; | 
|  | 269 |  | 
|  | 270 | /* Store the value we are going to load.  */ | 
|  | 271 | *got_addr = value; | 
|  | 272 |  | 
|  | 273 | /* If this binary uses the read-only secure plt format, we're done.  */ | 
|  | 274 | if (map->l_info[DT_ALPHA(PLTRO)]) | 
|  | 275 | return value; | 
|  | 276 |  | 
|  | 277 | /* Otherwise we have to modify the plt entry in place to do the branch.  */ | 
|  | 278 |  | 
|  | 279 | /* Recover the PLT entry address by calculating reloc's index into the | 
|  | 280 | .rela.plt, and finding that entry in the .plt.  */ | 
|  | 281 | rela_plt = (const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]); | 
|  | 282 | plte = (Elf64_Word *) (D_PTR (map, l_info[DT_PLTGOT]) + 32); | 
|  | 283 | plte += 3 * (reloc - rela_plt); | 
|  | 284 |  | 
|  | 285 | /* Find the displacement from the plt entry to the function.  */ | 
|  | 286 | edisp = (long int) (value - (Elf64_Addr)&plte[3]) / 4; | 
|  | 287 |  | 
|  | 288 | if (edisp >= -0x100000 && edisp < 0x100000) | 
|  | 289 | { | 
|  | 290 | /* If we are in range, use br to perfect branch prediction and | 
|  | 291 | elide the dependency on the address load.  This case happens, | 
|  | 292 | e.g., when a shared library call is resolved to the same library.  */ | 
|  | 293 |  | 
|  | 294 | int hi, lo; | 
|  | 295 | hi = value - (Elf64_Addr)&plte[0]; | 
|  | 296 | lo = (short int) hi; | 
|  | 297 | hi = (hi - lo) >> 16; | 
|  | 298 |  | 
|  | 299 | /* Emit "lda $27,lo($27)" */ | 
|  | 300 | plte[1] = 0x237b0000 | (lo & 0xffff); | 
|  | 301 |  | 
|  | 302 | /* Emit "br $31,function" */ | 
|  | 303 | plte[2] = 0xc3e00000 | (edisp & 0x1fffff); | 
|  | 304 |  | 
|  | 305 | /* Think about thread-safety -- the previous instructions must be | 
|  | 306 | committed to memory before the first is overwritten.  */ | 
|  | 307 | __asm__ __volatile__("wmb" : : : "memory"); | 
|  | 308 |  | 
|  | 309 | /* Emit "ldah $27,hi($27)" */ | 
|  | 310 | plte[0] = 0x277b0000 | (hi & 0xffff); | 
|  | 311 | } | 
|  | 312 | else | 
|  | 313 | { | 
|  | 314 | /* Don't bother with the hint since we already know the hint is | 
|  | 315 | wrong.  Eliding it prevents the wrong page from getting pulled | 
|  | 316 | into the cache.  */ | 
|  | 317 |  | 
|  | 318 | int hi, lo; | 
|  | 319 | hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0]; | 
|  | 320 | lo = (short)hi; | 
|  | 321 | hi = (hi - lo) >> 16; | 
|  | 322 |  | 
|  | 323 | /* Emit "ldq $27,lo($27)" */ | 
|  | 324 | plte[1] = 0xa77b0000 | (lo & 0xffff); | 
|  | 325 |  | 
|  | 326 | /* Emit "jmp $31,($27)" */ | 
|  | 327 | plte[2] = 0x6bfb0000; | 
|  | 328 |  | 
|  | 329 | /* Think about thread-safety -- the previous instructions must be | 
|  | 330 | committed to memory before the first is overwritten.  */ | 
|  | 331 | __asm__ __volatile__("wmb" : : : "memory"); | 
|  | 332 |  | 
|  | 333 | /* Emit "ldah $27,hi($27)" */ | 
|  | 334 | plte[0] = 0x277b0000 | (hi & 0xffff); | 
|  | 335 | } | 
|  | 336 |  | 
|  | 337 | /* At this point, if we've been doing runtime resolution, Icache is dirty. | 
|  | 338 | This will be taken care of in _dl_runtime_resolve.  If instead we are | 
|  | 339 | doing this as part of non-lazy startup relocation, that bit of code | 
|  | 340 | hasn't made it into Icache yet, so there's nothing to clean up.  */ | 
|  | 341 |  | 
|  | 342 | return value; | 
|  | 343 | } | 
|  | 344 |  | 
|  | 345 | /* Return the final value of a plt relocation.  */ | 
|  | 346 | static inline Elf64_Addr | 
|  | 347 | elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, | 
|  | 348 | Elf64_Addr value) | 
|  | 349 | { | 
|  | 350 | return value + reloc->r_addend; | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | /* Names of the architecture-specific auditing callback functions.  */ | 
|  | 354 | #define ARCH_LA_PLTENTER	alpha_gnu_pltenter | 
|  | 355 | #define ARCH_LA_PLTEXIT		alpha_gnu_pltexit | 
|  | 356 |  | 
|  | 357 | #endif /* !dl_machine_h */ | 
|  | 358 |  | 
|  | 359 | #ifdef RESOLVE_MAP | 
|  | 360 |  | 
|  | 361 | /* Perform the relocation specified by RELOC and SYM (which is fully resolved). | 
|  | 362 | MAP is the object containing the reloc.  */ | 
|  | 363 | auto inline void | 
|  | 364 | __attribute__ ((always_inline)) | 
|  | 365 | elf_machine_rela (struct link_map *map, | 
|  | 366 | const Elf64_Rela *reloc, | 
|  | 367 | const Elf64_Sym *sym, | 
|  | 368 | const struct r_found_version *version, | 
|  | 369 | void *const reloc_addr_arg, | 
|  | 370 | int skip_ifunc) | 
|  | 371 | { | 
|  | 372 | Elf64_Addr *const reloc_addr = reloc_addr_arg; | 
|  | 373 | unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info); | 
|  | 374 |  | 
|  | 375 | #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED | 
|  | 376 | /* This is defined in rtld.c, but nowhere in the static libc.a; make the | 
|  | 377 | reference weak so static programs can still link.  This declaration | 
|  | 378 | cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP) | 
|  | 379 | because rtld.c contains the common defn for _dl_rtld_map, which is | 
|  | 380 | incompatible with a weak decl in the same file.  */ | 
|  | 381 | weak_extern (_dl_rtld_map); | 
|  | 382 | #endif | 
|  | 383 |  | 
|  | 384 | /* We cannot use a switch here because we cannot locate the switch | 
|  | 385 | jump table until we've self-relocated.  */ | 
|  | 386 |  | 
|  | 387 | #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC | 
|  | 388 | if (__builtin_expect (r_type == R_ALPHA_RELATIVE, 0)) | 
|  | 389 | { | 
|  | 390 | # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC | 
|  | 391 | /* Already done in dynamic linker.  */ | 
|  | 392 | if (map != &GL(dl_rtld_map)) | 
|  | 393 | # endif | 
|  | 394 | { | 
|  | 395 | /* XXX Make some timings.  Maybe it's preferable to test for | 
|  | 396 | unaligned access and only do it the complex way if necessary.  */ | 
|  | 397 | Elf64_Addr reloc_addr_val; | 
|  | 398 |  | 
|  | 399 | /* Load value without causing unaligned trap. */ | 
|  | 400 | memcpy (&reloc_addr_val, reloc_addr_arg, 8); | 
|  | 401 | reloc_addr_val += map->l_addr; | 
|  | 402 |  | 
|  | 403 | /* Store value without causing unaligned trap. */ | 
|  | 404 | memcpy (reloc_addr_arg, &reloc_addr_val, 8); | 
|  | 405 | } | 
|  | 406 | } | 
|  | 407 | else | 
|  | 408 | #endif | 
|  | 409 | if (__builtin_expect (r_type == R_ALPHA_NONE, 0)) | 
|  | 410 | return; | 
|  | 411 | else | 
|  | 412 | { | 
|  | 413 | struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); | 
|  | 414 | Elf64_Addr sym_value; | 
|  | 415 | Elf64_Addr sym_raw_value; | 
|  | 416 |  | 
|  | 417 | sym_raw_value = sym_value = reloc->r_addend; | 
|  | 418 | if (sym_map) | 
|  | 419 | { | 
|  | 420 | sym_raw_value += sym->st_value; | 
|  | 421 | sym_value = sym_raw_value + sym_map->l_addr; | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | if (r_type == R_ALPHA_GLOB_DAT) | 
|  | 425 | *reloc_addr = sym_value; | 
|  | 426 | #ifdef RESOLVE_CONFLICT_FIND_MAP | 
|  | 427 | /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have | 
|  | 428 | R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits | 
|  | 429 | are .rela.plt index.  */ | 
|  | 430 | else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT) | 
|  | 431 | { | 
|  | 432 | /* elf_machine_fixup_plt needs the map reloc_addr points into, | 
|  | 433 | while in _dl_resolve_conflicts map is _dl_loaded.  */ | 
|  | 434 | RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr); | 
|  | 435 | reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL])) | 
|  | 436 | + (r_type >> 8); | 
|  | 437 | elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value); | 
|  | 438 | } | 
|  | 439 | #else | 
|  | 440 | else if (r_type == R_ALPHA_JMP_SLOT) | 
|  | 441 | elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value); | 
|  | 442 | #endif | 
|  | 443 | #ifndef RTLD_BOOTSTRAP | 
|  | 444 | else if (r_type == R_ALPHA_REFQUAD) | 
|  | 445 | { | 
|  | 446 | /* Store value without causing unaligned trap.  */ | 
|  | 447 | memcpy (reloc_addr_arg, &sym_value, 8); | 
|  | 448 | } | 
|  | 449 | #endif | 
|  | 450 | else if (r_type == R_ALPHA_DTPMOD64) | 
|  | 451 | { | 
|  | 452 | # ifdef RTLD_BOOTSTRAP | 
|  | 453 | /* During startup the dynamic linker is always index 1.  */ | 
|  | 454 | *reloc_addr = 1; | 
|  | 455 | # else | 
|  | 456 | /* Get the information from the link map returned by the | 
|  | 457 | resolv function.  */ | 
|  | 458 | if (sym_map != NULL) | 
|  | 459 | *reloc_addr = sym_map->l_tls_modid; | 
|  | 460 | # endif | 
|  | 461 | } | 
|  | 462 | else if (r_type == R_ALPHA_DTPREL64) | 
|  | 463 | { | 
|  | 464 | # ifndef RTLD_BOOTSTRAP | 
|  | 465 | /* During relocation all TLS symbols are defined and used. | 
|  | 466 | Therefore the offset is already correct.  */ | 
|  | 467 | *reloc_addr = sym_raw_value; | 
|  | 468 | # endif | 
|  | 469 | } | 
|  | 470 | else if (r_type == R_ALPHA_TPREL64) | 
|  | 471 | { | 
|  | 472 | # ifdef RTLD_BOOTSTRAP | 
|  | 473 | *reloc_addr = sym_raw_value + map->l_tls_offset; | 
|  | 474 | # else | 
|  | 475 | if (sym_map) | 
|  | 476 | { | 
|  | 477 | CHECK_STATIC_TLS (map, sym_map); | 
|  | 478 | *reloc_addr = sym_raw_value + sym_map->l_tls_offset; | 
|  | 479 | } | 
|  | 480 | # endif | 
|  | 481 | } | 
|  | 482 | else | 
|  | 483 | _dl_reloc_bad_type (map, r_type, 0); | 
|  | 484 | } | 
|  | 485 | } | 
|  | 486 |  | 
|  | 487 | /* Let do-rel.h know that on Alpha if l_addr is 0, all RELATIVE relocs | 
|  | 488 | can be skipped.  */ | 
|  | 489 | #define ELF_MACHINE_REL_RELATIVE 1 | 
|  | 490 |  | 
|  | 491 | auto inline void | 
|  | 492 | __attribute__ ((always_inline)) | 
|  | 493 | elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, | 
|  | 494 | void *const reloc_addr_arg) | 
|  | 495 | { | 
|  | 496 | /* XXX Make some timings.  Maybe it's preferable to test for | 
|  | 497 | unaligned access and only do it the complex way if necessary.  */ | 
|  | 498 | Elf64_Addr reloc_addr_val; | 
|  | 499 |  | 
|  | 500 | /* Load value without causing unaligned trap. */ | 
|  | 501 | memcpy (&reloc_addr_val, reloc_addr_arg, 8); | 
|  | 502 | reloc_addr_val += l_addr; | 
|  | 503 |  | 
|  | 504 | /* Store value without causing unaligned trap. */ | 
|  | 505 | memcpy (reloc_addr_arg, &reloc_addr_val, 8); | 
|  | 506 | } | 
|  | 507 |  | 
|  | 508 | auto inline void | 
|  | 509 | __attribute__ ((always_inline)) | 
|  | 510 | elf_machine_lazy_rel (struct link_map *map, | 
|  | 511 | Elf64_Addr l_addr, const Elf64_Rela *reloc, | 
|  | 512 | int skip_ifunc) | 
|  | 513 | { | 
|  | 514 | Elf64_Addr * const reloc_addr = (void *)(l_addr + reloc->r_offset); | 
|  | 515 | unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info); | 
|  | 516 |  | 
|  | 517 | if (r_type == R_ALPHA_JMP_SLOT) | 
|  | 518 | { | 
|  | 519 | /* Perform a RELATIVE reloc on the .got entry that transfers | 
|  | 520 | to the .plt.  */ | 
|  | 521 | *reloc_addr += l_addr; | 
|  | 522 | } | 
|  | 523 | else if (r_type == R_ALPHA_NONE) | 
|  | 524 | return; | 
|  | 525 | else | 
|  | 526 | _dl_reloc_bad_type (map, r_type, 1); | 
|  | 527 | } | 
|  | 528 |  | 
|  | 529 | #endif /* RESOLVE_MAP */ |