2008-10-01 Mark Shinwell <shinwell@codesourcery.com>
[platform/upstream/linaro-glibc.git] / sysdeps / mips / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  MIPS version.
2    Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007
3    Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 /*  FIXME: Profiling of shared libraries is not implemented yet.  */
23 #ifndef dl_machine_h
24 #define dl_machine_h
25
26 #define ELF_MACHINE_NAME "MIPS"
27
28 #include <entry.h>
29
30 #ifndef ENTRY_POINT
31 #error ENTRY_POINT needs to be defined for MIPS.
32 #endif
33
34 #include <sgidefs.h>
35 #include <sys/asm.h>
36 #include <dl-tls.h>
37
38 /* The offset of gp from GOT might be system-dependent.  It's set by
39    ld.  The same value is also */
40 #define OFFSET_GP_GOT 0x7ff0
41
42 #ifndef _RTLD_PROLOGUE
43 # define _RTLD_PROLOGUE(entry)                                          \
44         ".globl\t" __STRING(entry) "\n\t"                               \
45         ".ent\t" __STRING(entry) "\n\t"                                 \
46         ".type\t" __STRING(entry) ", @function\n"                       \
47         __STRING(entry) ":\n\t"
48 #endif
49
50 #ifndef _RTLD_EPILOGUE
51 # define _RTLD_EPILOGUE(entry)                                          \
52         ".end\t" __STRING(entry) "\n\t"                                 \
53         ".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
54 #endif
55
56 /* Until elf/elf.h in glibc is updated.  */
57 #ifndef STO_MIPS_PLT
58 #define STO_MIPS_PLT                    0x8
59 #define R_MIPS_COPY             126
60 #define R_MIPS_JUMP_SLOT        127
61 #define DT_MIPS_PLTGOT       0x70000032
62 #endif
63
64 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
65    This only makes sense on MIPS when using PLTs, so choose the
66    PLT relocation (not encountered when not using PLTs).  */
67 #define ELF_MACHINE_JMP_SLOT                    R_MIPS_JUMP_SLOT
68 #define elf_machine_type_class(type) \
69   ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)     \
70    | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
71
72 #define ELF_MACHINE_PLT_REL 1
73
74 /* Translate a processor specific dynamic tag to the index
75    in l_info array.  */
76 #define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
77
78 /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
79    with the run-time address of the r_debug structure  */
80 #define ELF_MACHINE_DEBUG_SETUP(l,r) \
81 do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
82        *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
83        (ElfW(Addr)) (r); \
84    } while (0)
85
86 /* Allow ABIVERSION == 1, meaning PLTs and copy relocations are
87    required.  */
88 #define VALID_ELF_ABIVERSION(ver)       (ver == 0 || ver == 2)
89 #define VALID_ELF_OSABI(osabi)          (osabi == ELFOSABI_SYSV)
90 #define VALID_ELF_HEADER(hdr,exp,size) \
91   memcmp (hdr,exp,size-2) == 0 \
92   && VALID_ELF_OSABI (hdr[EI_OSABI]) \
93   && VALID_ELF_ABIVERSION (hdr[EI_ABIVERSION])
94
95 /* Return nonzero iff ELF header is compatible with the running host.  */
96 static inline int __attribute_used__
97 elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
98 {
99 #if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
100   /* Don't link o32 and n32 together.  */
101   if (((ehdr->e_flags & EF_MIPS_ABI2) != 0) != (_MIPS_SIM == _ABIN32))
102     return 0;
103 #endif
104
105   switch (ehdr->e_machine)
106     {
107     case EM_MIPS:
108     case EM_MIPS_RS3_LE:
109       return 1;
110     default:
111       return 0;
112     }
113 }
114
115 static inline ElfW(Addr) *
116 elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
117 {
118   /* FIXME: the offset of gp from GOT may be system-dependent. */
119   return (ElfW(Addr) *) (gpreg - OFFSET_GP_GOT);
120 }
121
122 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
123    first element of the GOT.  This must be inlined in a function which
124    uses global data.  We assume its $gp points to the primary GOT.  */
125 static inline ElfW(Addr)
126 elf_machine_dynamic (void)
127 {
128   register ElfW(Addr) gp __asm__ ("$28");
129   return *elf_mips_got_from_gpreg (gp);
130 }
131
132 #define STRINGXP(X) __STRING(X)
133 #define STRINGXV(X) STRINGV_(X)
134 #define STRINGV_(...) # __VA_ARGS__
135
136 /* Return the run-time load address of the shared object.  */
137 static inline ElfW(Addr)
138 elf_machine_load_address (void)
139 {
140   ElfW(Addr) addr;
141   asm ("        .set noreorder\n"
142        "        " STRINGXP (PTR_LA) " %0, 0f\n"
143        "        bltzal $0, 0f\n"
144        "        nop\n"
145        "0:      " STRINGXP (PTR_SUBU) " %0, $31, %0\n"
146        "        .set reorder\n"
147        :        "=r" (addr)
148        :        /* No inputs */
149        :        "$31");
150   return addr;
151 }
152
153 /* The MSB of got[1] of a gnu object is set to identify gnu objects.  */
154 #if _MIPS_SIM == _ABI64
155 # define ELF_MIPS_GNU_GOT1_MASK 0x8000000000000000L
156 #else
157 # define ELF_MIPS_GNU_GOT1_MASK 0x80000000L
158 #endif
159
160 /* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
161    fiddles with global data.  */
162 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)                     \
163 do {                                                                    \
164   struct link_map *map = &bootstrap_map;                                \
165   ElfW(Sym) *sym;                                                       \
166   ElfW(Addr) *got;                                                      \
167   int i, n;                                                             \
168                                                                         \
169   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);                  \
170                                                                         \
171   if (__builtin_expect (map->l_addr == 0, 1))                           \
172     break;                                                              \
173                                                                         \
174   /* got[0] is reserved. got[1] is also reserved for the dynamic object \
175      generated by gnu ld. Skip these reserved entries from              \
176      relocation.  */                                                    \
177   i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;                         \
178   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;                   \
179                                                                         \
180   /* Add the run-time displacement to all local got entries. */         \
181   while (i < n)                                                         \
182     got[i++] += map->l_addr;                                            \
183                                                                         \
184   /* Handle global got entries. */                                      \
185   got += n;                                                             \
186   sym = (ElfW(Sym) *) D_PTR(map, l_info[DT_SYMTAB])                     \
187        + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;                     \
188   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val                      \
189        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);                    \
190                                                                         \
191   while (i--)                                                           \
192     {                                                                   \
193       if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)    \
194         *got = map->l_addr + sym->st_value;                             \
195       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC                 \
196                && *got != sym->st_value)                                \
197         *got += map->l_addr;                                            \
198       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)             \
199         {                                                               \
200           if (sym->st_other == 0)                                       \
201             *got += map->l_addr;                                        \
202         }                                                               \
203       else                                                              \
204         *got = map->l_addr + sym->st_value;                             \
205                                                                         \
206       got++;                                                            \
207       sym++;                                                            \
208     }                                                                   \
209 } while(0)
210
211
212 /* Mask identifying addresses reserved for the user program,
213    where the dynamic linker should not map anything.  */
214 #define ELF_MACHINE_USER_ADDRESS_MASK   0x80000000UL
215
216
217 /* Initial entry point code for the dynamic linker.
218    The C function `_dl_start' is the real entry point;
219    its return value is the user program's entry point.
220    Note how we have to be careful about two things:
221
222    1) That we allocate a minimal stack of 24 bytes for
223       every function call, the MIPS ABI states that even
224       if all arguments are passed in registers the procedure
225       called can use the 16 byte area pointed to by $sp
226       when it is called to store away the arguments passed
227       to it.
228
229    2) That under Linux the entry is named __start
230       and not just plain _start.  */
231
232 #define RTLD_START asm (\
233         ".text\n\
234         " _RTLD_PROLOGUE(ENTRY_POINT) "\
235         " STRINGXV(SETUP_GPX($25)) "\n\
236         " STRINGXV(SETUP_GPX64($18,$25)) "\n\
237         # i386 ABI book says that the first entry of GOT holds\n\
238         # the address of the dynamic structure. Though MIPS ABI\n\
239         # doesn't say nothing about this, I emulate this here.\n\
240         " STRINGXP(PTR_LA) " $4, _DYNAMIC\n\
241         # Subtract OFFSET_GP_GOT\n\
242         " STRINGXP(PTR_S) " $4, -0x7ff0($28)\n\
243         move $4, $29\n\
244         " STRINGXP(PTR_SUBIU) " $29, 16\n\
245         \n\
246         " STRINGXP(PTR_LA) " $8, .Lcoff\n\
247         bltzal $8, .Lcoff\n\
248 .Lcoff: " STRINGXP(PTR_SUBU) " $8, $31, $8\n\
249         \n\
250         " STRINGXP(PTR_LA) " $25, _dl_start\n\
251         " STRINGXP(PTR_ADDU) " $25, $8\n\
252         jalr $25\n\
253         \n\
254         " STRINGXP(PTR_ADDIU) " $29, 16\n\
255         # Get the value of label '_dl_start_user' in t9 ($25).\n\
256         " STRINGXP(PTR_LA) " $25, _dl_start_user\n\
257         " _RTLD_EPILOGUE(ENTRY_POINT) "\
258         \n\
259         \n\
260         " _RTLD_PROLOGUE(_dl_start_user) "\
261         " STRINGXP(SETUP_GP) "\n\
262         " STRINGXV(SETUP_GP64($18,_dl_start_user)) "\n\
263         move $16, $28\n\
264         # Save the user entry point address in a saved register.\n\
265         move $17, $2\n\
266         # See if we were run as a command with the executable file\n\
267         # name as an extra leading argument.\n\
268         lw $2, _dl_skip_args\n\
269         beq $2, $0, 1f\n\
270         # Load the original argument count.\n\
271         " STRINGXP(PTR_L) " $4, 0($29)\n\
272         # Subtract _dl_skip_args from it.\n\
273         subu $4, $2\n\
274         # Adjust the stack pointer to skip _dl_skip_args words.\n\
275         sll $2, " STRINGXP (PTRLOG) "\n\
276         " STRINGXP(PTR_ADDU) " $29, $2\n\
277         # Save back the modified argument count.\n\
278         " STRINGXP(PTR_S) " $4, 0($29)\n\
279 1:      # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
280         " STRINGXP(PTR_L) " $4, _rtld_local\n\
281         " STRINGXP(PTR_L) /* or lw???  fixme */ " $5, 0($29)\n\
282         " STRINGXP(PTR_LA) " $6, " STRINGXP (PTRSIZE) "($29)\n\
283         sll $7, $5, " STRINGXP (PTRLOG) "\n\
284         " STRINGXP(PTR_ADDU) " $7, $7, $6\n\
285         " STRINGXP(PTR_ADDU) " $7, $7, " STRINGXP (PTRSIZE) " \n\
286         # Make sure the stack pointer is aligned for _dl_init_internal.\n\
287         and $2, $29, -2 * " STRINGXP(SZREG) "\n\
288         " STRINGXP(PTR_S) " $29, -" STRINGXP(SZREG) "($2)\n\
289         " STRINGXP(PTR_SUBIU) " $29, $2, 32\n\
290         " STRINGXP(SAVE_GP(16)) "\n\
291         # Call the function to run the initializers.\n\
292         jal _dl_init_internal\n\
293         # Restore the stack pointer for _start.\n\
294         " STRINGXP(PTR_L)  " $29, 32-" STRINGXP(SZREG) "($29)\n\
295         # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
296         " STRINGXP(PTR_LA) " $2, _dl_fini\n\
297         # Jump to the user entry point.\n\
298         move $25, $17\n\
299         jr $25\n\t"\
300         _RTLD_EPILOGUE(_dl_start_user)\
301         ".previous"\
302 );
303
304 /* Names of the architecture-specific auditing callback functions.  */
305 # if _MIPS_SIM == _ABIO32
306 #  define ARCH_LA_PLTENTER mips_o32_gnu_pltenter
307 #  define ARCH_LA_PLTEXIT mips_o32_gnu_pltexit
308 # elif _MIPS_SIM == _ABIN32
309 #  define ARCH_LA_PLTENTER mips_n32_gnu_pltenter
310 #  define ARCH_LA_PLTEXIT mips_n32_gnu_pltexit
311 # else
312 #  define ARCH_LA_PLTENTER mips_n64_gnu_pltenter
313 #  define ARCH_LA_PLTEXIT mips_n64_gnu_pltexit
314 # endif
315
316 /* For a non-writable PLT, rewrite the .got.plt entry at RELOC_ADDR to
317    point at the symbol with address VALUE.  For a writable PLT, rewrite
318    the corresponding PLT entry instead.  */
319 static inline ElfW(Addr)
320 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
321                        const ElfW(Rel) *reloc,
322                        ElfW(Addr) *reloc_addr, ElfW(Addr) value)
323 {
324   return *reloc_addr = value;
325 }
326
327 static inline ElfW(Addr)
328 elf_machine_plt_value (struct link_map *map, const ElfW(Rel) *reloc,
329                        ElfW(Addr) value)
330 {
331   return value;
332 }
333
334 #endif /* !dl_machine_h */
335
336 #ifdef RESOLVE_MAP
337
338 /* Perform a relocation described by R_INFO at the location pointed to
339    by RELOC_ADDR.  SYM is the relocation symbol specified by R_INFO and
340    MAP is the object containing the reloc.  */
341
342 auto inline void
343 __attribute__ ((always_inline))
344 elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info,
345                    const ElfW(Sym) *sym, const struct r_found_version *version,
346                    void *reloc_addr, ElfW(Addr) r_addend, int inplace_p)
347 {
348   const unsigned long int r_type = ELFW(R_TYPE) (r_info);
349   ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
350
351 #if !defined RTLD_BOOTSTRAP && !defined SHARED
352   /* This is defined in rtld.c, but nowhere in the static libc.a;
353      make the reference weak so static programs can still link.  This
354      declaration cannot be done when compiling rtld.c (i.e.  #ifdef
355      RTLD_BOOTSTRAP) because rtld.c contains the common defn for
356      _dl_rtld_map, which is incompatible with a weak decl in the same
357      file.  */
358   weak_extern (GL(dl_rtld_map));
359 #endif
360
361   switch (r_type)
362     {
363 #if defined (USE_TLS) && !defined (RTLD_BOOTSTRAP)
364 # if _MIPS_SIM == _ABI64
365     case R_MIPS_TLS_DTPMOD64:
366     case R_MIPS_TLS_DTPREL64:
367     case R_MIPS_TLS_TPREL64:
368 # else
369     case R_MIPS_TLS_DTPMOD32:
370     case R_MIPS_TLS_DTPREL32:
371     case R_MIPS_TLS_TPREL32:
372 # endif
373       {
374         struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
375
376         switch (r_type)
377           {
378           case R_MIPS_TLS_DTPMOD64:
379           case R_MIPS_TLS_DTPMOD32:
380             if (sym_map)
381               *addr_field = sym_map->l_tls_modid;
382             break;
383
384           case R_MIPS_TLS_DTPREL64:
385           case R_MIPS_TLS_DTPREL32:
386             if (sym)
387               {
388                 if (inplace_p)
389                   r_addend = *addr_field;
390                 *addr_field = r_addend + TLS_DTPREL_VALUE (sym);
391               }
392             break;
393
394           case R_MIPS_TLS_TPREL32:
395           case R_MIPS_TLS_TPREL64:
396             if (sym)
397               {
398                 CHECK_STATIC_TLS (map, sym_map);
399                 if (inplace_p)
400                   r_addend = *addr_field;
401                 *addr_field = r_addend + TLS_TPREL_VALUE (sym_map, sym);
402               }
403             break;
404           }
405
406         break;
407       }
408 #endif
409
410 #if _MIPS_SIM == _ABI64
411     case (R_MIPS_64 << 8) | R_MIPS_REL32:
412 #else
413     case R_MIPS_REL32:
414 #endif
415       {
416         int symidx = ELFW(R_SYM) (r_info);
417         ElfW(Addr) reloc_value;
418
419         if (inplace_p)
420           /* Support relocations on mis-aligned offsets.  */
421           __builtin_memcpy (&reloc_value, reloc_addr, sizeof (reloc_value));
422         else
423           reloc_value = r_addend;
424
425         if (symidx)
426           {
427             const ElfW(Word) gotsym
428               = (const ElfW(Word)) map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
429
430             if ((ElfW(Word))symidx < gotsym)
431               {
432                 /* This wouldn't work for a symbol imported from other
433                    libraries for which there's no GOT entry, but MIPS
434                    requires every symbol referenced in a dynamic
435                    relocation to have a GOT entry in the primary GOT,
436                    so we only get here for locally-defined symbols.
437                    For section symbols, we should *NOT* be adding
438                    sym->st_value (per the definition of the meaning of
439                    S in reloc expressions in the ELF64 MIPS ABI),
440                    since it should have already been added to
441                    reloc_value by the linker, but older versions of
442                    GNU ld didn't add it, and newer versions don't emit
443                    useless relocations to section symbols any more, so
444                    it is safe to keep on adding sym->st_value, even
445                    though it's not ABI compliant.  Some day we should
446                    bite the bullet and stop doing this.  */
447 #ifndef RTLD_BOOTSTRAP
448                 if (map != &GL(dl_rtld_map))
449 #endif
450                   reloc_value += sym->st_value + map->l_addr;
451               }
452             else
453               {
454 #ifndef RTLD_BOOTSTRAP
455                 const ElfW(Addr) *got
456                   = (const ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
457                 const ElfW(Word) local_gotno
458                   = (const ElfW(Word))
459                     map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
460
461                 reloc_value += got[symidx + local_gotno - gotsym];
462 #endif
463               }
464           }
465         else
466 #ifndef RTLD_BOOTSTRAP
467           if (map != &GL(dl_rtld_map))
468 #endif
469             reloc_value += map->l_addr;
470
471         __builtin_memcpy (reloc_addr, &reloc_value, sizeof (reloc_value));
472       }
473       break;
474 #ifndef RTLD_BOOTSTRAP
475 #if _MIPS_SIM == _ABI64
476     case (R_MIPS_64 << 8) | R_MIPS_GLOB_DAT:
477 #else
478     case R_MIPS_GLOB_DAT:
479 #endif
480       {
481         int symidx = ELFW(R_SYM) (r_info);
482         const ElfW(Word) gotsym
483           = (const ElfW(Word)) map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
484
485         if (__builtin_expect ((ElfW(Word)) symidx >= gotsym, 1))
486           {
487             const ElfW(Addr) *got
488               = (const ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
489             const ElfW(Word) local_gotno
490               = ((const ElfW(Word))
491                  map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val);
492
493             ElfW(Addr) reloc_value = got[symidx + local_gotno - gotsym];
494             __builtin_memcpy (reloc_addr, &reloc_value, sizeof (reloc_value));
495           }
496       }
497       break;
498 #endif
499     case R_MIPS_NONE:           /* Alright, Wilbur.  */
500       break;
501
502     case R_MIPS_JUMP_SLOT:
503       {
504         struct link_map *sym_map;
505         ElfW(Addr) value;
506
507         /* The addend for a jump slot relocation must always be zero:
508            calls via the PLT always branch to the symbol's address and
509            not to the address plus a non-zero offset.  */
510         if (r_addend != 0)
511           _dl_signal_error (0, map->l_name, NULL,
512                             "found jump slot relocation with non-zero addend");
513
514         sym_map = RESOLVE_MAP (&sym, version, r_type);
515         value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
516         *addr_field = value;
517
518         break;
519       }
520
521     case R_MIPS_COPY:
522       {
523         const ElfW(Sym) *const refsym = sym;
524         struct link_map *sym_map;
525         ElfW(Addr) value;
526
527         /* Calculate the address of the symbol.  */
528         sym_map = RESOLVE_MAP (&sym, version, r_type);
529         value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
530
531         if (__builtin_expect (sym == NULL, 0))
532           /* This can happen in trace mode if an object could not be
533              found.  */
534           break;
535         if (__builtin_expect (sym->st_size > refsym->st_size, 0)
536             || (__builtin_expect (sym->st_size < refsym->st_size, 0)
537                 && GLRO(dl_verbose)))
538           {
539             const char *strtab;
540
541             strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
542             _dl_error_printf ("\
543   %s: Symbol `%s' has different size in shared object, consider re-linking\n",
544                               rtld_progname ?: "<program name unknown>",
545                               strtab + refsym->st_name);
546           }
547         memcpy (reloc_addr, (void *) value,
548                 MIN (sym->st_size, refsym->st_size));
549         break;
550       }
551
552 #if _MIPS_SIM == _ABI64
553     case R_MIPS_64:
554       /* For full compliance with the ELF64 ABI, one must precede the
555          _REL32/_64 pair of relocations with a _64 relocation, such
556          that the in-place addend is read as a 64-bit value.  IRIX
557          didn't pick up on this requirement, so we treat the
558          _REL32/_64 relocation as a 64-bit relocation even if it's by
559          itself.  For ABI compliance, we ignore such _64 dummy
560          relocations.  For RELA, this may be simply removed, since
561          it's totally unnecessary.  */
562       if (ELFW(R_SYM) (r_info) == 0)
563         break;
564       /* Fall through.  */
565 #endif
566     default:
567       _dl_reloc_bad_type (map, r_type, 0);
568       break;
569     }
570 }
571
572 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
573    MAP is the object containing the reloc.  */
574
575 auto inline void
576 __attribute__ ((always_inline))
577 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
578                  const ElfW(Sym) *sym, const struct r_found_version *version,
579                  void *const reloc_addr)
580 {
581   elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1);
582 }
583
584 auto inline void
585 __attribute__((always_inline))
586 elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
587                           void *const reloc_addr)
588 {
589   /* XXX Nothing to do.  There is no relative relocation, right?  */
590 }
591
592 auto inline void
593 __attribute__((always_inline))
594 elf_machine_lazy_rel (struct link_map *map,
595                       ElfW(Addr) l_addr, const ElfW(Rel) *reloc)
596 {
597   ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
598   const unsigned int r_type = ELFW(R_TYPE) (reloc->r_info);
599   /* Check for unexpected PLT reloc type.  */
600   if (__builtin_expect (r_type == R_MIPS_JUMP_SLOT, 1))
601     {
602       if (__builtin_expect (map->l_mach.plt, 0) == 0)
603         {
604           /* Nothing is required here since we only support lazy
605              relocation in executables.  */
606         }
607       else
608         *reloc_addr = map->l_mach.plt;
609     }
610   else
611     _dl_reloc_bad_type (map, r_type, 1);
612 }
613
614 auto inline void
615 __attribute__ ((always_inline))
616 elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
617                   const ElfW(Sym) *sym, const struct r_found_version *version,
618                  void *const reloc_addr)
619 {
620   elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr,
621                      reloc->r_addend, 0);
622 }
623
624 auto inline void
625 __attribute__((always_inline))
626 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
627                            void *const reloc_addr)
628 {
629 }
630
631 #ifndef RTLD_BOOTSTRAP
632 /* Relocate GOT. */
633 auto inline void
634 __attribute__((always_inline))
635 elf_machine_got_rel (struct link_map *map, int lazy)
636 {
637   ElfW(Addr) *got;
638   ElfW(Sym) *sym;
639   const ElfW(Half) *vernum;
640   int i, n, symidx;
641
642 #define RESOLVE_GOTSYM(sym,vernum,sym_index,reloc)                        \
643     ({                                                                    \
644       const ElfW(Sym) *ref = sym;                                         \
645       const struct r_found_version *version                               \
646         = vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL;   \
647       struct link_map *sym_map;                                           \
648       sym_map = RESOLVE_MAP (&ref, version, reloc);                       \
649       ref ? sym_map->l_addr + ref->st_value : 0;                          \
650     })
651
652   if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
653     vernum = (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
654   else
655     vernum = NULL;
656
657   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
658
659   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
660   /* The dynamic linker's local got entries have already been relocated.  */
661   if (map != &GL(dl_rtld_map))
662     {
663       /* got[0] is reserved. got[1] is also reserved for the dynamic object
664          generated by gnu ld. Skip these reserved entries from relocation.  */
665       i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
666
667       /* Add the run-time displacement to all local got entries if
668          needed.  */
669       if (__builtin_expect (map->l_addr != 0, 0))
670         {
671           while (i < n)
672             got[i++] += map->l_addr;
673         }
674     }
675
676   /* Handle global got entries. */
677   got += n;
678   /* Keep track of the symbol index.  */
679   symidx = map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
680   sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]) + symidx;
681   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
682        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
683
684   /* This loop doesn't handle Quickstart.  */
685   while (i--)
686     {
687       if (sym->st_shndx == SHN_UNDEF)
688         {
689           if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_value
690               && !(sym->st_other & STO_MIPS_PLT))
691             {
692               if (lazy)
693                 *got = sym->st_value + map->l_addr;
694               else
695                 /* This is a lazy-binding stub, so we don't need the
696                    canonical address.  */
697                 *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_JUMP_SLOT);
698             }
699           else
700             *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
701         }
702       else if (sym->st_shndx == SHN_COMMON)
703         *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
704       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
705                && *got != sym->st_value)
706         {
707           if (lazy)
708             *got += map->l_addr;
709           else
710             /* This is a lazy-binding stub, so we don't need the
711                canonical address.  */
712             *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_JUMP_SLOT);
713         }
714       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
715         {
716           if (sym->st_other == 0)
717             *got += map->l_addr;
718         }
719       else
720         *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
721
722       ++got;
723       ++sym;
724       ++symidx;
725     }
726
727 #undef RESOLVE_GOTSYM
728 }
729 #endif
730
731 /* Set up the loaded object described by L so its stub function
732    will jump to the on-demand fixup code __dl_runtime_resolve.  */
733
734 auto inline int
735 __attribute__((always_inline))
736 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
737 {
738 # ifndef RTLD_BOOTSTRAP
739   ElfW(Addr) *got;
740   extern void _dl_runtime_resolve (ElfW(Word));
741   extern void _dl_runtime_pltresolve (void);
742   extern int _dl_mips_gnu_objects;
743
744   if (lazy)
745     {
746       /* The GOT entries for functions have not yet been filled in.
747          Their initial contents will arrange when called to put an
748          offset into the .dynsym section in t8, the return address
749          in t7 and then jump to _GLOBAL_OFFSET_TABLE[0].  */
750       got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
751
752       /* This function will get called to fix up the GOT entry indicated by
753          the register t8, and then jump to the resolved address.  */
754       got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
755
756       /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
757          of got[1] of a gnu object is set to identify gnu objects.
758          Where we can store l for non gnu objects? XXX  */
759       if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
760         got[1] = ((ElfW(Addr)) l | ELF_MIPS_GNU_GOT1_MASK);
761       else
762         _dl_mips_gnu_objects = 0;
763     }
764
765   /* Relocate global offset table.  */
766   elf_machine_got_rel (l, lazy);
767
768   /* If using PLTs, fill in the first two entries of .got.plt.  */
769   if (l->l_info[DT_JMPREL] && lazy)
770     {
771       ElfW(Addr) *gotplt;
772       gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_MIPS (PLTGOT)]);
773       /* If a library is prelinked but we have to relocate anyway,
774          we have to be able to undo the prelinking of .got.plt.
775          The prelinker saved the address of .plt for us here.  */
776       if (gotplt[1])
777         l->l_mach.plt = gotplt[1] + l->l_addr;
778       gotplt[0] = (ElfW(Addr)) &_dl_runtime_pltresolve;
779       gotplt[1] = (ElfW(Addr)) l;
780     }
781
782 # endif
783   return lazy;
784 }
785
786 #endif /* RESOLVE_MAP */