Update.
[platform/upstream/linaro-glibc.git] / sysdeps / sh / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  SH version.
2    Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #ifndef dl_machine_h
21 #define dl_machine_h
22
23 /* Only dummy. This doesn't work. */
24
25 #define ELF_MACHINE_NAME "SH"
26
27 #include <sys/param.h>
28
29 #include <assert.h>
30
31 /* Return nonzero iff ELF header is compatible with the running host.  */
32 static inline int __attribute__ ((unused))
33 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
34 {
35   return ehdr->e_machine == EM_SH;
36 }
37
38
39 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
40    first element of the GOT.  This must be inlined in a function which
41    uses global data.  */
42 static inline Elf32_Addr __attribute__ ((unused))
43 elf_machine_dynamic (void)
44 {
45   register Elf32_Addr *got;
46   asm ("mov r12,%0" :"=r" (got));
47   return *got;
48 }
49
50
51 /* Return the run-time load address of the shared object.  */
52 static inline Elf32_Addr __attribute__ ((unused))
53 elf_machine_load_address (void)
54 {
55   Elf32_Addr addr;
56   asm ("mov.l .L1,r0\n\
57         mov.l .L3,r2\n\
58         add r12,r2\n\
59         mov.l @(r0,r12),r0\n\
60         bra .L2\n\
61          sub r0,r2\n\
62         .align 2\n\
63         .L1: .long _dl_start@GOT\n\
64         .L3: .long _dl_start@GOTOFF\n\
65         .L2: mov r2,%0"
66        : "=r" (addr) : : "r0", "r1", "r2");
67   return addr;
68 }
69
70
71 /* Set up the loaded object described by L so its unrelocated PLT
72    entries will jump to the on-demand fixup code in dl-runtime.c.  */
73
74 static inline int __attribute__ ((unused))
75 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
76 {
77   Elf32_Addr *got;
78   extern void _dl_runtime_resolve (Elf32_Word);
79   extern void _dl_runtime_profile (Elf32_Word);
80
81   if (l->l_info[DT_JMPREL] && lazy)
82     {
83       /* The GOT entries for functions in the PLT have not yet been filled
84          in.  Their initial contents will arrange when called to load an
85          offset into the .rela.plt section and _GLOBAL_OFFSET_TABLE_[1],
86          and then jump to _GLOBAL_OFFSET_TABLE[2].  */
87       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
88       got[1] = (Elf32_Addr) l;  /* Identify this shared object.  */
89
90       /* The got[2] entry contains the address of a function which gets
91          called to get the address of a so far unresolved function and
92          jump to it.  The profiling extension of the dynamic linker allows
93          to intercept the calls to collect information.  In this case we
94          don't store the address in the GOT so that all future calls also
95          end in this function.  */
96       if (profile)
97         {
98           got[2] = (Elf32_Addr) &_dl_runtime_profile;
99           /* Say that we really want profiling and the timers are started.  */
100           _dl_profile_map = l;
101         }
102       else
103         /* This function will get called to fix up the GOT entry indicated by
104            the offset on the stack, and then jump to the resolved address.  */
105         got[2] = (Elf32_Addr) &_dl_runtime_resolve;
106     }
107   return lazy;
108 }
109
110 /* This code is used in dl-runtime.c to call the `fixup' function
111    and then redirect to the address it returns.  */
112
113 #define ELF_MACHINE_RUNTIME_FIXUP_ARGS int plt_type
114
115 #ifdef SHARED
116 #define FUN_ADDR        "\
117         mov.l 1f,r2\n\
118         mova 1f,r0\n\
119         bra 2f\n\
120          add r0,r2              ! Get GOT address in r2\n\
121 0:      .align 2\n\
122 1:      .long _GLOBAL_OFFSET_TABLE_\n\
123 2:      mov.l 3f,r0\n\
124         add r2,r0"
125 #define GOTJMP(x)       #x "@GOTOFF"
126 #else
127 #define FUN_ADDR        "\
128         mov.l 3f,r0"
129 #define GOTJMP(x)       #x
130 #endif
131
132 #ifdef HAVE_FPU
133 #define FGR_SAVE        "\
134         sts.l   fpscr, @-r15\n\
135         mov     #8,r3\n\
136         swap.w  r3, r3\n\
137         lds     r3, fpscr\n\
138         fmov.s  fr11, @-r15\n\
139         fmov.s  fr10, @-r15\n\
140         fmov.s  fr9, @-r15\n\
141         fmov.s  fr8, @-r15\n\
142         fmov.s  fr7, @-r15\n\
143         fmov.s  fr6, @-r15\n\
144         fmov.s  fr5, @-r15\n\
145         fmov.s  fr4, @-r15"
146 #define FGR_LOAD        "\
147         fmov.s  @r15+, fr4\n\
148         fmov.s  @r15+, fr5\n\
149         fmov.s  @r15+, fr6\n\
150         fmov.s  @r15+, fr7\n\
151         fmov.s  @r15+, fr8\n\
152         fmov.s  @r15+, fr9\n\
153         fmov.s  @r15+, fr10\n\
154         fmov.s  @r15+, fr11\n\
155         lds.l   @r15+, fpscr"
156 #else
157 #define FGR_SAVE        ""
158 #define FGR_LOAD        ""
159 #endif
160
161 #ifndef PROF
162 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
163         .text\n\
164         .globl _dl_runtime_resolve\n\
165         .type _dl_runtime_resolve, @function\n\
166         .align 5\n\
167 _dl_runtime_resolve:\n\
168         mov.l r2,@-r15\n\
169         mov.l r3,@-r15\n\
170         mov.l r4,@-r15\n\
171         mov.l r5,@-r15\n\
172         mov.l r6,@-r15\n\
173         mov.l r7,@-r15\n\
174         mov.l r12,@-r15\n\
175         movt r3                 ! Save T flag.\n\
176         mov.l r3,@-r15\n\
177         " FGR_SAVE "\n\
178         sts.l pr,@-r15\n\
179         tst r0,r0\n\
180         bt 1f\n\
181         mov r0,r2\n\
182 1:\n\
183         mov r0,r4               ! PLT type\n\
184         mov r2,r5               ! link map address\n\
185         " FUN_ADDR "\n\
186         jsr @r0                 ! Call resolver.\n\
187          mov r1,r6              ! reloc offset\n\
188         lds.l @r15+,pr          ! Get register content back.\n\
189         " FGR_LOAD "\n\
190         mov.l @r15+,r3\n\
191         shal r3                 ! Lode T flag.\n\
192         mov.l @r15+,r12\n\
193         mov.l @r15+,r7\n\
194         mov.l @r15+,r6\n\
195         mov.l @r15+,r5\n\
196         mov.l @r15+,r4\n\
197         mov.l @r15+,r3\n\
198         jmp @r0                 ! Jump to function address.\n\
199          mov.l @r15+,r2\n\
200         .align 2\n\
201 3:\n\
202         .long " GOTJMP (fixup) "\n\
203         .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
204 \n\
205         .globl _dl_runtime_profile\n\
206         .type _dl_runtime_profile, @function\n\
207         .align 5\n\
208 _dl_runtime_profile:\n\
209         mov.l r2,@-r15\n\
210         mov.l r3,@-r15\n\
211         mov.l r4,@-r15\n\
212         mov.l r5,@-r15\n\
213         mov.l r6,@-r15\n\
214         mov.l r7,@-r15\n\
215         mov.l r12,@-r15\n\
216         movt r3                 ! Save T flag.\n\
217         mov.l r3,@-r15\n\
218         " FGR_SAVE "\n\
219         sts.l pr,@-r15\n\
220         tst r0,r0\n\
221         bt 1f\n\
222         mov r0,r2\n\
223 1:\n\
224         mov r0,r4               ! PLT type\n\
225         mov r2,r5               ! link map address\n\
226         sts pr,r7               ! return address\n\
227         " FUN_ADDR "\n\
228         jsr @r0                 ! Call resolver.\n\
229          mov r1,r6              ! reloc offset\n\
230         lds.l @r15+,pr          ! Get register content back.\n\
231         " FGR_LOAD "\n\
232         mov.l @r15+,r3\n\
233         shal r3                 ! Lode T flag.\n\
234         mov.l @r15+,r12\n\
235         mov.l @r15+,r7\n\
236         mov.l @r15+,r6\n\
237         mov.l @r15+,r5\n\
238         mov.l @r15+,r4\n\
239         mov.l @r15+,r3\n\
240         jmp @r0                 ! Jump to function address.\n\
241          mov.l @r15+,r2\n\
242         .align 2\n\
243 3:\n\
244         .long " GOTJMP (profile_fixup) "\n\
245         .size _dl_runtime_profile, .-_dl_runtime_profile\n\
246         .previous\n\
247 ");
248 #else
249 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
250         .text\n\
251         .globl _dl_runtime_resolve\n\
252         .globl _dl_runtime_profile\n\
253         .type _dl_runtime_resolve, @function\n\
254         .type _dl_runtime_profile, @function\n\
255         .align 5\n\
256 _dl_runtime_resolve:\n\
257 _dl_runtime_profile:\n\
258         mov.l r2,@-r15\n\
259         mov.l r3,@-r15\n\
260         mov.l r4,@-r15\n\
261         mov.l r5,@-r15\n\
262         mov.l r6,@-r15\n\
263         mov.l r7,@-r15\n\
264         mov.l r12,@-r15\n\
265         movt r3                 ! Save T flag.\n\
266         mov.l r3,@-r15\n\
267         " FGR_SAVE "\n\
268         sts.l pr,@-r15\n\
269         tst r0,r0\n\
270         bt 1f\n\
271         mov r0,r2\n\
272 1:\n\
273         mov r0,r4               ! PLT type\n\
274         mov r2,r5               ! link map address\n\
275         sts pr,r7               ! return address\n\
276         " FUN_ADDR "\n\
277         jsr @r0                 ! Call resolver.\n\
278          mov r1,r6              ! reloc offset\n\
279         lds.l @r15+,pr          ! Get register content back.\n\
280         " FGR_LOAD "\n\
281         mov.l @r15+,r3\n\
282         shal r3                 ! Lode T flag.\n\
283         mov.l @r15+,r12\n\
284         mov.l @r15+,r7\n\
285         mov.l @r15+,r6\n\
286         mov.l @r15+,r5\n\
287         mov.l @r15+,r4\n\
288         mov.l @r15+,r3\n\
289         jmp @r0                 ! Jump to function address.\n\
290          mov.l @r15+,r2\n\
291         .align 2\n\
292 3:\n\
293         .long " GOTJMP (fixup) "\n\
294         .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
295         .size _dl_runtime_profile, .-_dl_runtime_profile\n\
296         .previous\n\
297 ");
298 #endif
299
300 /* Mask identifying addresses reserved for the user program,
301    where the dynamic linker should not map anything.  */
302 #define ELF_MACHINE_USER_ADDRESS_MASK   0x80000000UL
303
304 /* Initial entry point code for the dynamic linker.
305    The C function `_dl_start' is the real entry point;
306    its return value is the user program's entry point.  */
307
308 #define RTLD_START asm ("\
309 .text\n\
310 .globl _start\n\
311 .globl _dl_start_user\n\
312 _start:\n\
313         mov r15,r4\n\
314         mov.l .L_dl_start,r1\n\
315         mova .L_dl_start,r0\n\
316         add r1,r0\n\
317         jsr @r0\n\
318          nop\n\
319 _dl_start_user:\n\
320         ! Save the user entry point address in r8.\n\
321         mov r0,r8\n\
322         ! Point r12 at the GOT.\n\
323         mov.l 1f,r12\n\
324         mova 1f,r0\n\
325         bra 2f\n\
326          add r0,r12\n\
327         .align 2\n\
328 1:      .long _GLOBAL_OFFSET_TABLE_\n\
329 2:      ! Store the highest stack address\n\
330         mov.l .L_stack_end,r0\n\
331         mov.l @(r0,r12),r0\n\
332         mov.l r15,@r0\n\
333         ! See if we were run as a command with the executable file\n\
334         ! name as an extra leading argument.\n\
335         mov.l .L_dl_skip_args,r0\n\
336         mov.l @(r0,r12),r0\n\
337         mov.l @r0,r0\n\
338         ! Get the original argument count.\n\
339         mov.l @r15,r5\n\
340         ! Subtract _dl_skip_args from it.\n\
341         sub r0,r5\n\
342         ! Adjust the stack pointer to skip _dl_skip_args words.\n\
343         shll2 r0\n\
344         add r0,r15\n\
345         ! Store back the modified argument count.\n\
346         mov.l r5,@r15\n\
347         ! Compute argv address and envp.\n\
348         mov r15,r6\n\
349         add #4,r6\n\
350         mov r5,r7\n\
351         shll2 r7\n\
352         add r15,r7\n\
353         mov.l .L_dl_loaded,r0\n\
354         mov.l @(r0,r12),r0\n\
355         mov.l @r0,r4\n\
356         ! Call _dl_init.\n\
357         mov.l .L_dl_init,r1\n\
358         mova .L_dl_init,r0\n\
359         add r1,r0\n\
360         jsr @r0\n\
361          nop\n\
362 1:      ! Clear the startup flag.\n\
363         mov.l .L_dl_starting_up,r0\n\
364         mov.l @(r0,r12),r0\n\
365         mov #0,r2\n\
366         mov.l r2,@r0\n\
367         ! Pass our finalizer function to the user in r4, as per ELF ABI.\n\
368         mov.l .L_dl_fini,r0\n\
369         mov.l @(r0,r12),r4\n\
370         ! Jump to the user's entry point.\n\
371         jmp @r8\n\
372          nop\n\
373         .align 2\n\
374 .L_dl_start:\n\
375         .long _dl_start@PLT\n\
376 .L_stack_end:\n\
377         .long __libc_stack_end@GOT\n\
378 .L_dl_skip_args:\n\
379         .long _dl_skip_args@GOT\n\
380 .L_dl_init:\n\
381         .long _dl_init@PLT\n\
382 .L_dl_loaded:\n\
383         .long _dl_loaded@GOT\n\
384 .L_dl_starting_up:\n\
385         .long _dl_starting_up@GOT\n\
386 .L_dl_fini:\n\
387         .long _dl_fini@GOT\n\
388 .previous\n\
389 ");
390
391 /* Nonzero iff TYPE should not be allowed to resolve to one of
392    the main executable's symbols, as for a COPY reloc.  */
393 #define elf_machine_lookup_noexec_p(type) ((type) == R_SH_COPY)
394
395 /* Nonzero iff TYPE describes relocation of a PLT entry, so
396    PLT entries should not be allowed to define the value.  */
397 #define elf_machine_lookup_noplt_p(type) ((type) == R_SH_JMP_SLOT)
398
399 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
400 #define ELF_MACHINE_JMP_SLOT    R_SH_JMP_SLOT
401
402 /* We define an initialization functions.  This is called very early in
403    _dl_sysdep_start.  */
404 #define DL_PLATFORM_INIT dl_platform_init ()
405
406 extern const char *_dl_platform;
407
408 static inline void __attribute__ ((unused))
409 dl_platform_init (void)
410 {
411   if (_dl_platform != NULL && *_dl_platform == '\0')
412     /* Avoid an empty string which would disturb us.  */
413     _dl_platform = NULL;
414 }
415
416 static inline Elf32_Addr
417 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
418                        const Elf32_Rela *reloc,
419                        Elf32_Addr *reloc_addr, Elf32_Addr value)
420 {
421   return *reloc_addr = value;
422 }
423
424 /* Return the final value of a plt relocation.  */
425 static inline Elf32_Addr
426 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
427                        Elf32_Addr value)
428 {
429   return value + reloc->r_addend;
430 }
431
432 #endif /* !dl_machine_h */
433
434 #ifdef RESOLVE
435
436 /* SH never uses Elf32_Rel relocations.  */
437 #define ELF_MACHINE_NO_REL 1
438
439 extern char **_dl_argv;
440
441 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
442    MAP is the object containing the reloc.  */
443
444 static inline void
445 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
446                  const Elf32_Sym *sym, const struct r_found_version *version,
447                  Elf32_Addr *const reloc_addr)
448 {
449   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
450   Elf32_Addr value;
451
452 #define COPY_UNALIGNED_WORD(sw, tw, align) \
453   { \
454     void *__s = &(sw), *__t = &(tw); \
455     switch ((align)) \
456     { \
457     case 0: \
458       *(unsigned long *) __t = *(unsigned long *) __s; \
459       break; \
460     case 2: \
461       *((unsigned short *) __t)++ = *((unsigned short *) __s)++; \
462       *((unsigned short *) __t) = *((unsigned short *) __s); \
463       break; \
464     default: \
465       *((unsigned char *) __t)++ = *((unsigned char *) __s)++; \
466       *((unsigned char *) __t)++ = *((unsigned char *) __s)++; \
467       *((unsigned char *) __t)++ = *((unsigned char *) __s)++; \
468       *((unsigned char *) __t) = *((unsigned char *) __s); \
469       break; \
470     } \
471   }
472
473   if (__builtin_expect (r_type == R_SH_RELATIVE, 0))
474     {
475 #ifndef RTLD_BOOTSTRAP
476       if (map != &_dl_rtld_map) /* Already done in rtld itself.  */
477 #endif
478         {
479           if (reloc->r_addend)
480             value = map->l_addr + reloc->r_addend;
481           else
482             {
483               COPY_UNALIGNED_WORD (*reloc_addr, value, (int) reloc_addr & 3);
484               value += map->l_addr;
485             }
486           COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
487         }
488     }
489 #ifndef RTLD_BOOTSTRAP
490   else if (__builtin_expect (r_type 1= R_SH_NONE, 0))
491     return;
492 #endif
493   else
494     {
495       const Elf32_Sym *const refsym = sym;
496
497       value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
498       if (sym)
499         value += sym->st_value;
500       value += reloc->r_addend;
501
502       switch (ELF32_R_TYPE (reloc->r_info))
503         {
504         case R_SH_COPY:
505           if (sym == NULL)
506             /* This can happen in trace mode if an object could not be
507                found.  */
508             break;
509           if (sym->st_size > refsym->st_size
510               || (sym->st_size < refsym->st_size && _dl_verbose))
511             {
512               const char *strtab;
513
514               strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
515               _dl_error_printf ("\
516 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
517                                 _dl_argv[0] ?: "<program name unknown>",
518                                 strtab + refsym->st_name);
519             }
520           memcpy (reloc_addr, (void *) value, MIN (sym->st_size,
521                                                    refsym->st_size));
522           break;
523         case R_SH_GLOB_DAT:
524         case R_SH_JMP_SLOT:
525           /* These addresses are always aligned.  */
526           *reloc_addr = value;
527           break;
528         case R_SH_DIR32:
529           {
530 #ifndef RTLD_BOOTSTRAP
531            /* This is defined in rtld.c, but nowhere in the static
532               libc.a; make the reference weak so static programs can
533               still link.  This declaration cannot be done when
534               compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP) because
535               rtld.c contains the common defn for _dl_rtld_map, which
536               is incompatible with a weak decl in the same file.  */
537             weak_extern (_dl_rtld_map);
538             if (map == &_dl_rtld_map)
539               /* Undo the relocation done here during bootstrapping.
540                  Now we will relocate it anew, possibly using a
541                  binding found in the user program or a loaded library
542                  rather than the dynamic linker's built-in definitions
543                  used while loading those libraries.  */
544               value -= map->l_addr + refsym->st_value + reloc->r_addend;
545 #endif
546             COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
547             break;
548           }
549         case R_SH_REL32:
550           value = (value - (Elf32_Addr) reloc_addr);
551           COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
552           break;
553         default:
554           _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 0);
555           break;
556         }
557     }
558 }
559
560 static inline void
561 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
562                           Elf32_Addr *const reloc_addr)
563 {
564   if (reloc->r_addend)
565     value = l_addr + reloc->r_addend;
566   else
567     {
568       COPY_UNALIGNED_WORD (*reloc_addr, value, (int) reloc_addr & 3);
569       value += l_addr;
570     }
571   COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
572
573 #undef COPY_UNALIGNED_WORD
574 }
575
576 static inline void
577 elf_machine_lazy_rel (struct link_map *map,
578                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
579 {
580   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
581   /* Check for unexpected PLT reloc type.  */
582   if (ELF32_R_TYPE (reloc->r_info) == R_SH_JMP_SLOT)
583     *reloc_addr += l_addr;
584   else
585     _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
586 }
587
588 #endif /* RESOLVE */