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