]>
git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/mips/dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions. MIPS version.
2 Copyright (C) 1996-2012 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>.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 /* FIXME: Profiling of shared libraries is not implemented yet. */
25 #define ELF_MACHINE_NAME "MIPS"
30 #error ENTRY_POINT needs to be defined for MIPS.
37 /* The offset of gp from GOT might be system-dependent. It's set by
38 ld. The same value is also */
39 #define OFFSET_GP_GOT 0x7ff0
41 #ifndef _RTLD_PROLOGUE
42 # define _RTLD_PROLOGUE(entry) \
43 ".globl\t" __STRING(entry) "\n\t" \
44 ".ent\t" __STRING(entry) "\n\t" \
45 ".type\t" __STRING(entry) ", @function\n" \
46 __STRING(entry) ":\n\t"
49 #ifndef _RTLD_EPILOGUE
50 # define _RTLD_EPILOGUE(entry) \
51 ".end\t" __STRING(entry) "\n\t" \
52 ".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
55 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
56 This only makes sense on MIPS when using PLTs, so choose the
57 PLT relocation (not encountered when not using PLTs). */
58 #define ELF_MACHINE_JMP_SLOT R_MIPS_JUMP_SLOT
59 #define elf_machine_type_class(type) \
60 ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
61 | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
63 #define ELF_MACHINE_PLT_REL 1
65 /* Translate a processor specific dynamic tag to the index
67 #define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
69 /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
70 with the run-time address of the r_debug structure */
71 #define ELF_MACHINE_DEBUG_SETUP(l,r) \
72 do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
73 *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
77 /* Return nonzero iff ELF header is compatible with the running host. */
78 static inline int __attribute_used__
79 elf_machine_matches_host (const ElfW(Ehdr
) *ehdr
)
81 #if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
82 /* Don't link o32 and n32 together. */
83 if (((ehdr
->e_flags
& EF_MIPS_ABI2
) != 0) != (_MIPS_SIM
== _ABIN32
))
87 switch (ehdr
->e_machine
)
97 static inline ElfW(Addr
) *
98 elf_mips_got_from_gpreg (ElfW(Addr
) gpreg
)
100 /* FIXME: the offset of gp from GOT may be system-dependent. */
101 return (ElfW(Addr
) *) (gpreg
- OFFSET_GP_GOT
);
104 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
105 first element of the GOT. This must be inlined in a function which
106 uses global data. We assume its $gp points to the primary GOT. */
107 static inline ElfW(Addr
)
108 elf_machine_dynamic (void)
110 register ElfW(Addr
) gp
__asm__ ("$28");
111 return *elf_mips_got_from_gpreg (gp
);
114 #define STRINGXP(X) __STRING(X)
115 #define STRINGXV(X) STRINGV_(X)
116 #define STRINGV_(...) # __VA_ARGS__
118 /* Return the run-time load address of the shared object. */
119 static inline ElfW(Addr
)
120 elf_machine_load_address (void)
123 asm (" .set noreorder\n"
124 " " STRINGXP (PTR_LA
) " %0, 0f\n"
127 "0: " STRINGXP (PTR_SUBU
) " %0, $31, %0\n"
135 /* The MSB of got[1] of a gnu object is set to identify gnu objects. */
136 #if _MIPS_SIM == _ABI64
137 # define ELF_MIPS_GNU_GOT1_MASK 0x8000000000000000L
139 # define ELF_MIPS_GNU_GOT1_MASK 0x80000000L
142 /* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
143 fiddles with global data. */
144 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) \
146 struct link_map *map = &bootstrap_map; \
151 got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]); \
153 if (__builtin_expect (map->l_addr == 0, 1)) \
156 /* got[0] is reserved. got[1] is also reserved for the dynamic object \
157 generated by gnu ld. Skip these reserved entries from \
159 i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1; \
160 n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val; \
162 /* Add the run-time displacement to all local got entries. */ \
164 got[i++] += map->l_addr; \
166 /* Handle global got entries. */ \
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); \
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) \
182 if (sym->st_other == 0) \
183 *got += map->l_addr; \
186 *got = map->l_addr + sym->st_value; \
194 /* Mask identifying addresses reserved for the user program,
195 where the dynamic linker should not map anything. */
196 #define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
199 /* Initial entry point code for the dynamic linker.
200 The C function `_dl_start' is the real entry point;
201 its return value is the user program's entry point.
202 Note how we have to be careful about two things:
204 1) That we allocate a minimal stack of 24 bytes for
205 every function call, the MIPS ABI states that even
206 if all arguments are passed in registers the procedure
207 called can use the 16 byte area pointed to by $sp
208 when it is called to store away the arguments passed
211 2) That under Linux the entry is named __start
212 and not just plain _start. */
214 #define RTLD_START asm (\
216 " _RTLD_PROLOGUE(ENTRY_POINT) "\
217 " STRINGXV(SETUP_GPX($25)) "\n\
218 " STRINGXV(SETUP_GPX64($18,$25)) "\n\
219 # i386 ABI book says that the first entry of GOT holds\n\
220 # the address of the dynamic structure. Though MIPS ABI\n\
221 # doesn't say nothing about this, I emulate this here.\n\
222 " STRINGXP(PTR_LA) " $4, _DYNAMIC\n\
223 # Subtract OFFSET_GP_GOT\n\
224 " STRINGXP(PTR_S) " $4, -0x7ff0($28)\n\
226 " STRINGXP(PTR_SUBIU) " $29, 16\n\
228 " STRINGXP(PTR_LA) " $8, .Lcoff\n\
230 .Lcoff: " STRINGXP(PTR_SUBU) " $8, $31, $8\n\
232 " STRINGXP(PTR_LA) " $25, _dl_start\n\
233 " STRINGXP(PTR_ADDU) " $25, $8\n\
236 " STRINGXP(PTR_ADDIU) " $29, 16\n\
237 # Get the value of label '_dl_start_user' in t9 ($25).\n\
238 " STRINGXP(PTR_LA) " $25, _dl_start_user\n\
239 " _RTLD_EPILOGUE(ENTRY_POINT) "\
242 " _RTLD_PROLOGUE(_dl_start_user) "\
243 " STRINGXP(SETUP_GP) "\n\
244 " STRINGXV(SETUP_GP64($18,_dl_start_user)) "\n\
246 # Save the user entry point address in a saved register.\n\
248 # See if we were run as a command with the executable file\n\
249 # name as an extra leading argument.\n\
250 lw $2, _dl_skip_args\n\
252 # Load the original argument count.\n\
253 " STRINGXP(PTR_L) " $4, 0($29)\n\
254 # Subtract _dl_skip_args from it.\n\
256 # Adjust the stack pointer to skip _dl_skip_args words.\n\
257 sll $2, " STRINGXP (PTRLOG) "\n\
258 " STRINGXP(PTR_ADDU) " $29, $2\n\
259 # Save back the modified argument count.\n\
260 " STRINGXP(PTR_S) " $4, 0($29)\n\
261 1: # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
262 " STRINGXP(PTR_L) " $4, _rtld_local\n\
263 " STRINGXP(PTR_L) /* or lw??? fixme */ " $5, 0($29)\n\
264 " STRINGXP(PTR_LA) " $6, " STRINGXP (PTRSIZE) "($29)\n\
265 sll $7, $5, " STRINGXP (PTRLOG) "\n\
266 " STRINGXP(PTR_ADDU) " $7, $7, $6\n\
267 " STRINGXP(PTR_ADDU) " $7, $7, " STRINGXP (PTRSIZE) " \n\
268 # Make sure the stack pointer is aligned for _dl_init_internal.\n\
269 and $2, $29, -2 * " STRINGXP(SZREG) "\n\
270 " STRINGXP(PTR_S) " $29, -" STRINGXP(SZREG) "($2)\n\
271 " STRINGXP(PTR_SUBIU) " $29, $2, 32\n\
272 " STRINGXP(SAVE_GP(16)) "\n\
273 # Call the function to run the initializers.\n\
274 jal _dl_init_internal\n\
275 # Restore the stack pointer for _start.\n\
276 " STRINGXP(PTR_L) " $29, 32-" STRINGXP(SZREG) "($29)\n\
277 # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
278 " STRINGXP(PTR_LA) " $2, _dl_fini\n\
279 # Jump to the user entry point.\n\
282 _RTLD_EPILOGUE(_dl_start_user)\
286 /* Names of the architecture-specific auditing callback functions. */
287 # if _MIPS_SIM == _ABIO32
288 # define ARCH_LA_PLTENTER mips_o32_gnu_pltenter
289 # define ARCH_LA_PLTEXIT mips_o32_gnu_pltexit
290 # elif _MIPS_SIM == _ABIN32
291 # define ARCH_LA_PLTENTER mips_n32_gnu_pltenter
292 # define ARCH_LA_PLTEXIT mips_n32_gnu_pltexit
294 # define ARCH_LA_PLTENTER mips_n64_gnu_pltenter
295 # define ARCH_LA_PLTEXIT mips_n64_gnu_pltexit
298 /* We define an initialization function. This is called very early in
300 #define DL_PLATFORM_INIT dl_platform_init ()
302 static inline void __attribute__ ((unused
))
303 dl_platform_init (void)
305 if (GLRO(dl_platform
) != NULL
&& *GLRO(dl_platform
) == '\0')
306 /* Avoid an empty string which would disturb us. */
307 GLRO(dl_platform
) = NULL
;
310 /* For a non-writable PLT, rewrite the .got.plt entry at RELOC_ADDR to
311 point at the symbol with address VALUE. For a writable PLT, rewrite
312 the corresponding PLT entry instead. */
313 static inline ElfW(Addr
)
314 elf_machine_fixup_plt (struct link_map
*map
, lookup_t t
,
315 const ElfW(Rel
) *reloc
,
316 ElfW(Addr
) *reloc_addr
, ElfW(Addr
) value
)
318 return *reloc_addr
= value
;
321 static inline ElfW(Addr
)
322 elf_machine_plt_value (struct link_map
*map
, const ElfW(Rel
) *reloc
,
328 #endif /* !dl_machine_h */
332 /* Perform a relocation described by R_INFO at the location pointed to
333 by RELOC_ADDR. SYM is the relocation symbol specified by R_INFO and
334 MAP is the object containing the reloc. */
337 __attribute__ ((always_inline
))
338 elf_machine_reloc (struct link_map
*map
, ElfW(Addr
) r_info
,
339 const ElfW(Sym
) *sym
, const struct r_found_version
*version
,
340 void *reloc_addr
, ElfW(Addr
) r_addend
, int inplace_p
)
342 const unsigned long int r_type
= ELFW(R_TYPE
) (r_info
);
343 ElfW(Addr
) *addr_field
= (ElfW(Addr
) *) reloc_addr
;
345 #if !defined RTLD_BOOTSTRAP && !defined SHARED
346 /* This is defined in rtld.c, but nowhere in the static libc.a;
347 make the reference weak so static programs can still link. This
348 declaration cannot be done when compiling rtld.c (i.e. #ifdef
349 RTLD_BOOTSTRAP) because rtld.c contains the common defn for
350 _dl_rtld_map, which is incompatible with a weak decl in the same
352 weak_extern (GL(dl_rtld_map
));
357 #if !defined (RTLD_BOOTSTRAP)
358 # if _MIPS_SIM == _ABI64
359 case R_MIPS_TLS_DTPMOD64
:
360 case R_MIPS_TLS_DTPREL64
:
361 case R_MIPS_TLS_TPREL64
:
363 case R_MIPS_TLS_DTPMOD32
:
364 case R_MIPS_TLS_DTPREL32
:
365 case R_MIPS_TLS_TPREL32
:
368 struct link_map
*sym_map
= RESOLVE_MAP (&sym
, version
, r_type
);
372 case R_MIPS_TLS_DTPMOD64
:
373 case R_MIPS_TLS_DTPMOD32
:
375 *addr_field
= sym_map
->l_tls_modid
;
378 case R_MIPS_TLS_DTPREL64
:
379 case R_MIPS_TLS_DTPREL32
:
383 r_addend
= *addr_field
;
384 *addr_field
= r_addend
+ TLS_DTPREL_VALUE (sym
);
388 case R_MIPS_TLS_TPREL32
:
389 case R_MIPS_TLS_TPREL64
:
392 CHECK_STATIC_TLS (map
, sym_map
);
394 r_addend
= *addr_field
;
395 *addr_field
= r_addend
+ TLS_TPREL_VALUE (sym_map
, sym
);
404 #if _MIPS_SIM == _ABI64
405 case (R_MIPS_64
<< 8) | R_MIPS_REL32
:
410 int symidx
= ELFW(R_SYM
) (r_info
);
411 ElfW(Addr
) reloc_value
;
414 /* Support relocations on mis-aligned offsets. */
415 __builtin_memcpy (&reloc_value
, reloc_addr
, sizeof (reloc_value
));
417 reloc_value
= r_addend
;
421 const ElfW(Word
) gotsym
422 = (const ElfW(Word
)) map
->l_info
[DT_MIPS (GOTSYM
)]->d_un
.d_val
;
424 if ((ElfW(Word
))symidx
< gotsym
)
426 /* This wouldn't work for a symbol imported from other
427 libraries for which there's no GOT entry, but MIPS
428 requires every symbol referenced in a dynamic
429 relocation to have a GOT entry in the primary GOT,
430 so we only get here for locally-defined symbols.
431 For section symbols, we should *NOT* be adding
432 sym->st_value (per the definition of the meaning of
433 S in reloc expressions in the ELF64 MIPS ABI),
434 since it should have already been added to
435 reloc_value by the linker, but older versions of
436 GNU ld didn't add it, and newer versions don't emit
437 useless relocations to section symbols any more, so
438 it is safe to keep on adding sym->st_value, even
439 though it's not ABI compliant. Some day we should
440 bite the bullet and stop doing this. */
441 #ifndef RTLD_BOOTSTRAP
442 if (map
!= &GL(dl_rtld_map
))
444 reloc_value
+= sym
->st_value
+ map
->l_addr
;
448 #ifndef RTLD_BOOTSTRAP
449 const ElfW(Addr
) *got
450 = (const ElfW(Addr
) *) D_PTR (map
, l_info
[DT_PLTGOT
]);
451 const ElfW(Word
) local_gotno
453 map
->l_info
[DT_MIPS (LOCAL_GOTNO
)]->d_un
.d_val
;
455 reloc_value
+= got
[symidx
+ local_gotno
- gotsym
];
460 #ifndef RTLD_BOOTSTRAP
461 if (map
!= &GL(dl_rtld_map
))
463 reloc_value
+= map
->l_addr
;
465 __builtin_memcpy (reloc_addr
, &reloc_value
, sizeof (reloc_value
));
468 #ifndef RTLD_BOOTSTRAP
469 #if _MIPS_SIM == _ABI64
470 case (R_MIPS_64
<< 8) | R_MIPS_GLOB_DAT
:
472 case R_MIPS_GLOB_DAT
:
475 int symidx
= ELFW(R_SYM
) (r_info
);
476 const ElfW(Word
) gotsym
477 = (const ElfW(Word
)) map
->l_info
[DT_MIPS (GOTSYM
)]->d_un
.d_val
;
479 if (__builtin_expect ((ElfW(Word
)) symidx
>= gotsym
, 1))
481 const ElfW(Addr
) *got
482 = (const ElfW(Addr
) *) D_PTR (map
, l_info
[DT_PLTGOT
]);
483 const ElfW(Word
) local_gotno
484 = ((const ElfW(Word
))
485 map
->l_info
[DT_MIPS (LOCAL_GOTNO
)]->d_un
.d_val
);
487 ElfW(Addr
) reloc_value
= got
[symidx
+ local_gotno
- gotsym
];
488 __builtin_memcpy (reloc_addr
, &reloc_value
, sizeof (reloc_value
));
493 case R_MIPS_NONE
: /* Alright, Wilbur. */
496 case R_MIPS_JUMP_SLOT
:
498 struct link_map
*sym_map
;
501 /* The addend for a jump slot relocation must always be zero:
502 calls via the PLT always branch to the symbol's address and
503 not to the address plus a non-zero offset. */
505 _dl_signal_error (0, map
->l_name
, NULL
,
506 "found jump slot relocation with non-zero addend");
508 sym_map
= RESOLVE_MAP (&sym
, version
, r_type
);
509 value
= sym_map
== NULL
? 0 : sym_map
->l_addr
+ sym
->st_value
;
517 const ElfW(Sym
) *const refsym
= sym
;
518 struct link_map
*sym_map
;
521 /* Calculate the address of the symbol. */
522 sym_map
= RESOLVE_MAP (&sym
, version
, r_type
);
523 value
= sym_map
== NULL
? 0 : sym_map
->l_addr
+ sym
->st_value
;
525 if (__builtin_expect (sym
== NULL
, 0))
526 /* This can happen in trace mode if an object could not be
529 if (__builtin_expect (sym
->st_size
> refsym
->st_size
, 0)
530 || (__builtin_expect (sym
->st_size
< refsym
->st_size
, 0)
531 && GLRO(dl_verbose
)))
535 strtab
= (const void *) D_PTR (map
, l_info
[DT_STRTAB
]);
537 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
538 rtld_progname
?: "<program name unknown>",
539 strtab
+ refsym
->st_name
);
541 memcpy (reloc_addr
, (void *) value
,
542 MIN (sym
->st_size
, refsym
->st_size
));
546 #if _MIPS_SIM == _ABI64
548 /* For full compliance with the ELF64 ABI, one must precede the
549 _REL32/_64 pair of relocations with a _64 relocation, such
550 that the in-place addend is read as a 64-bit value. IRIX
551 didn't pick up on this requirement, so we treat the
552 _REL32/_64 relocation as a 64-bit relocation even if it's by
553 itself. For ABI compliance, we ignore such _64 dummy
554 relocations. For RELA, this may be simply removed, since
555 it's totally unnecessary. */
556 if (ELFW(R_SYM
) (r_info
) == 0)
561 _dl_reloc_bad_type (map
, r_type
, 0);
566 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
567 MAP is the object containing the reloc. */
570 __attribute__ ((always_inline
))
571 elf_machine_rel (struct link_map
*map
, const ElfW(Rel
) *reloc
,
572 const ElfW(Sym
) *sym
, const struct r_found_version
*version
,
573 void *const reloc_addr
, int skip_ifunc
)
575 elf_machine_reloc (map
, reloc
->r_info
, sym
, version
, reloc_addr
, 0, 1);
579 __attribute__((always_inline
))
580 elf_machine_rel_relative (ElfW(Addr
) l_addr
, const ElfW(Rel
) *reloc
,
581 void *const reloc_addr
)
583 /* XXX Nothing to do. There is no relative relocation, right? */
587 __attribute__((always_inline
))
588 elf_machine_lazy_rel (struct link_map
*map
,
589 ElfW(Addr
) l_addr
, const ElfW(Rel
) *reloc
,
592 ElfW(Addr
) *const reloc_addr
= (void *) (l_addr
+ reloc
->r_offset
);
593 const unsigned int r_type
= ELFW(R_TYPE
) (reloc
->r_info
);
594 /* Check for unexpected PLT reloc type. */
595 if (__builtin_expect (r_type
== R_MIPS_JUMP_SLOT
, 1))
597 if (__builtin_expect (map
->l_mach
.plt
, 0) == 0)
599 /* Nothing is required here since we only support lazy
600 relocation in executables. */
603 *reloc_addr
= map
->l_mach
.plt
;
606 _dl_reloc_bad_type (map
, r_type
, 1);
610 __attribute__ ((always_inline
))
611 elf_machine_rela (struct link_map
*map
, const ElfW(Rela
) *reloc
,
612 const ElfW(Sym
) *sym
, const struct r_found_version
*version
,
613 void *const reloc_addr
, int skip_ifunc
)
615 elf_machine_reloc (map
, reloc
->r_info
, sym
, version
, reloc_addr
,
620 __attribute__((always_inline
))
621 elf_machine_rela_relative (ElfW(Addr
) l_addr
, const ElfW(Rela
) *reloc
,
622 void *const reloc_addr
)
626 #ifndef RTLD_BOOTSTRAP
629 __attribute__((always_inline
))
630 elf_machine_got_rel (struct link_map
*map
, int lazy
)
634 const ElfW(Half
) *vernum
;
637 #define RESOLVE_GOTSYM(sym,vernum,sym_index,reloc) \
639 const ElfW(Sym) *ref = sym; \
640 const struct r_found_version *version \
641 = vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL; \
642 struct link_map *sym_map; \
643 sym_map = RESOLVE_MAP (&ref, version, reloc); \
644 ref ? sym_map->l_addr + ref->st_value : 0; \
647 if (map
->l_info
[VERSYMIDX (DT_VERSYM
)] != NULL
)
648 vernum
= (const void *) D_PTR (map
, l_info
[VERSYMIDX (DT_VERSYM
)]);
652 got
= (ElfW(Addr
) *) D_PTR (map
, l_info
[DT_PLTGOT
]);
654 n
= map
->l_info
[DT_MIPS (LOCAL_GOTNO
)]->d_un
.d_val
;
655 /* The dynamic linker's local got entries have already been relocated. */
656 if (map
!= &GL(dl_rtld_map
))
658 /* got[0] is reserved. got[1] is also reserved for the dynamic object
659 generated by gnu ld. Skip these reserved entries from relocation. */
660 i
= (got
[1] & ELF_MIPS_GNU_GOT1_MASK
)? 2 : 1;
662 /* Add the run-time displacement to all local got entries if
664 if (__builtin_expect (map
->l_addr
!= 0, 0))
667 got
[i
++] += map
->l_addr
;
671 /* Handle global got entries. */
673 /* Keep track of the symbol index. */
674 symidx
= map
->l_info
[DT_MIPS (GOTSYM
)]->d_un
.d_val
;
675 sym
= (ElfW(Sym
) *) D_PTR (map
, l_info
[DT_SYMTAB
]) + symidx
;
676 i
= (map
->l_info
[DT_MIPS (SYMTABNO
)]->d_un
.d_val
677 - map
->l_info
[DT_MIPS (GOTSYM
)]->d_un
.d_val
);
679 /* This loop doesn't handle Quickstart. */
682 if (sym
->st_shndx
== SHN_UNDEF
)
684 if (ELFW(ST_TYPE
) (sym
->st_info
) == STT_FUNC
&& sym
->st_value
685 && !(sym
->st_other
& STO_MIPS_PLT
))
688 *got
= sym
->st_value
+ map
->l_addr
;
690 /* This is a lazy-binding stub, so we don't need the
691 canonical address. */
692 *got
= RESOLVE_GOTSYM (sym
, vernum
, symidx
, R_MIPS_JUMP_SLOT
);
695 *got
= RESOLVE_GOTSYM (sym
, vernum
, symidx
, R_MIPS_32
);
697 else if (sym
->st_shndx
== SHN_COMMON
)
698 *got
= RESOLVE_GOTSYM (sym
, vernum
, symidx
, R_MIPS_32
);
699 else if (ELFW(ST_TYPE
) (sym
->st_info
) == STT_FUNC
700 && *got
!= sym
->st_value
)
705 /* This is a lazy-binding stub, so we don't need the
706 canonical address. */
707 *got
= RESOLVE_GOTSYM (sym
, vernum
, symidx
, R_MIPS_JUMP_SLOT
);
709 else if (ELFW(ST_TYPE
) (sym
->st_info
) == STT_SECTION
)
711 if (sym
->st_other
== 0)
715 *got
= RESOLVE_GOTSYM (sym
, vernum
, symidx
, R_MIPS_32
);
722 #undef RESOLVE_GOTSYM
726 /* Set up the loaded object described by L so its stub function
727 will jump to the on-demand fixup code __dl_runtime_resolve. */
730 __attribute__((always_inline
))
731 elf_machine_runtime_setup (struct link_map
*l
, int lazy
, int profile
)
733 # ifndef RTLD_BOOTSTRAP
735 extern void _dl_runtime_resolve (ElfW(Word
));
736 extern void _dl_runtime_pltresolve (void);
737 extern int _dl_mips_gnu_objects
;
741 /* The GOT entries for functions have not yet been filled in.
742 Their initial contents will arrange when called to put an
743 offset into the .dynsym section in t8, the return address
744 in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */
745 got
= (ElfW(Addr
) *) D_PTR (l
, l_info
[DT_PLTGOT
]);
747 /* This function will get called to fix up the GOT entry indicated by
748 the register t8, and then jump to the resolved address. */
749 got
[0] = (ElfW(Addr
)) &_dl_runtime_resolve
;
751 /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
752 of got[1] of a gnu object is set to identify gnu objects.
753 Where we can store l for non gnu objects? XXX */
754 if ((got
[1] & ELF_MIPS_GNU_GOT1_MASK
) != 0)
755 got
[1] = ((ElfW(Addr
)) l
| ELF_MIPS_GNU_GOT1_MASK
);
757 _dl_mips_gnu_objects
= 0;
760 /* Relocate global offset table. */
761 elf_machine_got_rel (l
, lazy
);
763 /* If using PLTs, fill in the first two entries of .got.plt. */
764 if (l
->l_info
[DT_JMPREL
] && lazy
)
767 gotplt
= (ElfW(Addr
) *) D_PTR (l
, l_info
[DT_MIPS (PLTGOT
)]);
768 /* If a library is prelinked but we have to relocate anyway,
769 we have to be able to undo the prelinking of .got.plt.
770 The prelinker saved the address of .plt for us here. */
772 l
->l_mach
.plt
= gotplt
[1] + l
->l_addr
;
773 gotplt
[0] = (ElfW(Addr
)) &_dl_runtime_pltresolve
;
774 gotplt
[1] = (ElfW(Addr
)) l
;
781 #endif /* RESOLVE_MAP */