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