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