Update.
[platform/upstream/glibc.git] / sysdeps / mips / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  MIPS version.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000 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 Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 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 /* The offset of gp from GOT might be system-dependent.  It's set by
36    ld.  The same value is also */
37 #define OFFSET_GP_GOT 0x7ff0
38
39 #ifndef _RTLD_PROLOGUE
40 # define _RTLD_PROLOGUE(entry)                                          \
41         ".globl\t" __STRING(entry) "\n\t"                               \
42         ".ent\t" __STRING(entry) "\n\t"                                 \
43         ".type\t" __STRING(entry) ", @function\n"                       \
44         __STRING(entry) ":\n\t"
45 #endif
46
47 #ifndef _RTLD_EPILOGUE
48 # define _RTLD_EPILOGUE(entry)                                          \
49         ".end\t" __STRING(entry) "\n\t"                                 \
50         ".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
51 #endif
52
53 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
54    This makes no sense on MIPS but we have to define this to R_MIPS_REL32
55    to avoid the asserts in dl-lookup.c from blowing.  */
56 #define ELF_MACHINE_JMP_SLOT                    R_MIPS_REL32
57 #define elf_machine_lookup_noplt_p(type)        (1)
58 #define elf_machine_lookup_noexec_p(type)       (0)
59
60 /* Translate a processor specific dynamic tag to the index
61    in l_info array.  */
62 #define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
63
64 /*
65  * MIPS libraries are usually linked to a non-zero base address.  We
66  * subtract the base address from the address where we map the object
67  * to.  This results in more efficient address space usage.
68  *
69  * FIXME: By the time when MAP_BASE_ADDR is called we don't have the
70  * DYNAMIC section read.  Until this is fixed make the assumption that
71  * libraries have their base address at 0x5ffe0000.  This needs to be
72  * fixed before we can safely get rid of this MIPSism.
73  */
74 #if 0
75 #define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \
76                           (l)->l_info[DT_MIPS(BASE_ADDRESS)]->d_un.d_ptr : 0)
77 #else
78 #define MAP_BASE_ADDR(l) 0x5ffe0000
79 #endif
80
81 /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
82    with the run-time address of the r_debug structure  */
83 #define ELF_MACHINE_DEBUG_SETUP(l,r) \
84 do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
85        *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
86        (ElfW(Addr)) (r); \
87    } while (0)
88
89 /* Return nonzero iff E_MACHINE is compatible with the running host.  */
90 static inline int __attribute__ ((unused))
91 elf_machine_matches_host (ElfW(Half) e_machine)
92 {
93   switch (e_machine)
94     {
95     case EM_MIPS:
96     case EM_MIPS_RS3_LE:
97       return 1;
98     default:
99       return 0;
100     }
101 }
102
103 static inline ElfW(Addr) *
104 elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
105 {
106   /* FIXME: the offset of gp from GOT may be system-dependent. */
107   return (ElfW(Addr) *) (gpreg - OFFSET_GP_GOT);
108 }
109
110 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
111    first element of the GOT.  This must be inlined in a function which
112    uses global data.  */
113 static inline ElfW(Addr)
114 elf_machine_dynamic (void)
115 {
116   register ElfW(Addr) gp __asm__ ("$28");
117   return *elf_mips_got_from_gpreg (gp);
118 }
119
120
121 /* Return the run-time load address of the shared object.  */
122 static inline ElfW(Addr)
123 elf_machine_load_address (void)
124 {
125   ElfW(Addr) addr;
126   asm ("        .set noreorder\n"
127        "        la %0, here\n"
128        "        bltzal $0, here\n"
129        "        nop\n"
130        "here:   subu %0, $31, %0\n"
131        "        .set reorder\n"
132        :        "=r" (addr)
133        :        /* No inputs */
134        :        "$31");
135   return addr;
136 }
137
138 /* The MSB of got[1] of a gnu object is set to identify gnu objects.  */
139 #define ELF_MIPS_GNU_GOT1_MASK 0x80000000
140
141 /* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
142    fiddles with global data.  */
143 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)                     \
144 do {                                                                    \
145   struct link_map *map = &bootstrap_map;                                \
146   ElfW(Sym) *sym;                                                       \
147   ElfW(Addr) *got;                                                      \
148   int i, n;                                                             \
149                                                                         \
150   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);                  \
151                                                                         \
152                                                                         \
153   if (__builtin_expect (map->l_addr == 0, 1))                           \
154     goto done;                                                          \
155                                                                         \
156   /* got[0] is reserved. got[1] is also reserved for the dynamic object \
157      generated by gnu ld. Skip these reserved entries from              \
158      relocation.  */                                                    \
159   i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;                         \
160   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;                   \
161                                                                         \
162   /* Add the run-time display to all local got entries. */              \
163   while (i < n)                                                         \
164     got[i++] += map->l_addr;                                            \
165                                                                         \
166   /* Handle global got entries. */                                      \
167   got += n;                                                             \
168   sym = (ElfW(Sym) *) D_PTR(map, l_info[DT_SYMTAB])                     \
169        + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;                     \
170   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val                      \
171        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);                    \
172                                                                         \
173   while (i--)                                                           \
174     {                                                                   \
175       if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)    \
176         *got = map->l_addr + sym->st_value;                             \
177       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC                 \
178                && *got != sym->st_value)                                \
179         *got += map->l_addr;                                            \
180       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)             \
181         {                                                               \
182           if (sym->st_other == 0)                                       \
183             *got += map->l_addr;                                        \
184         }                                                               \
185       else                                                              \
186         *got = map->l_addr + sym->st_value;                             \
187                                                                         \
188       got++;                                                            \
189       sym++;                                                            \
190     }                                                                   \
191 done:                                                                   \
192 } while(0)
193
194
195 /* Get link map for callers object containing STUB_PC.  */
196 static inline struct link_map *
197 elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
198 {
199   extern int _dl_mips_gnu_objects;
200
201   /* got[1] is reserved to keep its link map address for the shared
202      object generated by the gnu linker.  If all are such objects, we
203      can find the link map from current GPREG simply.  If not so, get
204      the link map for caller's object containing STUB_PC.  */
205
206   if (_dl_mips_gnu_objects)
207     {
208       ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
209       ElfW(Word) g1;
210
211       g1 = ((ElfW(Word) *) got)[1];
212
213       if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
214         {
215           struct link_map *l =
216             (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
217           ElfW(Addr) base, limit;
218           const ElfW(Phdr) *p = l->l_phdr;
219           ElfW(Half) this, nent = l->l_phnum;
220
221           /* For the common case of a stub being called from the containing
222              object, STUB_PC will point to somewhere within the object that
223              is described by the link map fetched via got[1].  Otherwise we
224              have to scan all maps.  */
225           for (this = 0; this < nent; this++)
226             {
227               if (p[this].p_type == PT_LOAD)
228                 {
229                   base = p[this].p_vaddr + l->l_addr;
230                   limit = base + p[this].p_memsz;
231                   if (stub_pc >= base && stub_pc < limit)
232                     return l;
233                 }
234             }
235         }
236     }
237
238     {
239       struct link_map *l = _dl_loaded;
240
241       while (l)
242         {
243           ElfW(Addr) base, limit;
244           const ElfW(Phdr) *p = l->l_phdr;
245           ElfW(Half) this, nent = l->l_phnum;
246
247           for (this = 0; this < nent; ++this)
248             {
249               if (p[this].p_type == PT_LOAD)
250                 {
251                   base = p[this].p_vaddr + l->l_addr;
252                   limit = base + p[this].p_memsz;
253                   if (stub_pc >= base && stub_pc < limit)
254                     return l;
255                 }
256             }
257           l = l->l_next;
258         }
259     }
260
261   _dl_signal_error (0, NULL, "cannot find runtime link map");
262   return NULL;
263 }
264
265 /* Define mips specific runtime resolver. The function __dl_runtime_resolve
266    is called from assembler function _dl_runtime_resolve which converts
267    special argument registers t7 ($15) and t8 ($24):
268      t7  address to return to the caller of the function
269      t8  index for this function symbol in .dynsym
270    to usual c arguments.
271
272    Other architectures call fixup from dl-runtime.c in
273    _dl_runtime_resolve.  MIPS instead calls __dl_runtime_resolve.  We
274    have to use our own version because of the way the got section is
275    treated on MIPS (we've also got ELF_MACHINE_PLT defined).  */
276
277 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                                        \
278 /* The flag _dl_mips_gnu_objects is set if all dynamic objects are            \
279    generated by the gnu linker. */                                            \
280 int _dl_mips_gnu_objects = 1;                                                 \
281                                                                               \
282 /* This is called from assembly stubs below which the compiler can't see.  */ \
283 static ElfW(Addr)                                                             \
284 __dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))         \
285                   __attribute__ ((unused));                                   \
286                                                                               \
287 static ElfW(Addr)                                                             \
288 __dl_runtime_resolve (ElfW(Word) sym_index,                                   \
289                       ElfW(Word) return_address,                              \
290                       ElfW(Addr) old_gpreg,                                   \
291                       ElfW(Addr) stub_pc)                                     \
292 {                                                                             \
293   struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);     \
294   const ElfW(Sym) *const symtab                                               \
295     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);                            \
296   const char *strtab                                                          \
297     = (const void *) D_PTR (l, l_info[DT_STRTAB]);                            \
298   const ElfW(Addr) *got                                                       \
299     = (const ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);                      \
300   const ElfW(Word) local_gotno                                                \
301     = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;        \
302   const ElfW(Word) gotsym                                                     \
303     = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;             \
304   const ElfW(Sym) *sym = &symtab[sym_index];                                  \
305   ElfW(Addr) value;                                                           \
306                                                                               \
307   /* FIXME: The symbol versioning stuff is not tested yet.  */                \
308   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)         \
309     {                                                                         \
310       switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)                       \
311         {                                                                     \
312         default:                                                              \
313           {                                                                   \
314             const ElfW(Half) *vernum =                                        \
315               (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);        \
316             ElfW(Half) ndx = vernum[sym_index];                               \
317             const struct r_found_version *version = &l->l_versions[ndx];      \
318                                                                               \
319             if (version->hash != 0)                                           \
320               {                                                               \
321                 value = _dl_lookup_versioned_symbol(strtab + sym->st_name, l, \
322                                                     &sym, l->l_scope, version,\
323                                                     R_MIPS_REL32, 0);         \
324                 break;                                                        \
325               }                                                               \
326             /* Fall through.  */                                              \
327           }                                                                   \
328         case 0:                                                               \
329           value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,          \
330                                      l->l_scope, R_MIPS_REL32, 0);            \
331         }                                                                     \
332                                                                               \
333       /* Currently value contains the base load address of the object         \
334          that defines sym.  Now add in the symbol offset.  */                 \
335       value = (sym ? value + sym->st_value : 0);                              \
336     }                                                                         \
337   else                                                                        \
338     /* We already found the symbol.  The module (and therefore its load       \
339        address) is also known.  */                                            \
340     value = l->l_addr + sym->st_value;                                        \
341                                                                               \
342   /* Apply the relocation with that value.  */                                \
343   *(got + local_gotno + sym_index - gotsym) = value;                          \
344                                                                               \
345   return value;                                                               \
346 }                                                                             \
347                                                                               \
348 asm ("\n                                                                      \
349         .text\n                                                               \
350         .align  2\n                                                           \
351         .globl  _dl_runtime_resolve\n                                         \
352         .type   _dl_runtime_resolve,@function\n                               \
353         .ent    _dl_runtime_resolve\n                                         \
354 _dl_runtime_resolve:\n                                                        \
355         .set noreorder\n                                                      \
356         # Save GP.\n                                                  \
357         move    $3, $28\n                                                     \
358         # Modify t9 ($25) so as to point .cpload instruction.\n               \
359         addu    $25,8\n                                                       \
360         # Compute GP.\n                                                       \
361         .cpload $25\n                                                         \
362         .set reorder\n                                                        \
363         # Save slot call pc.\n                                                \
364         move    $2, $31\n                                                     \
365         # Save arguments and sp value in stack.\n                             \
366         subu    $29, 40\n                                                     \
367         .cprestore 32\n                                                       \
368         sw      $15, 36($29)\n                                                \
369         sw      $4, 12($29)\n                                                 \
370         sw      $5, 16($29)\n                                                 \
371         sw      $6, 20($29)\n                                                 \
372         sw      $7, 24($29)\n                                                 \
373         sw      $16, 28($29)\n                                                \
374         move    $16, $29\n                                                    \
375         move    $4, $24\n                                                     \
376         move    $5, $15\n                                                     \
377         move    $6, $3\n                                                      \
378         move    $7, $2\n                                                      \
379         jal     __dl_runtime_resolve\n                                        \
380         move    $29, $16\n                                                    \
381         lw      $31, 36($29)\n                                                \
382         lw      $4, 12($29)\n                                                 \
383         lw      $5, 16($29)\n                                                 \
384         lw      $6, 20($29)\n                                                 \
385         lw      $7, 24($29)\n                                                 \
386         lw      $16, 28($29)\n                                                \
387         addu    $29, 40\n                                                     \
388         move    $25, $2\n                                                     \
389         jr      $25\n                                                         \
390         .end    _dl_runtime_resolve\n                                         \
391         .previous\n                                                           \
392 ");
393
394 /* Mask identifying addresses reserved for the user program,
395    where the dynamic linker should not map anything.  */
396 #define ELF_MACHINE_USER_ADDRESS_MASK   0x80000000UL
397
398
399
400 /* Initial entry point code for the dynamic linker.
401    The C function `_dl_start' is the real entry point;
402    its return value is the user program's entry point.
403    Note how we have to be careful about two things:
404
405    1) That we allocate a minimal stack of 24 bytes for
406       every function call, the MIPS ABI states that even
407       if all arguments are passed in registers the procedure
408       called can use the 16 byte area pointed to by $sp
409       when it is called to store away the arguments passed
410       to it.
411
412    2) That under Linux the entry is named __start
413       and not just plain _start.  */
414
415 #define RTLD_START asm (\
416         ".text\n"\
417         _RTLD_PROLOGUE(ENTRY_POINT)\
418         ".set noreorder\n\
419         .set noreorder\n\
420         bltzal $0, 0f\n\
421         nop\n\
422 0:      .cpload $31\n\
423         .set reorder\n\
424         # i386 ABI book says that the first entry of GOT holds\n\
425         # the address of the dynamic structure. Though MIPS ABI\n\
426         # doesn't say nothing about this, I emulate this here.\n\
427         la $4, _DYNAMIC\n\
428         # Subtract OFFSET_GP_GOT\n\
429         sw $4, -0x7ff0($28)\n\
430         move $4, $29\n\
431         subu $29, 16\n\
432         \n\
433         la $8, coff\n\
434         bltzal $8, coff\n\
435 coff:   subu $8, $31, $8\n\
436         \n\
437         la $25, _dl_start\n\
438         addu $25, $8\n\
439         jalr $25\n\
440         \n\
441         addiu $29, 16\n\
442         # Get the value of label '_dl_start_user' in t9 ($25).\n\
443         la $25, _dl_start_user\n\
444         .globl _dl_start_user\n\
445 _dl_start_user:\n\
446         .set noreorder\n\
447         .cpload $25\n\
448         .set reorder\n\
449         move $16, $28\n\
450         # Save the user entry point address in a saved register.\n\
451         move $17, $2\n\
452         # Store the highest stack address\n\
453         sw $29, __libc_stack_end\n\
454         # See if we were run as a command with the executable file\n\
455         # name as an extra leading argument.\n\
456         lw $2, _dl_skip_args\n\
457         beq $2, $0, 1f\n\
458         # Load the original argument count.\n\
459         lw $4, 0($29)\n\
460         # Subtract _dl_skip_args from it.\n\
461         subu $4, $2\n\
462         # Adjust the stack pointer to skip _dl_skip_args words.\n\
463         sll $2, 2\n\
464         addu $29, $2\n\
465         # Save back the modified argument count.\n\
466         sw $4, 0($29)\n\
467 1:      # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
468         lw $4, _dl_loaded\n\
469         lw $5, 0($29)\n\
470         la $6, 4($29)\n\
471         sll $7, $5, 2\n\
472         addu $7, $7, $6\n\
473         addu $7, $7, 4\n\
474         subu $29, 16\n\
475         # Call the function to run the initializers.\n\
476         jal _dl_init
477         addiu $29, 16\n\
478         # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
479         la $2, _dl_fini\n\
480         # Jump to the user entry point.\n\
481         move $25, $17\n\
482         jr $25\n\t"\
483         _RTLD_EPILOGUE(ENTRY_POINT)\
484         ".previous"\
485 );
486
487 /* The MIPS never uses Elfxx_Rela relocations.  */
488 #define ELF_MACHINE_NO_RELA 1
489
490 #endif /* !dl_machine_h */
491
492 #ifdef RESOLVE
493
494 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
495    MAP is the object containing the reloc.  */
496
497 static inline void
498 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
499                  const ElfW(Sym) *sym, const struct r_found_version *version,
500                  ElfW(Addr) *const reloc_addr)
501 {
502 #ifndef RTLD_BOOTSTRAP
503   /* This is defined in rtld.c, but nowhere in the static libc.a;
504      make the reference weak so static programs can still link.  This
505      declaration cannot be done when compiling rtld.c (i.e.  #ifdef
506      RTLD_BOOTSTRAP) because rtld.c contains the common defn for
507      _dl_rtld_map, which is incompatible with a weak decl in the same
508      file.  */
509   weak_extern (_dl_rtld_map);
510 #endif
511
512   switch (ELFW(R_TYPE) (reloc->r_info))
513     {
514     case R_MIPS_REL32:
515 #ifndef RTLD_BOOTSTRAP
516       if (map != &_dl_rtld_map)
517 #endif
518         *reloc_addr += map->l_addr;
519       break;
520     case R_MIPS_NONE:           /* Alright, Wilbur.  */
521       break;
522     default:
523       _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
524       break;
525     }
526 }
527
528 static inline void
529 elf_machine_lazy_rel (struct link_map *map,
530                       ElfW(Addr) l_addr, const ElfW(Rel) *reloc)
531 {
532   /* Do nothing.  */
533 }
534
535 /* Relocate GOT. */
536 static inline void
537 elf_machine_got_rel (struct link_map *map, int lazy)
538 {
539   ElfW(Addr) *got;
540   ElfW(Sym) *sym;
541   int i, n, symidx;
542   /*  This function is loaded in dl-reloc as a nested function and can
543       therefore access the variables scope and strtab from
544       _dl_relocate_object.  */
545 #ifdef RTLD_BOOTSTRAP
546 # define RESOLVE_GOTSYM(sym,sym_index) 0
547 #else
548 # define RESOLVE_GOTSYM(sym,sym_index)                                    \
549     ({                                                                    \
550       const ElfW(Sym) *ref = sym;                                         \
551       ElfW(Addr) value;                                                   \
552                                                                           \
553       switch (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)                 \
554         {                                                                 \
555         default:                                                          \
556           {                                                               \
557             const ElfW(Half) *vernum =                                    \
558               (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);  \
559             ElfW(Half) ndx = vernum[sym_index];                           \
560             const struct r_found_version *version = &l->l_versions[ndx];  \
561                                                                           \
562             if (version->hash != 0)                                       \
563               {                                                           \
564                 value = _dl_lookup_versioned_symbol(strtab + sym->st_name,\
565                                                     map,                  \
566                                                     &ref, scope, version, \
567                                                     R_MIPS_REL32, 0);     \
568                 break;                                                    \
569               }                                                           \
570             /* Fall through.  */                                          \
571           }                                                               \
572         case 0:                                                           \
573           value = _dl_lookup_symbol (strtab + sym->st_name, map, &ref,    \
574                                      scope, R_MIPS_REL32, 0);             \
575         }                                                                 \
576                                                                           \
577       (ref)? value + ref->st_value: 0;                                    \
578     })
579 #endif /* RTLD_BOOTSTRAP */
580
581   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
582
583   /* got[0] is reserved. got[1] is also reserved for the dynamic object
584      generated by gnu ld. Skip these reserved entries from relocation.  */
585   i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
586   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
587   /* Add the run-time display to all local got entries if needed. */
588   if (__builtin_expect (map->l_addr != 0, 0))
589     {
590       while (i < n)
591         got[i++] += map->l_addr;
592     }
593
594   /* Handle global got entries. */
595   got += n;
596   /* Keep track of the symbol index.  */
597   symidx = map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
598   sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]) + symidx;
599   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
600        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
601
602   /* This loop doesn't handle Quickstart.  */
603   while (i--)
604     {
605       if (sym->st_shndx == SHN_UNDEF)
606         {
607           if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
608               && sym->st_value && lazy)
609             *got = sym->st_value + map->l_addr;
610           else
611             *got = RESOLVE_GOTSYM (sym, symidx);
612         }
613       else if (sym->st_shndx == SHN_COMMON)
614         *got = RESOLVE_GOTSYM (sym, symidx);
615       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
616                && *got != sym->st_value
617                && lazy)
618         *got += map->l_addr;
619       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
620         {
621           if (sym->st_other == 0)
622             *got += map->l_addr;
623         }
624       else
625         *got = RESOLVE_GOTSYM (sym, symidx);
626
627       ++got;
628       ++sym;
629       ++symidx;
630     }
631
632 #undef RESOLVE_GOTSYM
633
634   return;
635 }
636
637 /* Set up the loaded object described by L so its stub function
638    will jump to the on-demand fixup code __dl_runtime_resolve.  */
639
640 static inline int
641 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
642 {
643 # ifndef RTLD_BOOTSTRAP
644   ElfW(Addr) *got;
645   extern void _dl_runtime_resolve (ElfW(Word));
646   extern int _dl_mips_gnu_objects;
647
648   if (lazy)
649     {
650       /* The GOT entries for functions have not yet been filled in.
651          Their initial contents will arrange when called to put an
652          offset into the .dynsym section in t8, the return address
653          in t7 and then jump to _GLOBAL_OFFSET_TABLE[0].  */
654       got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
655
656       /* This function will get called to fix up the GOT entry indicated by
657          the register t8, and then jump to the resolved address.  */
658       got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
659
660       /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
661          of got[1] of a gnu object is set to identify gnu objects.
662          Where we can store l for non gnu objects? XXX  */
663       if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
664         got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK);
665       else
666         _dl_mips_gnu_objects = 0;
667     }
668
669   /* Relocate global offset table.  */
670   elf_machine_got_rel (l, lazy);
671
672 # endif
673   return lazy;
674 }
675
676 #endif /* RESOLVE */