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