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