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