* Versions: Add comment about linuxthreads' frozen ABI.
[glibc.git] / sysdeps / alpha / dl-machine.h
blob7c5f3c151827c973725a7e67b7b097b6b6dfd567
1 /* Machine-dependent ELF dynamic relocation inline functions. Alpha version.
2 Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Richard Henderson <rth@tamu.edu>.
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.
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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 /* This was written in the absence of an ABI -- don't expect
22 it to remain unchanged. */
24 #ifndef dl_machine_h
25 #define dl_machine_h 1
27 #define ELF_MACHINE_NAME "alpha"
29 #include <string.h>
32 /* Mask identifying addresses reserved for the user program,
33 where the dynamic linker should not map anything. */
34 #define ELF_MACHINE_USER_ADDRESS_MASK 0x120000000UL
36 /* Return nonzero iff ELF header is compatible with the running host. */
37 static inline int
38 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
40 return ehdr->e_machine == EM_ALPHA;
43 /* Return the link-time address of _DYNAMIC. The multiple-got-capable
44 linker no longer allocates the first .got entry for this. But not to
45 worry, no special tricks are needed. */
46 static inline Elf64_Addr
47 elf_machine_dynamic (void)
49 #ifndef NO_AXP_MULTI_GOT_LD
50 return (Elf64_Addr) &_DYNAMIC;
51 #else
52 register Elf64_Addr *gp __asm__ ("$29");
53 return gp[-4096];
54 #endif
57 /* Return the run-time load address of the shared object. */
58 static inline Elf64_Addr
59 elf_machine_load_address (void)
61 /* NOTE: While it is generally unfriendly to put data in the text
62 segment, it is only slightly less so when the "data" is an
63 instruction. While we don't have to worry about GLD just yet, an
64 optimizing linker might decide that our "data" is an unreachable
65 instruction and throw it away -- with the right switches, DEC's
66 linker will do this. What ought to happen is we should add
67 something to GAS to allow us access to the new GPREL_HI32/LO32
68 relocation types stolen from OSF/1 3.0. */
69 /* This code relies on the fact that BRADDR relocations do not
70 appear in dynamic relocation tables. Not that that would be very
71 useful anyway -- br/bsr has a 4MB range and the shared libraries
72 are usually many many terabytes away. */
74 Elf64_Addr dot;
75 long int zero_disp;
77 asm("br %0, 1f\n"
78 "0:\n\t"
79 "br $0, 2f\n"
80 "1:\n\t"
81 ".section\t.data\n"
82 "2:\n\t"
83 ".quad 0b\n\t"
84 ".previous"
85 : "=r"(dot));
87 zero_disp = *(int *) dot;
88 zero_disp = (zero_disp << 43) >> 41;
90 return dot - *(Elf64_Addr *) (dot + 4 + zero_disp);
93 /* Set up the loaded object described by L so its unrelocated PLT
94 entries will jump to the on-demand fixup code in dl-runtime.c. */
96 static inline int
97 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
99 Elf64_Addr plt;
100 extern void _dl_runtime_resolve (void);
101 extern void _dl_runtime_profile (void);
103 if (l->l_info[DT_JMPREL] && lazy)
105 /* The GOT entries for the functions in the PLT have not been
106 filled in yet. Their initial contents are directed to the
107 PLT which arranges for the dynamic linker to be called. */
108 plt = D_PTR (l, l_info[DT_PLTGOT]);
110 /* This function will be called to perform the relocation. */
111 if (!profile)
112 *(Elf64_Addr *)(plt + 16) = (Elf64_Addr) &_dl_runtime_resolve;
113 else
115 *(Elf64_Addr *)(plt + 16) = (Elf64_Addr) &_dl_runtime_profile;
117 if (_dl_name_match_p (GLRO(dl_profile), l))
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) = l;
125 /* Identify this shared object */
126 *(Elf64_Addr *)(plt + 24) = (Elf64_Addr) l;
128 /* If the first instruction of the plt entry is not
129 "br $28, plt0", we have to reinitialize .plt for lazy relocation. */
130 if (*(unsigned int *)(plt + 32) != 0xc39ffff7)
132 unsigned int val = 0xc39ffff7;
133 unsigned int *slot, *end;
134 const Elf64_Rela *rela = (const Elf64_Rela *)
135 D_PTR (l, l_info[DT_JMPREL]);
136 Elf64_Addr l_addr = l->l_addr;
138 /* br t12,.+4; ldq t12,12(t12); nop; jmp t12,(t12),.+4 */
139 *(unsigned long *)plt = 0xa77b000cc3600000;
140 *(unsigned long *)(plt + 8) = 0x6b7b000047ff041f;
141 slot = (unsigned int *)(plt + 32);
142 end = (unsigned int *)(plt + 32
143 + l->l_info[DT_PLTRELSZ]->d_un.d_val / 2);
144 while (slot < end)
146 /* br at,.plt+0 */
147 *slot = val;
148 *(Elf64_Addr *) rela->r_offset = (Elf64_Addr) slot - l_addr;
149 val -= 3;
150 slot += 3;
151 ++rela;
156 return lazy;
159 /* This code is used in dl-runtime.c to call the `fixup' function
160 and then redirect to the address it returns. */
161 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name, IMB) \
162 extern void tramp_name (void); \
163 asm ( "\
164 .globl " #tramp_name " \n\
165 .ent " #tramp_name " \n\
166 " #tramp_name ": \n\
167 lda $sp, -44*8($sp) \n\
168 .frame $sp, 44*8, $26 \n\
169 /* Preserve all integer registers that C normally \n\
170 doesn't. */ \n\
171 stq $26, 0*8($sp) \n\
172 stq $0, 1*8($sp) \n\
173 stq $1, 2*8($sp) \n\
174 stq $2, 3*8($sp) \n\
175 stq $3, 4*8($sp) \n\
176 stq $4, 5*8($sp) \n\
177 stq $5, 6*8($sp) \n\
178 stq $6, 7*8($sp) \n\
179 stq $7, 8*8($sp) \n\
180 stq $8, 9*8($sp) \n\
181 stq $16, 10*8($sp) \n\
182 stq $17, 11*8($sp) \n\
183 stq $18, 12*8($sp) \n\
184 stq $19, 13*8($sp) \n\
185 stq $20, 14*8($sp) \n\
186 stq $21, 15*8($sp) \n\
187 stq $22, 16*8($sp) \n\
188 stq $23, 17*8($sp) \n\
189 stq $24, 18*8($sp) \n\
190 stq $25, 19*8($sp) \n\
191 stq $29, 20*8($sp) \n\
192 stt $f0, 21*8($sp) \n\
193 stt $f1, 22*8($sp) \n\
194 stt $f10, 23*8($sp) \n\
195 stt $f11, 24*8($sp) \n\
196 stt $f12, 25*8($sp) \n\
197 stt $f13, 26*8($sp) \n\
198 stt $f14, 27*8($sp) \n\
199 stt $f15, 28*8($sp) \n\
200 stt $f16, 29*8($sp) \n\
201 stt $f17, 30*8($sp) \n\
202 stt $f18, 31*8($sp) \n\
203 stt $f19, 32*8($sp) \n\
204 stt $f20, 33*8($sp) \n\
205 stt $f21, 34*8($sp) \n\
206 stt $f22, 35*8($sp) \n\
207 stt $f23, 36*8($sp) \n\
208 stt $f24, 37*8($sp) \n\
209 stt $f25, 38*8($sp) \n\
210 stt $f26, 39*8($sp) \n\
211 stt $f27, 40*8($sp) \n\
212 stt $f28, 41*8($sp) \n\
213 stt $f29, 42*8($sp) \n\
214 stt $f30, 43*8($sp) \n\
215 .mask 0x27ff01ff, -44*8 \n\
216 .fmask 0xfffffc03, -(44-21)*8 \n\
217 /* Set up our $gp */ \n\
218 br $gp, .+4 \n\
219 ldgp $gp, 0($gp) \n\
220 .prologue 0 \n\
221 /* Set up the arguments for fixup: */ \n\
222 /* $16 = link_map out of plt0 */ \n\
223 /* $17 = offset of reloc entry = ($28 - $27 - 20) /12 * 24 */\n\
224 /* $18 = return address */ \n\
225 subq $28, $27, $17 \n\
226 ldq $16, 8($27) \n\
227 subq $17, 20, $17 \n\
228 mov $26, $18 \n\
229 addq $17, $17, $17 \n\
230 /* Do the fixup */ \n\
231 bsr $26, " #fixup_name " !samegp \n\
232 /* Move the destination address into position. */ \n\
233 mov $0, $27 \n\
234 /* Restore program registers. */ \n\
235 ldq $26, 0*8($sp) \n\
236 ldq $0, 1*8($sp) \n\
237 ldq $1, 2*8($sp) \n\
238 ldq $2, 3*8($sp) \n\
239 ldq $3, 4*8($sp) \n\
240 ldq $4, 5*8($sp) \n\
241 ldq $5, 6*8($sp) \n\
242 ldq $6, 7*8($sp) \n\
243 ldq $7, 8*8($sp) \n\
244 ldq $8, 9*8($sp) \n\
245 ldq $16, 10*8($sp) \n\
246 ldq $17, 11*8($sp) \n\
247 ldq $18, 12*8($sp) \n\
248 ldq $19, 13*8($sp) \n\
249 ldq $20, 14*8($sp) \n\
250 ldq $21, 15*8($sp) \n\
251 ldq $22, 16*8($sp) \n\
252 ldq $23, 17*8($sp) \n\
253 ldq $24, 18*8($sp) \n\
254 ldq $25, 19*8($sp) \n\
255 ldq $29, 20*8($sp) \n\
256 ldt $f0, 21*8($sp) \n\
257 ldt $f1, 22*8($sp) \n\
258 ldt $f10, 23*8($sp) \n\
259 ldt $f11, 24*8($sp) \n\
260 ldt $f12, 25*8($sp) \n\
261 ldt $f13, 26*8($sp) \n\
262 ldt $f14, 27*8($sp) \n\
263 ldt $f15, 28*8($sp) \n\
264 ldt $f16, 29*8($sp) \n\
265 ldt $f17, 30*8($sp) \n\
266 ldt $f18, 31*8($sp) \n\
267 ldt $f19, 32*8($sp) \n\
268 ldt $f20, 33*8($sp) \n\
269 ldt $f21, 34*8($sp) \n\
270 ldt $f22, 35*8($sp) \n\
271 ldt $f23, 36*8($sp) \n\
272 ldt $f24, 37*8($sp) \n\
273 ldt $f25, 38*8($sp) \n\
274 ldt $f26, 39*8($sp) \n\
275 ldt $f27, 40*8($sp) \n\
276 ldt $f28, 41*8($sp) \n\
277 ldt $f29, 42*8($sp) \n\
278 ldt $f30, 43*8($sp) \n\
279 /* Flush the Icache after having modified the .plt code. */\n\
280 " #IMB " \n\
281 /* Clean up and turn control to the destination */ \n\
282 lda $sp, 44*8($sp) \n\
283 jmp $31, ($27) \n\
284 .end " #tramp_name)
286 #ifndef PROF
287 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
288 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup, imb); \
289 TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup, /* nop */);
290 #else
291 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
292 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup, imb); \
293 strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
294 #endif
296 /* Initial entry point code for the dynamic linker.
297 The C function `_dl_start' is the real entry point;
298 its return value is the user program's entry point. */
300 #define RTLD_START asm ("\
301 .section .text \n\
302 .set at \n\
303 .globl _start \n\
304 .ent _start \n\
305 _start: \n\
306 .frame $31,0,$31,0 \n\
307 br $gp, 0f \n\
308 0: ldgp $gp, 0($gp) \n\
309 .prologue 0 \n\
310 /* Pass pointer to argument block to _dl_start. */ \n\
311 mov $sp, $16 \n\
312 bsr $26, _dl_start !samegp \n\
313 .end _start \n\
314 /* FALLTHRU */ \n\
315 .globl _dl_start_user \n\
316 .ent _dl_start_user \n\
317 _dl_start_user: \n\
318 .frame $31,0,$31,0 \n\
319 .prologue 0 \n\
320 /* Save the user entry point address in s0. */ \n\
321 mov $0, $9 \n\
322 /* See if we were run as a command with the executable \n\
323 file name as an extra leading argument. */ \n\
324 ldah $1, _dl_skip_args($gp) !gprelhigh \n\
325 ldl $1, _dl_skip_args($1) !gprellow \n\
326 bne $1, $fixup_stack \n\
327 $fixup_stack_ret: \n\
328 /* The special initializer gets called with the stack \n\
329 just as the application's entry point will see it; \n\
330 it can switch stacks if it moves these contents \n\
331 over. */ \n\
332 " RTLD_START_SPECIAL_INIT " \n\
333 /* Call _dl_init(_dl_loaded, argc, argv, envp) to run \n\
334 initializers. */ \n\
335 ldah $16, _rtld_local($gp) !gprelhigh \n\
336 ldq $16, _rtld_local($16) !gprellow \n\
337 ldq $17, 0($sp) \n\
338 lda $18, 8($sp) \n\
339 s8addq $17, 8, $19 \n\
340 addq $19, $18, $19 \n\
341 bsr $26, _dl_init_internal !samegp \n\
342 /* Pass our finalizer function to the user in $0. */ \n\
343 ldah $0, _dl_fini($gp) !gprelhigh \n\
344 lda $0, _dl_fini($0) !gprellow \n\
345 /* Jump to the user's entry point. */ \n\
346 mov $9, $27 \n\
347 jmp ($9) \n\
348 $fixup_stack: \n\
349 /* Adjust the stack pointer to skip _dl_skip_args words.\n\
350 This involves copying everything down, since the \n\
351 stack pointer must always be 16-byte aligned. */ \n\
352 ldah $7, _dl_argv_internal($gp) !gprelhigh \n\
353 ldq $2, 0($sp) \n\
354 ldq $5, _dl_argv_internal($7) !gprellow \n\
355 subq $31, $1, $6 \n\
356 subq $2, $1, $2 \n\
357 s8addq $6, $5, $5 \n\
358 mov $sp, $4 \n\
359 s8addq $1, $sp, $3 \n\
360 stq $2, 0($sp) \n\
361 stq $5, _dl_argv_internal($7) !gprellow \n\
362 /* Copy down argv. */ \n\
363 0: ldq $5, 8($3) \n\
364 addq $4, 8, $4 \n\
365 addq $3, 8, $3 \n\
366 stq $5, 0($4) \n\
367 bne $5, 0b \n\
368 /* Copy down envp. */ \n\
369 1: ldq $5, 8($3) \n\
370 addq $4, 8, $4 \n\
371 addq $3, 8, $3 \n\
372 stq $5, 0($4) \n\
373 bne $5, 1b \n\
374 /* Copy down auxiliary table. */ \n\
375 2: ldq $5, 8($3) \n\
376 ldq $6, 16($3) \n\
377 addq $4, 16, $4 \n\
378 addq $3, 16, $3 \n\
379 stq $5, -8($4) \n\
380 stq $6, 0($4) \n\
381 bne $5, 2b \n\
382 br $fixup_stack_ret \n\
383 .end _dl_start_user \n\
384 .set noat \n\
385 .previous");
387 #ifndef RTLD_START_SPECIAL_INIT
388 #define RTLD_START_SPECIAL_INIT /* nothing */
389 #endif
391 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry
392 or TLS variables, so undefined references should not be allowed
393 to define the value.
395 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve
396 to one of the main executable's symbols, as for a COPY reloc.
397 This is unused on Alpha. */
399 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
400 #define elf_machine_type_class(type) \
401 (((type) == R_ALPHA_JMP_SLOT \
402 || (type) == R_ALPHA_DTPMOD64 \
403 || (type) == R_ALPHA_DTPREL64 \
404 || (type) == R_ALPHA_TPREL64) * ELF_RTYPE_CLASS_PLT)
405 #else
406 #define elf_machine_type_class(type) \
407 (((type) == R_ALPHA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)
408 #endif
410 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
411 #define ELF_MACHINE_JMP_SLOT R_ALPHA_JMP_SLOT
413 /* The alpha never uses Elf64_Rel relocations. */
414 #define ELF_MACHINE_NO_REL 1
416 /* Fix up the instructions of a PLT entry to invoke the function
417 rather than the dynamic linker. */
418 static inline Elf64_Addr
419 elf_machine_fixup_plt (struct link_map *l, lookup_t t,
420 const Elf64_Rela *reloc,
421 Elf64_Addr *got_addr, Elf64_Addr value)
423 const Elf64_Rela *rela_plt;
424 Elf64_Word *plte;
425 long int edisp;
427 /* Store the value we are going to load. */
428 *got_addr = value;
430 /* Recover the PLT entry address by calculating reloc's index into the
431 .rela.plt, and finding that entry in the .plt. */
432 rela_plt = (void *) D_PTR (l, l_info[DT_JMPREL]);
433 plte = (void *) (D_PTR (l, l_info[DT_PLTGOT]) + 32);
434 plte += 3 * (reloc - rela_plt);
436 /* Find the displacement from the plt entry to the function. */
437 edisp = (long int) (value - (Elf64_Addr)&plte[3]) / 4;
439 if (edisp >= -0x100000 && edisp < 0x100000)
441 /* If we are in range, use br to perfect branch prediction and
442 elide the dependency on the address load. This case happens,
443 e.g., when a shared library call is resolved to the same library. */
445 int hi, lo;
446 hi = value - (Elf64_Addr)&plte[0];
447 lo = (short int) hi;
448 hi = (hi - lo) >> 16;
450 /* Emit "lda $27,lo($27)" */
451 plte[1] = 0x237b0000 | (lo & 0xffff);
453 /* Emit "br $31,function" */
454 plte[2] = 0xc3e00000 | (edisp & 0x1fffff);
456 /* Think about thread-safety -- the previous instructions must be
457 committed to memory before the first is overwritten. */
458 __asm__ __volatile__("wmb" : : : "memory");
460 /* Emit "ldah $27,hi($27)" */
461 plte[0] = 0x277b0000 | (hi & 0xffff);
463 else
465 /* Don't bother with the hint since we already know the hint is
466 wrong. Eliding it prevents the wrong page from getting pulled
467 into the cache. */
469 int hi, lo;
470 hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0];
471 lo = (short)hi;
472 hi = (hi - lo) >> 16;
474 /* Emit "ldq $27,lo($27)" */
475 plte[1] = 0xa77b0000 | (lo & 0xffff);
477 /* Emit "jmp $31,($27)" */
478 plte[2] = 0x6bfb0000;
480 /* Think about thread-safety -- the previous instructions must be
481 committed to memory before the first is overwritten. */
482 __asm__ __volatile__("wmb" : : : "memory");
484 /* Emit "ldah $27,hi($27)" */
485 plte[0] = 0x277b0000 | (hi & 0xffff);
488 /* At this point, if we've been doing runtime resolution, Icache is dirty.
489 This will be taken care of in _dl_runtime_resolve. If instead we are
490 doing this as part of non-lazy startup relocation, that bit of code
491 hasn't made it into Icache yet, so there's nothing to clean up. */
493 return value;
496 /* Return the final value of a plt relocation. */
497 static inline Elf64_Addr
498 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
499 Elf64_Addr value)
501 return value + reloc->r_addend;
504 #endif /* !dl_machine_h */
506 #ifdef RESOLVE
508 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
509 MAP is the object containing the reloc. */
510 static inline void
511 elf_machine_rela (struct link_map *map,
512 const Elf64_Rela *reloc,
513 const Elf64_Sym *sym,
514 const struct r_found_version *version,
515 void *const reloc_addr_arg)
517 Elf64_Addr *const reloc_addr = reloc_addr_arg;
518 unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
520 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
521 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
522 reference weak so static programs can still link. This declaration
523 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
524 because rtld.c contains the common defn for _dl_rtld_map, which is
525 incompatible with a weak decl in the same file. */
526 weak_extern (_dl_rtld_map);
527 #endif
529 /* We cannot use a switch here because we cannot locate the switch
530 jump table until we've self-relocated. */
532 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
533 if (__builtin_expect (r_type == R_ALPHA_RELATIVE, 0))
535 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
536 /* Already done in dynamic linker. */
537 if (map != &GL(dl_rtld_map))
538 # endif
540 /* XXX Make some timings. Maybe it's preferable to test for
541 unaligned access and only do it the complex way if necessary. */
542 Elf64_Addr reloc_addr_val;
544 /* Load value without causing unaligned trap. */
545 memcpy (&reloc_addr_val, reloc_addr_arg, 8);
546 reloc_addr_val += map->l_addr;
548 /* Store value without causing unaligned trap. */
549 memcpy (reloc_addr_arg, &reloc_addr_val, 8);
552 else
553 #endif
554 if (__builtin_expect (r_type == R_ALPHA_NONE, 0))
555 return;
556 else
558 Elf64_Addr sym_value;
559 Elf64_Addr sym_raw_value;
561 #if defined USE_TLS && !defined RTLD_BOOTSTRAP
562 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
563 sym_raw_value = sym_value = reloc->r_addend;
564 if (sym)
566 sym_raw_value += sym->st_value;
567 sym_value = sym_raw_value + sym_map->l_addr;
569 #else
570 Elf64_Addr loadbase = RESOLVE (&sym, version, r_type);
571 sym_raw_value = sym_value = reloc->r_addend;
572 if (sym)
574 sym_raw_value += sym->st_value;
575 sym_value = sym_raw_value + loadbase;
577 #endif
579 if (r_type == R_ALPHA_GLOB_DAT)
580 *reloc_addr = sym_value;
581 #ifdef RESOLVE_CONFLICT_FIND_MAP
582 /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
583 R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
584 are .rela.plt index. */
585 else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
587 /* elf_machine_fixup_plt needs the map reloc_addr points into,
588 while in _dl_resolve_conflicts map is _dl_loaded. */
589 RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
590 reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
591 + (r_type >> 8);
592 elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
594 #else
595 else if (r_type == R_ALPHA_JMP_SLOT)
596 elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
597 #endif
598 #ifndef RTLD_BOOTSTRAP
599 else if (r_type == R_ALPHA_REFQUAD)
601 /* Store value without causing unaligned trap. */
602 memcpy (reloc_addr_arg, &sym_value, 8);
604 #endif
605 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
606 else if (r_type == R_ALPHA_DTPMOD64)
608 #ifdef RTLD_BOOTSTRAP
609 /* During startup the dynamic linker is always index 1. */
610 *reloc_addr = 1;
611 #else
612 /* Get the information from the link map returned by the
613 resolv function. */
614 if (sym_map != NULL)
615 *reloc_addr = sym_map->l_tls_modid;
616 #endif
618 else if (r_type == R_ALPHA_DTPREL64)
620 #ifndef RTLD_BOOTSTRAP
621 /* During relocation all TLS symbols are defined and used.
622 Therefore the offset is already correct. */
623 *reloc_addr = sym_raw_value;
624 #endif
626 else if (r_type == R_ALPHA_TPREL64)
628 #ifdef RTLD_BOOTSTRAP
629 *reloc_addr = sym_raw_value + map->l_tls_offset;
630 #else
631 if (sym_map)
633 CHECK_STATIC_TLS (map, sym_map);
634 *reloc_addr = sym_raw_value + sym_map->l_tls_offset;
636 #endif
638 #endif /* USE_TLS */
639 else
640 _dl_reloc_bad_type (map, r_type, 0);
644 /* Let do-rel.h know that on Alpha if l_addr is 0, all RELATIVE relocs
645 can be skipped. */
646 #define ELF_MACHINE_REL_RELATIVE 1
648 static inline void
649 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
650 void *const reloc_addr_arg)
652 /* XXX Make some timings. Maybe it's preferable to test for
653 unaligned access and only do it the complex way if necessary. */
654 Elf64_Addr reloc_addr_val;
656 /* Load value without causing unaligned trap. */
657 memcpy (&reloc_addr_val, reloc_addr_arg, 8);
658 reloc_addr_val += l_addr;
660 /* Store value without causing unaligned trap. */
661 memcpy (reloc_addr_arg, &reloc_addr_val, 8);
664 static inline void
665 elf_machine_lazy_rel (struct link_map *map,
666 Elf64_Addr l_addr, const Elf64_Rela *reloc)
668 Elf64_Addr * const reloc_addr = (void *)(l_addr + reloc->r_offset);
669 unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
671 if (r_type == R_ALPHA_JMP_SLOT)
673 /* Perform a RELATIVE reloc on the .got entry that transfers
674 to the .plt. */
675 *reloc_addr += l_addr;
677 else if (r_type == R_ALPHA_NONE)
678 return;
679 else
680 _dl_reloc_bad_type (map, r_type, 1);
683 #endif /* RESOLVE */