Partly revert patch from 2000-10-18.
[platform/upstream/linaro-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 ELF header is compatible with the running host.  */
90 static inline int __attribute__ ((unused))
91 elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
92 {
93   switch (ehdr->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   if (__builtin_expect (map->l_addr == 0, 1))                           \
153     goto done;                                                          \
154                                                                         \
155   /* got[0] is reserved. got[1] is also reserved for the dynamic object \
156      generated by gnu ld. Skip these reserved entries from              \
157      relocation.  */                                                    \
158   i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;                         \
159   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;                   \
160                                                                         \
161   /* Add the run-time display to all local got entries. */              \
162   while (i < n)                                                         \
163     got[i++] += map->l_addr;                                            \
164                                                                         \
165   /* Handle global got entries. */                                      \
166   got += n;                                                             \
167   sym = (ElfW(Sym) *) D_PTR(map, l_info[DT_SYMTAB])                     \
168        + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;                     \
169   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val                      \
170        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);                    \
171                                                                         \
172   while (i--)                                                           \
173     {                                                                   \
174       if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)    \
175         *got = map->l_addr + sym->st_value;                             \
176       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC                 \
177                && *got != sym->st_value)                                \
178         *got += map->l_addr;                                            \
179       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)             \
180         {                                                               \
181           if (sym->st_other == 0)                                       \
182             *got += map->l_addr;                                        \
183         }                                                               \
184       else                                                              \
185         *got = map->l_addr + sym->st_value;                             \
186                                                                         \
187       got++;                                                            \
188       sym++;                                                            \
189     }                                                                   \
190 done:                                                                   \
191 } while(0)
192
193
194 /* Get link map for callers object containing STUB_PC.  */
195 static inline struct link_map *
196 elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
197 {
198   extern int _dl_mips_gnu_objects;
199
200   /* got[1] is reserved to keep its link map address for the shared
201      object generated by the gnu linker.  If all are such objects, we
202      can find the link map from current GPREG simply.  If not so, get
203      the link map for caller's object containing STUB_PC.  */
204
205   if (_dl_mips_gnu_objects)
206     {
207       ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
208       ElfW(Word) g1;
209
210       g1 = ((ElfW(Word) *) got)[1];
211
212       if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
213         {
214           struct link_map *l =
215             (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
216           ElfW(Addr) base, limit;
217           const ElfW(Phdr) *p = l->l_phdr;
218           ElfW(Half) this, nent = l->l_phnum;
219
220           /* For the common case of a stub being called from the containing
221              object, STUB_PC will point to somewhere within the object that
222              is described by the link map fetched via got[1].  Otherwise we
223              have to scan all maps.  */
224           for (this = 0; this < nent; this++)
225             {
226               if (p[this].p_type == PT_LOAD)
227                 {
228                   base = p[this].p_vaddr + l->l_addr;
229                   limit = base + p[this].p_memsz;
230                   if (stub_pc >= base && stub_pc < limit)
231                     return l;
232                 }
233             }
234         }
235     }
236
237     {
238       struct link_map *l = _dl_loaded;
239
240       while (l)
241         {
242           ElfW(Addr) base, limit;
243           const ElfW(Phdr) *p = l->l_phdr;
244           ElfW(Half) this, nent = l->l_phnum;
245
246           for (this = 0; this < nent; ++this)
247             {
248               if (p[this].p_type == PT_LOAD)
249                 {
250                   base = p[this].p_vaddr + l->l_addr;
251                   limit = base + p[this].p_memsz;
252                   if (stub_pc >= base && stub_pc < limit)
253                     return l;
254                 }
255             }
256           l = l->l_next;
257         }
258     }
259
260   _dl_signal_error (0, NULL, "cannot find runtime link map");
261   return NULL;
262 }
263
264 /* Define mips specific runtime resolver. The function __dl_runtime_resolve
265    is called from assembler function _dl_runtime_resolve which converts
266    special argument registers t7 ($15) and t8 ($24):
267      t7  address to return to the caller of the function
268      t8  index for this function symbol in .dynsym
269    to usual c arguments.
270
271    Other architectures call fixup from dl-runtime.c in
272    _dl_runtime_resolve.  MIPS instead calls __dl_runtime_resolve.  We
273    have to use our own version because of the way the got section is
274    treated on MIPS (we've also got ELF_MACHINE_PLT defined).  */
275
276 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                                        \
277 /* The flag _dl_mips_gnu_objects is set if all dynamic objects are            \
278    generated by the gnu linker. */                                            \
279 int _dl_mips_gnu_objects = 1;                                                 \
280                                                                               \
281 /* This is called from assembly stubs below which the compiler can't see.  */ \
282 static ElfW(Addr)                                                             \
283 __dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))         \
284                   __attribute__ ((unused));                                   \
285                                                                               \
286 static ElfW(Addr)                                                             \
287 __dl_runtime_resolve (ElfW(Word) sym_index,                                   \
288                       ElfW(Word) return_address,                              \
289                       ElfW(Addr) old_gpreg,                                   \
290                       ElfW(Addr) stub_pc)                                     \
291 {                                                                             \
292   struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);     \
293   const ElfW(Sym) *const symtab                                               \
294     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);                            \
295   const char *strtab                                                          \
296     = (const void *) D_PTR (l, l_info[DT_STRTAB]);                            \
297   const ElfW(Addr) *got                                                       \
298     = (const ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);                      \
299   const ElfW(Word) local_gotno                                                \
300     = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;        \
301   const ElfW(Word) gotsym                                                     \
302     = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;             \
303   const ElfW(Sym) *sym = &symtab[sym_index];                                  \
304   ElfW(Addr) value;                                                           \
305                                                                               \
306   /* FIXME: The symbol versioning stuff is not tested yet.  */                \
307   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)         \
308     {                                                                         \
309       switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)                       \
310         {                                                                     \
311         default:                                                              \
312           {                                                                   \
313             const ElfW(Half) *vernum =                                        \
314               (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);        \
315             ElfW(Half) ndx = vernum[sym_index];                               \
316             const struct r_found_version *version = &l->l_versions[ndx];      \
317                                                                               \
318             if (version->hash != 0)                                           \
319               {                                                               \
320                 value = _dl_lookup_versioned_symbol(strtab + sym->st_name, l, \
321                                                     &sym, l->l_scope, version,\
322                                                     R_MIPS_REL32, 0);         \
323                 break;                                                        \
324               }                                                               \
325             /* Fall through.  */                                              \
326           }                                                                   \
327         case 0:                                                               \
328           value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,          \
329                                      l->l_scope, R_MIPS_REL32, 0);            \
330         }                                                                     \
331                                                                               \
332       /* Currently value contains the base load address of the object         \
333          that defines sym.  Now add in the symbol offset.  */                 \
334       value = (sym ? value + sym->st_value : 0);                              \
335     }                                                                         \
336   else                                                                        \
337     /* We already found the symbol.  The module (and therefore its load       \
338        address) is also known.  */                                            \
339     value = l->l_addr + sym->st_value;                                        \
340                                                                               \
341   /* Apply the relocation with that value.  */                                \
342   *(got + local_gotno + sym_index - gotsym) = value;                          \
343                                                                               \
344   return value;                                                               \
345 }                                                                             \
346                                                                               \
347 asm ("\n                                                                      \
348         .text\n                                                               \
349         .align  2\n                                                           \
350         .globl  _dl_runtime_resolve\n                                         \
351         .type   _dl_runtime_resolve,@function\n                               \
352         .ent    _dl_runtime_resolve\n                                         \
353 _dl_runtime_resolve:\n                                                        \
354         .frame  $29, 40, $31\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, 16($29)\n                                                 \
370         sw      $5, 20($29)\n                                                 \
371         sw      $6, 24($29)\n                                                 \
372         sw      $7, 28($29)\n                                                 \
373         move    $4, $24\n                                                     \
374         move    $5, $15\n                                                     \
375         move    $6, $3\n                                                      \
376         move    $7, $2\n                                                      \
377         jal     __dl_runtime_resolve\n                                        \
378         lw      $31, 36($29)\n                                                \
379         lw      $4, 16($29)\n                                                 \
380         lw      $5, 20($29)\n                                                 \
381         lw      $6, 24($29)\n                                                 \
382         lw      $7, 28($29)\n                                                 \
383         addu    $29, 40\n                                                     \
384         move    $25, $2\n                                                     \
385         jr      $25\n                                                         \
386         .end    _dl_runtime_resolve\n                                         \
387         .previous\n                                                           \
388 ");
389
390 /* Mask identifying addresses reserved for the user program,
391    where the dynamic linker should not map anything.  */
392 #define ELF_MACHINE_USER_ADDRESS_MASK   0x80000000UL
393
394
395
396 /* Initial entry point code for the dynamic linker.
397    The C function `_dl_start' is the real entry point;
398    its return value is the user program's entry point.
399    Note how we have to be careful about two things:
400
401    1) That we allocate a minimal stack of 24 bytes for
402       every function call, the MIPS ABI states that even
403       if all arguments are passed in registers the procedure
404       called can use the 16 byte area pointed to by $sp
405       when it is called to store away the arguments passed
406       to it.
407
408    2) That under Linux the entry is named __start
409       and not just plain _start.  */
410
411 #define RTLD_START asm (\
412         ".text\n"\
413         _RTLD_PROLOGUE(ENTRY_POINT)\
414         ".set noreorder\n\
415         .set noreorder\n\
416         bltzal $0, 0f\n\
417         nop\n\
418 0:      .cpload $31\n\
419         .set reorder\n\
420         # i386 ABI book says that the first entry of GOT holds\n\
421         # the address of the dynamic structure. Though MIPS ABI\n\
422         # doesn't say nothing about this, I emulate this here.\n\
423         la $4, _DYNAMIC\n\
424         # Subtract OFFSET_GP_GOT\n\
425         sw $4, -0x7ff0($28)\n\
426         move $4, $29\n\
427         subu $29, 16\n\
428         \n\
429         la $8, coff\n\
430         bltzal $8, coff\n\
431 coff:   subu $8, $31, $8\n\
432         \n\
433         la $25, _dl_start\n\
434         addu $25, $8\n\
435         jalr $25\n\
436         \n\
437         addiu $29, 16\n\
438         # Get the value of label '_dl_start_user' in t9 ($25).\n\
439         la $25, _dl_start_user\n\
440         .globl _dl_start_user\n\
441 _dl_start_user:\n\
442         .set noreorder\n\
443         .cpload $25\n\
444         .set reorder\n\
445         move $16, $28\n\
446         # Save the user entry point address in a saved register.\n\
447         move $17, $2\n\
448         # Store the highest stack address\n\
449         sw $29, __libc_stack_end\n\
450         # See if we were run as a command with the executable file\n\
451         # name as an extra leading argument.\n\
452         lw $2, _dl_skip_args\n\
453         beq $2, $0, 1f\n\
454         # Load the original argument count.\n\
455         lw $4, 0($29)\n\
456         # Subtract _dl_skip_args from it.\n\
457         subu $4, $2\n\
458         # Adjust the stack pointer to skip _dl_skip_args words.\n\
459         sll $2, 2\n\
460         addu $29, $2\n\
461         # Save back the modified argument count.\n\
462         sw $4, 0($29)\n\
463 1:      # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
464         lw $4, _dl_loaded\n\
465         lw $5, 0($29)\n\
466         la $6, 4($29)\n\
467         sll $7, $5, 2\n\
468         addu $7, $7, $6\n\
469         addu $7, $7, 4\n\
470         subu $29, 16\n\
471         # Call the function to run the initializers.\n\
472         jal _dl_init
473         addiu $29, 16\n\
474         # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
475         la $2, _dl_fini\n\
476         # Jump to the user entry point.\n\
477         move $25, $17\n\
478         jr $25\n\t"\
479         _RTLD_EPILOGUE(ENTRY_POINT)\
480         ".previous"\
481 );
482
483 /* The MIPS never uses Elfxx_Rela relocations.  */
484 #define ELF_MACHINE_NO_RELA 1
485
486 #endif /* !dl_machine_h */
487
488 #ifdef RESOLVE
489
490 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
491    MAP is the object containing the reloc.  */
492
493 static inline void
494 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
495                  const ElfW(Sym) *sym, const struct r_found_version *version,
496                  ElfW(Addr) *const reloc_addr)
497 {
498 #ifndef RTLD_BOOTSTRAP
499   /* This is defined in rtld.c, but nowhere in the static libc.a;
500      make the reference weak so static programs can still link.  This
501      declaration cannot be done when compiling rtld.c (i.e.  #ifdef
502      RTLD_BOOTSTRAP) because rtld.c contains the common defn for
503      _dl_rtld_map, which is incompatible with a weak decl in the same
504      file.  */
505   weak_extern (_dl_rtld_map);
506 #endif
507
508   switch (ELFW(R_TYPE) (reloc->r_info))
509     {
510     case R_MIPS_REL32:
511 #ifndef RTLD_BOOTSTRAP
512       if (map != &_dl_rtld_map)
513 #endif
514         *reloc_addr += map->l_addr;
515       break;
516     case R_MIPS_NONE:           /* Alright, Wilbur.  */
517       break;
518     default:
519       _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
520       break;
521     }
522 }
523
524 static inline void
525 elf_machine_lazy_rel (struct link_map *map,
526                       ElfW(Addr) l_addr, const ElfW(Rel) *reloc)
527 {
528   /* Do nothing.  */
529 }
530
531 /* Relocate GOT. */
532 static inline void
533 elf_machine_got_rel (struct link_map *map, int lazy)
534 {
535   ElfW(Addr) *got;
536   ElfW(Sym) *sym;
537   int i, n, symidx;
538   /*  This function is loaded in dl-reloc as a nested function and can
539       therefore access the variables scope and strtab from
540       _dl_relocate_object.  */
541 #ifdef RTLD_BOOTSTRAP
542 # define RESOLVE_GOTSYM(sym,sym_index) 0
543 #else
544 # define RESOLVE_GOTSYM(sym,sym_index)                                    \
545     ({                                                                    \
546       const ElfW(Sym) *ref = sym;                                         \
547       ElfW(Addr) value;                                                   \
548                                                                           \
549       switch (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)                 \
550         {                                                                 \
551         default:                                                          \
552           {                                                               \
553             const ElfW(Half) *vernum =                                    \
554               (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);  \
555             ElfW(Half) ndx = vernum[sym_index];                           \
556             const struct r_found_version *version = &l->l_versions[ndx];  \
557                                                                           \
558             if (version->hash != 0)                                       \
559               {                                                           \
560                 value = _dl_lookup_versioned_symbol(strtab + sym->st_name,\
561                                                     map,                  \
562                                                     &ref, scope, version, \
563                                                     R_MIPS_REL32, 0);     \
564                 break;                                                    \
565               }                                                           \
566             /* Fall through.  */                                          \
567           }                                                               \
568         case 0:                                                           \
569           value = _dl_lookup_symbol (strtab + sym->st_name, map, &ref,    \
570                                      scope, R_MIPS_REL32, 0);             \
571         }                                                                 \
572                                                                           \
573       (ref)? value + ref->st_value: 0;                                    \
574     })
575 #endif /* RTLD_BOOTSTRAP */
576
577   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
578
579   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
580   /* The dynamic linker's local got entries have already been relocated.  */
581   if (map != &_dl_rtld_map)
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
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
595   /* Handle global got entries. */
596   got += n;
597   /* Keep track of the symbol index.  */
598   symidx = map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
599   sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]) + symidx;
600   i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
601        - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
602
603   /* This loop doesn't handle Quickstart.  */
604   while (i--)
605     {
606       if (sym->st_shndx == SHN_UNDEF)
607         {
608           if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
609               && sym->st_value && lazy)
610             *got = sym->st_value + map->l_addr;
611           else
612             *got = RESOLVE_GOTSYM (sym, symidx);
613         }
614       else if (sym->st_shndx == SHN_COMMON)
615         *got = RESOLVE_GOTSYM (sym, symidx);
616       else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
617                && *got != sym->st_value
618                && lazy)
619         *got += map->l_addr;
620       else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
621         {
622           if (sym->st_other == 0)
623             *got += map->l_addr;
624         }
625       else
626         *got = RESOLVE_GOTSYM (sym, symidx);
627
628       ++got;
629       ++sym;
630       ++symidx;
631     }
632
633 #undef RESOLVE_GOTSYM
634
635   return;
636 }
637
638 /* Set up the loaded object described by L so its stub function
639    will jump to the on-demand fixup code __dl_runtime_resolve.  */
640
641 static inline int
642 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
643 {
644 # ifndef RTLD_BOOTSTRAP
645   ElfW(Addr) *got;
646   extern void _dl_runtime_resolve (ElfW(Word));
647   extern int _dl_mips_gnu_objects;
648
649   if (lazy)
650     {
651       /* The GOT entries for functions have not yet been filled in.
652          Their initial contents will arrange when called to put an
653          offset into the .dynsym section in t8, the return address
654          in t7 and then jump to _GLOBAL_OFFSET_TABLE[0].  */
655       got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
656
657       /* This function will get called to fix up the GOT entry indicated by
658          the register t8, and then jump to the resolved address.  */
659       got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
660
661       /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
662          of got[1] of a gnu object is set to identify gnu objects.
663          Where we can store l for non gnu objects? XXX  */
664       if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
665         got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK);
666       else
667         _dl_mips_gnu_objects = 0;
668     }
669
670   /* Relocate global offset table.  */
671   elf_machine_got_rel (l, lazy);
672
673 # endif
674   return lazy;
675 }
676
677 #endif /* RESOLVE */