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