Update.
[glibc.git] / sysdeps / alpha / dl-machine.h
blob711bf10fddfa058441285630609742323b558d74
1 /* Machine-dependent ELF dynamic relocation inline functions. Alpha version.
2 Copyright (C) 1996-2001, 2002 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 (GL(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 br $gp, 0f \n\
307 0: ldgp $gp, 0($gp) \n\
308 .prologue 0 \n\
309 /* Pass pointer to argument block to _dl_start. */ \n\
310 mov $sp, $16 \n\
311 bsr $26, _dl_start !samegp \n\
312 .end _start \n\
313 /* FALLTHRU */ \n\
314 .globl _dl_start_user \n\
315 .ent _dl_start_user \n\
316 _dl_start_user: \n\
317 .frame $30,0,$31,0 \n\
318 .prologue 0 \n\
319 /* Save the user entry point address in s0. */ \n\
320 mov $0, $9 \n\
321 /* Store the highest stack address. */ \n\
322 stq $30, __libc_stack_end \n\
323 /* See if we were run as a command with the executable \n\
324 file name as an extra leading argument. */ \n\
325 ldl $1, _dl_skip_args($gp) !gprel \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 ldq $2, 0($sp) \n\
353 ldq $5, _dl_argv \n\
354 subq $31, $1, $6 \n\
355 subq $2, $1, $2 \n\
356 s8addq $6, $5, $5 \n\
357 mov $sp, $4 \n\
358 s8addq $1, $sp, $3 \n\
359 stq $2, 0($sp) \n\
360 stq $5, _dl_argv \n\
361 /* Copy down argv. */ \n\
362 0: ldq $5, 8($3) \n\
363 addq $4, 8, $4 \n\
364 addq $3, 8, $3 \n\
365 stq $5, 0($4) \n\
366 bne $5, 0b \n\
367 /* Copy down envp. */ \n\
368 1: ldq $5, 8($3) \n\
369 addq $4, 8, $4 \n\
370 addq $3, 8, $3 \n\
371 stq $5, 0($4) \n\
372 bne $5, 1b \n\
373 /* Copy down auxiliary table. */ \n\
374 2: ldq $5, 8($3) \n\
375 ldq $6, 16($3) \n\
376 addq $4, 16, $4 \n\
377 addq $3, 16, $3 \n\
378 stq $5, -8($4) \n\
379 stq $6, 0($4) \n\
380 bne $5, 2b \n\
381 br $fixup_stack_ret \n\
382 .end _dl_start_user \n\
383 .set noat \n\
384 .previous");
386 #ifndef RTLD_START_SPECIAL_INIT
387 #define RTLD_START_SPECIAL_INIT /* nothing */
388 #endif
390 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
391 PLT entries should not be allowed to define the value.
392 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
393 of the main executable's symbols, as for a COPY reloc, which we don't
394 use. */
395 #define elf_machine_type_class(type) \
396 (((type) == R_ALPHA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)
398 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
399 #define ELF_MACHINE_JMP_SLOT R_ALPHA_JMP_SLOT
401 /* The alpha never uses Elf64_Rel relocations. */
402 #define ELF_MACHINE_NO_REL 1
404 /* Fix up the instructions of a PLT entry to invoke the function
405 rather than the dynamic linker. */
406 static inline Elf64_Addr
407 elf_machine_fixup_plt (struct link_map *l, lookup_t t,
408 const Elf64_Rela *reloc,
409 Elf64_Addr *got_addr, Elf64_Addr value)
411 const Elf64_Rela *rela_plt;
412 Elf64_Word *plte;
413 long int edisp;
415 /* Store the value we are going to load. */
416 *got_addr = value;
418 /* Recover the PLT entry address by calculating reloc's index into the
419 .rela.plt, and finding that entry in the .plt. */
420 rela_plt = (void *) D_PTR (l, l_info[DT_JMPREL]);
421 plte = (void *) (D_PTR (l, l_info[DT_PLTGOT]) + 32);
422 plte += 3 * (reloc - rela_plt);
424 /* Find the displacement from the plt entry to the function. */
425 edisp = (long int) (value - (Elf64_Addr)&plte[3]) / 4;
427 if (edisp >= -0x100000 && edisp < 0x100000)
429 /* If we are in range, use br to perfect branch prediction and
430 elide the dependency on the address load. This case happens,
431 e.g., when a shared library call is resolved to the same library. */
433 int hi, lo;
434 hi = value - (Elf64_Addr)&plte[0];
435 lo = (short int) hi;
436 hi = (hi - lo) >> 16;
438 /* Emit "lda $27,lo($27)" */
439 plte[1] = 0x237b0000 | (lo & 0xffff);
441 /* Emit "br $31,function" */
442 plte[2] = 0xc3e00000 | (edisp & 0x1fffff);
444 /* Think about thread-safety -- the previous instructions must be
445 committed to memory before the first is overwritten. */
446 __asm__ __volatile__("wmb" : : : "memory");
448 /* Emit "ldah $27,hi($27)" */
449 plte[0] = 0x277b0000 | (hi & 0xffff);
451 else
453 /* Don't bother with the hint since we already know the hint is
454 wrong. Eliding it prevents the wrong page from getting pulled
455 into the cache. */
457 int hi, lo;
458 hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0];
459 lo = (short)hi;
460 hi = (hi - lo) >> 16;
462 /* Emit "ldq $27,lo($27)" */
463 plte[1] = 0xa77b0000 | (lo & 0xffff);
465 /* Emit "jmp $31,($27)" */
466 plte[2] = 0x6bfb0000;
468 /* Think about thread-safety -- the previous instructions must be
469 committed to memory before the first is overwritten. */
470 __asm__ __volatile__("wmb" : : : "memory");
472 /* Emit "ldah $27,hi($27)" */
473 plte[0] = 0x277b0000 | (hi & 0xffff);
476 /* At this point, if we've been doing runtime resolution, Icache is dirty.
477 This will be taken care of in _dl_runtime_resolve. If instead we are
478 doing this as part of non-lazy startup relocation, that bit of code
479 hasn't made it into Icache yet, so there's nothing to clean up. */
481 return value;
484 /* Return the final value of a plt relocation. */
485 static inline Elf64_Addr
486 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
487 Elf64_Addr value)
489 return value + reloc->r_addend;
492 #endif /* !dl_machine_h */
494 #ifdef RESOLVE
496 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
497 MAP is the object containing the reloc. */
498 static inline void
499 elf_machine_rela (struct link_map *map,
500 const Elf64_Rela *reloc,
501 const Elf64_Sym *sym,
502 const struct r_found_version *version,
503 Elf64_Addr *const reloc_addr)
505 unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
507 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
508 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
509 reference weak so static programs can still link. This declaration
510 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
511 because rtld.c contains the common defn for _dl_rtld_map, which is
512 incompatible with a weak decl in the same file. */
513 weak_extern (_dl_rtld_map);
514 #endif
516 /* We cannot use a switch here because we cannot locate the switch
517 jump table until we've self-relocated. */
519 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
520 if (__builtin_expect (r_type == R_ALPHA_RELATIVE, 0))
522 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
523 /* Already done in dynamic linker. */
524 if (map != &GL(dl_rtld_map))
525 # endif
527 /* XXX Make some timings. Maybe it's preferable to test for
528 unaligned access and only do it the complex way if necessary. */
529 void *reloc_addr_1 = reloc_addr;
530 Elf64_Addr reloc_addr_val;
532 /* Load value without causing unaligned trap. */
533 memcpy (&reloc_addr_val, reloc_addr_1, 8);
534 reloc_addr_val += map->l_addr;
536 /* Store value without causing unaligned trap. */
537 memcpy (reloc_addr_1, &reloc_addr_val, 8);
540 else
541 #endif
542 if (__builtin_expect (r_type == R_ALPHA_NONE, 0))
543 return;
544 else
546 Elf64_Addr sym_value;
548 #if defined USE_TLS && !defined RTLD_BOOTSTRAP
549 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
550 sym_value = sym ? sym_map->l_addr + sym->st_value : 0;
551 #else
552 Elf64_Addr loadbase = RESOLVE (&sym, version, r_type);
553 sym_value = sym ? loadbase + sym->st_value : 0;
554 #endif
555 sym_value += reloc->r_addend;
557 if (r_type == R_ALPHA_GLOB_DAT)
558 *reloc_addr = sym_value;
559 #ifdef RESOLVE_CONFLICT_FIND_MAP
560 /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
561 R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
562 are .rela.plt index. */
563 else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
565 /* elf_machine_fixup_plt needs the map reloc_addr points into,
566 while in _dl_resolve_conflicts map is _dl_loaded. */
567 RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
568 reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
569 + (r_type >> 8);
570 elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
572 #else
573 else if (r_type == R_ALPHA_JMP_SLOT)
574 elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
575 #endif
576 #ifndef RTLD_BOOTSTRAP
577 else if (r_type == R_ALPHA_REFQUAD)
579 void *reloc_addr_1 = reloc_addr;
581 /* Store value without causing unaligned trap. */
582 memcpy (reloc_addr_1, &sym_value, 8);
584 #endif
585 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
586 else if (r_type == R_ALPHA_DTPMOD64)
588 #ifdef RTLD_BOOTSTRAP
589 /* During startup the dynamic linker is always index 1. */
590 *reloc_addr = 1;
591 #else
592 /* Get the information from the link map returned by the
593 resolv function. */
594 if (sym_map != NULL)
595 *reloc_addr = sym_map->l_tls_modid;
596 #endif
598 else if (r_type == R_ALPHA_DTPREL64)
600 #ifndef RTLD_BOOTSTRAP
601 /* During relocation all TLS symbols are defined and used.
602 Therefore the offset is already correct. */
603 *reloc_addr = sym_value;
604 #endif
606 else if (r_type == R_ALPHA_TPREL64)
608 #ifdef RTLD_BOOTSTRAP
609 *reloc_addr = sym_value - map->l_tls_offset;
610 #else
611 if (sym_map)
613 *reloc_addr = sym_value - sym_map->l_tls_offset;
614 CHECK_STATIC_TLS (map, sym_map);
616 #endif
618 #endif /* USE_TLS */
619 else
620 _dl_reloc_bad_type (map, r_type, 0);
624 /* Let do-rel.h know that on Alpha if l_addr is 0, all RELATIVE relocs
625 can be skipped. */
626 #define ELF_MACHINE_REL_RELATIVE 1
628 static inline void
629 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
630 Elf64_Addr *const reloc_addr)
632 /* XXX Make some timings. Maybe it's preverable to test for
633 unaligned access and only do it the complex way if necessary. */
634 void *reloc_addr_1 = reloc_addr;
635 Elf64_Addr reloc_addr_val;
637 /* Load value without causing unaligned trap. */
638 memcpy (&reloc_addr_val, reloc_addr_1, 8);
639 reloc_addr_val += l_addr;
641 /* Store value without causing unaligned trap. */
642 memcpy (reloc_addr_1, &reloc_addr_val, 8);
645 static inline void
646 elf_machine_lazy_rel (struct link_map *map,
647 Elf64_Addr l_addr, const Elf64_Rela *reloc)
649 Elf64_Addr * const reloc_addr = (void *)(l_addr + reloc->r_offset);
650 unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
652 if (r_type == R_ALPHA_JMP_SLOT)
654 /* Perform a RELATIVE reloc on the .got entry that transfers
655 to the .plt. */
656 *reloc_addr += l_addr;
658 else if (r_type == R_ALPHA_NONE)
659 return;
660 else
661 _dl_reloc_bad_type (map, r_type, 1);
664 #endif /* RESOLVE */