]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/mips/dl-machine.h
Don't use INTDEF/INTUSE with _dl_init (bug 14132).
[thirdparty/glibc.git] / sysdeps / mips / dl-machine.h
CommitLineData
f1fc1823 1/* Machine-dependent ELF dynamic relocation inline functions. MIPS version.
d4697bc9 2 Copyright (C) 1996-2014 Free Software Foundation, Inc.
f1fc1823
UD
3 This file is part of the GNU C Library.
4 Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
8db38e6c 5
f1fc1823 6 The GNU C Library is free software; you can redistribute it and/or
3214b89b
AJ
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.
8db38e6c 10
f1fc1823
UD
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
3214b89b 14 Lesser General Public License for more details.
8db38e6c 15
3214b89b 16 You should have received a copy of the GNU Lesser General Public
ab84e3ff
PE
17 License along with the GNU C Library. If not, see
18 <http://www.gnu.org/licenses/>. */
8db38e6c 19
4f203842 20/* FIXME: Profiling of shared libraries is not implemented yet. */
0134d025
UD
21#ifndef dl_machine_h
22#define dl_machine_h
23
8db38e6c
RM
24#define ELF_MACHINE_NAME "MIPS"
25
bd4c4968
UD
26#include <entry.h>
27
28#ifndef ENTRY_POINT
29#error ENTRY_POINT needs to be defined for MIPS.
30#endif
31
b8ddf7a1 32#include <sgidefs.h>
0d5b7257 33#include <sys/asm.h>
305fae3b 34#include <dl-tls.h>
0d5b7257 35
4f203842
AJ
36/* The offset of gp from GOT might be system-dependent. It's set by
37 ld. The same value is also */
38#define OFFSET_GP_GOT 0x7ff0
39
bd4c4968 40#ifndef _RTLD_PROLOGUE
921bb2c3
AJ
41# define _RTLD_PROLOGUE(entry) \
42 ".globl\t" __STRING(entry) "\n\t" \
43 ".ent\t" __STRING(entry) "\n\t" \
44 ".type\t" __STRING(entry) ", @function\n" \
45 __STRING(entry) ":\n\t"
bd4c4968
UD
46#endif
47
48#ifndef _RTLD_EPILOGUE
921bb2c3
AJ
49# define _RTLD_EPILOGUE(entry) \
50 ".end\t" __STRING(entry) "\n\t" \
51 ".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
bd4c4968
UD
52#endif
53
58f68573 54/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.
63fb881a
DJ
55 This only makes sense on MIPS when using PLTs, so choose the
56 PLT relocation (not encountered when not using PLTs). */
57#define ELF_MACHINE_JMP_SLOT R_MIPS_JUMP_SLOT
58#define elf_machine_type_class(type) \
59 ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
60 | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
61
62#define ELF_MACHINE_PLT_REL 1
4cf5b6d0
SP
63#define ELF_MACHINE_NO_REL 0
64#define ELF_MACHINE_NO_RELA 0
8db38e6c 65
910e2e14 66/* Translate a processor specific dynamic tag to the index
8db38e6c
RM
67 in l_info array. */
68#define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
69
8db38e6c
RM
70/* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
71 with the run-time address of the r_debug structure */
0134d025 72#define ELF_MACHINE_DEBUG_SETUP(l,r) \
8db38e6c
RM
73do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
74 *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
75 (ElfW(Addr)) (r); \
76 } while (0)
77
9c21573c
MR
78#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \
79 || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008))
80# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?"
81#endif
82#ifdef __mips_nan2008
83# define ELF_MACHINE_NAN2008 EF_MIPS_NAN2008
84#else
85# define ELF_MACHINE_NAN2008 0
86#endif
87
f1dba308 88/* Return nonzero iff ELF header is compatible with the running host. */
4bf39226 89static inline int __attribute_used__
f1dba308 90elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
8db38e6c 91{
b8ddf7a1 92#if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
0d5b7257 93 /* Don't link o32 and n32 together. */
b8ddf7a1 94 if (((ehdr->e_flags & EF_MIPS_ABI2) != 0) != (_MIPS_SIM == _ABIN32))
0d5b7257
AO
95 return 0;
96#endif
97
9c21573c
MR
98 /* Don't link 2008-NaN and legacy-NaN objects together. */
99 if ((ehdr->e_flags & EF_MIPS_NAN2008) != ELF_MACHINE_NAN2008)
100 return 0;
101
f1dba308 102 switch (ehdr->e_machine)
8db38e6c
RM
103 {
104 case EM_MIPS:
be57c15a 105 case EM_MIPS_RS3_LE:
8db38e6c
RM
106 return 1;
107 default:
108 return 0;
109 }
110}
111
112static inline ElfW(Addr) *
113elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
114{
115 /* FIXME: the offset of gp from GOT may be system-dependent. */
4f203842 116 return (ElfW(Addr) *) (gpreg - OFFSET_GP_GOT);
8db38e6c 117}
0134d025 118
58f68573
AJ
119/* Return the link-time address of _DYNAMIC. Conveniently, this is the
120 first element of the GOT. This must be inlined in a function which
0d5b7257 121 uses global data. We assume its $gp points to the primary GOT. */
58f68573
AJ
122static inline ElfW(Addr)
123elf_machine_dynamic (void)
8db38e6c 124{
58f68573 125 register ElfW(Addr) gp __asm__ ("$28");
119fab98 126 return *elf_mips_got_from_gpreg (gp);
8db38e6c
RM
127}
128
0d5b7257
AO
129#define STRINGXP(X) __STRING(X)
130#define STRINGXV(X) STRINGV_(X)
131#define STRINGV_(...) # __VA_ARGS__
8db38e6c
RM
132
133/* Return the run-time load address of the shared object. */
134static inline ElfW(Addr)
135elf_machine_load_address (void)
136{
137 ElfW(Addr) addr;
43301bd3 138#ifndef __mips16
8db38e6c 139 asm (" .set noreorder\n"
0d5b7257
AO
140 " " STRINGXP (PTR_LA) " %0, 0f\n"
141 " bltzal $0, 0f\n"
8db38e6c 142 " nop\n"
0d5b7257 143 "0: " STRINGXP (PTR_SUBU) " %0, $31, %0\n"
8db38e6c 144 " .set reorder\n"
bd4c4968
UD
145 : "=r" (addr)
146 : /* No inputs */
147 : "$31");
43301bd3
MR
148#else
149 ElfW(Addr) tmp;
150 asm (" .set noreorder\n"
151 " move %1,$gp\n"
152 " lw %1,%%got(0f)(%1)\n"
153 "0: .fill 0\n" /* Clear the ISA bit on 0:. */
154 " la %0,0b\n"
155 " addiu %1,%%lo(0b)\n"
156 " subu %0,%1\n"
157 " .set reorder\n"
158 : "=d" (addr), "=d" (tmp)
159 : /* No inputs */);
160#endif
8db38e6c
RM
161 return addr;
162}
163
127035bb 164/* The MSB of got[1] of a gnu object is set to identify gnu objects. */
b8ddf7a1 165#if _MIPS_SIM == _ABI64
3d06657c
AO
166# define ELF_MIPS_GNU_GOT1_MASK 0x8000000000000000L
167#else
168# define ELF_MIPS_GNU_GOT1_MASK 0x80000000L
169#endif
d9c1416a 170
921bb2c3
AJ
171/* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
172 fiddles with global data. */
173#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) \
174do { \
175 struct link_map *map = &bootstrap_map; \
176 ElfW(Sym) *sym; \
177 ElfW(Addr) *got; \
178 int i, n; \
179 \
180 got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]); \
181 \
921bb2c3 182 if (__builtin_expect (map->l_addr == 0, 1)) \
872cf89f 183 break; \
921bb2c3
AJ
184 \
185 /* got[0] is reserved. got[1] is also reserved for the dynamic object \
186 generated by gnu ld. Skip these reserved entries from \
187 relocation. */ \
188 i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1; \
189 n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val; \
190 \
9285ecc8 191 /* Add the run-time displacement to all local got entries. */ \
921bb2c3
AJ
192 while (i < n) \
193 got[i++] += map->l_addr; \
194 \
195 /* Handle global got entries. */ \
196 got += n; \
197 sym = (ElfW(Sym) *) D_PTR(map, l_info[DT_SYMTAB]) \
198 + map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val; \
199 i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val \
200 - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val); \
201 \
202 while (i--) \
203 { \
204 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON) \
205 *got = map->l_addr + sym->st_value; \
206 else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC \
207 && *got != sym->st_value) \
208 *got += map->l_addr; \
209 else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION) \
210 { \
211 if (sym->st_other == 0) \
212 *got += map->l_addr; \
213 } \
214 else \
215 *got = map->l_addr + sym->st_value; \
216 \
217 got++; \
218 sym++; \
219 } \
921bb2c3
AJ
220} while(0)
221
222
8db38e6c
RM
223/* Mask identifying addresses reserved for the user program,
224 where the dynamic linker should not map anything. */
bd4c4968 225#define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
8db38e6c 226
0134d025 227
8db38e6c
RM
228/* Initial entry point code for the dynamic linker.
229 The C function `_dl_start' is the real entry point;
bd4c4968
UD
230 its return value is the user program's entry point.
231 Note how we have to be careful about two things:
232
233 1) That we allocate a minimal stack of 24 bytes for
234 every function call, the MIPS ABI states that even
235 if all arguments are passed in registers the procedure
236 called can use the 16 byte area pointed to by $sp
237 when it is called to store away the arguments passed
238 to it.
239
d05f2edb 240 2) That under Unix the entry is named __start
bd4c4968 241 and not just plain _start. */
8db38e6c 242
43301bd3
MR
243#ifndef __mips16
244# define RTLD_START asm (\
bd9fad09
AJ
245 ".text\n\
246 " _RTLD_PROLOGUE(ENTRY_POINT) "\
0d5b7257
AO
247 " STRINGXV(SETUP_GPX($25)) "\n\
248 " STRINGXV(SETUP_GPX64($18,$25)) "\n\
8db38e6c
RM
249 # i386 ABI book says that the first entry of GOT holds\n\
250 # the address of the dynamic structure. Though MIPS ABI\n\
251 # doesn't say nothing about this, I emulate this here.\n\
0d5b7257 252 " STRINGXP(PTR_LA) " $4, _DYNAMIC\n\
4f203842 253 # Subtract OFFSET_GP_GOT\n\
0d5b7257 254 " STRINGXP(PTR_S) " $4, -0x7ff0($28)\n\
8db38e6c 255 move $4, $29\n\
0d5b7257 256 " STRINGXP(PTR_SUBIU) " $29, 16\n\
921bb2c3 257 \n\
0d5b7257
AO
258 " STRINGXP(PTR_LA) " $8, .Lcoff\n\
259 bltzal $8, .Lcoff\n\
260.Lcoff: " STRINGXP(PTR_SUBU) " $8, $31, $8\n\
921bb2c3 261 \n\
0d5b7257
AO
262 " STRINGXP(PTR_LA) " $25, _dl_start\n\
263 " STRINGXP(PTR_ADDU) " $25, $8\n\
921bb2c3
AJ
264 jalr $25\n\
265 \n\
0d5b7257 266 " STRINGXP(PTR_ADDIU) " $29, 16\n\
8db38e6c 267 # Get the value of label '_dl_start_user' in t9 ($25).\n\
0d5b7257 268 " STRINGXP(PTR_LA) " $25, _dl_start_user\n\
bd9fad09
AJ
269 " _RTLD_EPILOGUE(ENTRY_POINT) "\
270 \n\
271 \n\
272 " _RTLD_PROLOGUE(_dl_start_user) "\
0d5b7257
AO
273 " STRINGXP(SETUP_GP) "\n\
274 " STRINGXV(SETUP_GP64($18,_dl_start_user)) "\n\
8db38e6c 275 move $16, $28\n\
3a344e73 276 # Save the user entry point address in a saved register.\n\
8db38e6c
RM
277 move $17, $2\n\
278 # See if we were run as a command with the executable file\n\
279 # name as an extra leading argument.\n\
280 lw $2, _dl_skip_args\n\
281 beq $2, $0, 1f\n\
282 # Load the original argument count.\n\
0d5b7257 283 " STRINGXP(PTR_L) " $4, 0($29)\n\
8db38e6c
RM
284 # Subtract _dl_skip_args from it.\n\
285 subu $4, $2\n\
286 # Adjust the stack pointer to skip _dl_skip_args words.\n\
0d5b7257
AO
287 sll $2, " STRINGXP (PTRLOG) "\n\
288 " STRINGXP(PTR_ADDU) " $29, $2\n\
8db38e6c 289 # Save back the modified argument count.\n\
0d5b7257 290 " STRINGXP(PTR_S) " $4, 0($29)\n\
3a344e73 2911: # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
0d5b7257
AO
292 " STRINGXP(PTR_L) " $4, _rtld_local\n\
293 " STRINGXP(PTR_L) /* or lw??? fixme */ " $5, 0($29)\n\
294 " STRINGXP(PTR_LA) " $6, " STRINGXP (PTRSIZE) "($29)\n\
295 sll $7, $5, " STRINGXP (PTRLOG) "\n\
296 " STRINGXP(PTR_ADDU) " $7, $7, $6\n\
297 " STRINGXP(PTR_ADDU) " $7, $7, " STRINGXP (PTRSIZE) " \n\
c5684fdb 298 # Make sure the stack pointer is aligned for _dl_init.\n\
bd9fad09 299 and $2, $29, -2 * " STRINGXP(SZREG) "\n\
76b1f93b 300 move $8, $29\n\
bd9fad09 301 " STRINGXP(PTR_SUBIU) " $29, $2, 32\n\
76b1f93b 302 " STRINGXP(PTR_S) " $8, (32 - " STRINGXP(SZREG) ")($29)\n\
0d5b7257 303 " STRINGXP(SAVE_GP(16)) "\n\
3a344e73 304 # Call the function to run the initializers.\n\
c5684fdb 305 jal _dl_init\n\
bd9fad09 306 # Restore the stack pointer for _start.\n\
76b1f93b 307 " STRINGXP(PTR_L) " $29, (32 - " STRINGXP(SZREG) ")($29)\n\
49e1806c 308 # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
0d5b7257 309 " STRINGXP(PTR_LA) " $2, _dl_fini\n\
8db38e6c 310 # Jump to the user entry point.\n\
feaff189 311 move $25, $17\n\
57f4291c 312 jr $25\n\t"\
bd9fad09 313 _RTLD_EPILOGUE(_dl_start_user)\
921bb2c3 314 ".previous"\
09d24ad4 315);
0134d025 316
43301bd3
MR
317#else /* __mips16 */
318/* MIPS16 version. We currently only support O32 under MIPS16; the proper
319 assembly preprocessor abstractions will need to be added if other ABIs
320 are to be supported. */
321
322# define RTLD_START asm (\
323 ".text\n\
324 .set mips16\n\
325 " _RTLD_PROLOGUE (ENTRY_POINT) "\
326 # Construct GP value in $3.\n\
327 li $3, %hi(_gp_disp)\n\
328 addiu $4, $pc, %lo(_gp_disp)\n\
329 sll $3, 16\n\
330 addu $3, $4\n\
331 move $28, $3\n\
332 lw $4, %got(_DYNAMIC)($3)\n\
333 sw $4, -0x7ff0($3)\n\
334 move $4, $sp\n\
335 addiu $sp, -16\n\
336 # _dl_start() is sufficiently near to use pc-relative\n\
337 # load address.\n\
338 la $3, _dl_start\n\
339 move $25, $3\n\
340 jalr $3\n\
341 addiu $sp, 16\n\
342 " _RTLD_EPILOGUE (ENTRY_POINT) "\
343 \n\
344 \n\
345 " _RTLD_PROLOGUE (_dl_start_user) "\
346 li $16, %hi(_gp_disp)\n\
347 addiu $4, $pc, %lo(_gp_disp)\n\
348 sll $16, 16\n\
349 addu $16, $4\n\
350 move $17, $2\n\
351 move $28, $16\n\
352 lw $4, %got(_dl_skip_args)($16)\n\
353 lw $4, 0($4)\n\
354 beqz $4, 1f\n\
355 # Load the original argument count.\n\
356 lw $5, 0($sp)\n\
357 # Subtract _dl_skip_args from it.\n\
358 subu $5, $4\n\
359 # Adjust the stack pointer to skip _dl_skip_args words.\n\
360 sll $4, " STRINGXP (PTRLOG) "\n\
361 move $6, $sp\n\
362 addu $6, $4\n\
363 move $sp, $6\n\
364 # Save back the modified argument count.\n\
365 sw $5, 0($sp)\n\
3661: # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
367 lw $4, %got(_rtld_local)($16)\n\
368 lw $4, 0($4)\n\
369 lw $5, 0($sp)\n\
370 addiu $6, $sp, " STRINGXP (PTRSIZE) "\n\
371 sll $7, $5, " STRINGXP (PTRLOG) "\n\
372 addu $7, $6\n\
373 addu $7, " STRINGXP (PTRSIZE) "\n\
c5684fdb 374 # Make sure the stack pointer is aligned for _dl_init.\n\
43301bd3
MR
375 li $2, 2 * " STRINGXP (SZREG) "\n\
376 neg $2, $2\n\
377 move $3, $sp\n\
378 and $2, $3\n\
379 sw $3, -" STRINGXP (SZREG) "($2)\n\
380 addiu $2, -32\n\
381 move $sp, $2\n\
382 sw $16, 16($sp)\n\
383 # Call the function to run the initializers.\n\
c5684fdb 384 lw $2, %call16(_dl_init)($16)\n\
43301bd3
MR
385 move $25, $2\n\
386 jalr $2\n\
387 # Restore the stack pointer for _start.\n\
388 lw $2, 32-" STRINGXP (SZREG) "($sp)\n\
389 move $sp, $2\n\
390 move $28, $16\n\
391 # Pass our finalizer function to the user in $2 as per ELF ABI.\n\
392 lw $2, %call16(_dl_fini)($16)\n\
393 # Jump to the user entry point.\n\
394 move $25, $17\n\
395 jr $17\n\t"\
396 _RTLD_EPILOGUE (_dl_start_user)\
397 ".previous"\
398);
399
400#endif /* __mips16 */
401
bd9fad09
AJ
402/* Names of the architecture-specific auditing callback functions. */
403# if _MIPS_SIM == _ABIO32
404# define ARCH_LA_PLTENTER mips_o32_gnu_pltenter
405# define ARCH_LA_PLTEXIT mips_o32_gnu_pltexit
406# elif _MIPS_SIM == _ABIN32
407# define ARCH_LA_PLTENTER mips_n32_gnu_pltenter
408# define ARCH_LA_PLTEXIT mips_n32_gnu_pltexit
409# else
410# define ARCH_LA_PLTENTER mips_n64_gnu_pltenter
411# define ARCH_LA_PLTEXIT mips_n64_gnu_pltexit
412# endif
413
87ae60cc
RM
414/* We define an initialization function. This is called very early in
415 _dl_sysdep_start. */
416#define DL_PLATFORM_INIT dl_platform_init ()
417
418static inline void __attribute__ ((unused))
419dl_platform_init (void)
420{
421 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
422 /* Avoid an empty string which would disturb us. */
423 GLRO(dl_platform) = NULL;
424}
425
63fb881a
DJ
426/* For a non-writable PLT, rewrite the .got.plt entry at RELOC_ADDR to
427 point at the symbol with address VALUE. For a writable PLT, rewrite
428 the corresponding PLT entry instead. */
429static inline ElfW(Addr)
430elf_machine_fixup_plt (struct link_map *map, lookup_t t,
431 const ElfW(Rel) *reloc,
432 ElfW(Addr) *reloc_addr, ElfW(Addr) value)
433{
434 return *reloc_addr = value;
435}
436
437static inline ElfW(Addr)
438elf_machine_plt_value (struct link_map *map, const ElfW(Rel) *reloc,
439 ElfW(Addr) value)
440{
441 return value;
442}
443
cb4a2928
JM
444/* The semantics of zero/non-zero values of undefined symbols differs
445 depending on whether the non-PIC ABI is in use. Under the non-PIC
446 ABI, a non-zero value indicates that there is an address reference
447 to the symbol and thus it must always be resolved (except when
448 resolving a jump slot relocation) to the PLT entry whose address is
449 provided as the symbol's value; a zero value indicates that this
450 canonical-address behaviour is not required. Yet under the classic
451 MIPS psABI, a zero value indicates that there is an address
452 reference to the function and the dynamic linker must resolve the
453 symbol immediately upon loading. To avoid conflict, symbols for
454 which the dynamic linker must assume the non-PIC ABI semantics are
455 marked with the STO_MIPS_PLT flag. */
456#define ELF_MACHINE_SYM_NO_MATCH(sym) \
457 ((sym)->st_shndx == SHN_UNDEF && !((sym)->st_other & STO_MIPS_PLT))
458
0134d025 459#endif /* !dl_machine_h */
8db38e6c 460
bd9fad09 461#ifdef RESOLVE_MAP
3887a8dc 462
cb5bcf74
DJ
463/* Perform a relocation described by R_INFO at the location pointed to
464 by RELOC_ADDR. SYM is the relocation symbol specified by R_INFO and
3887a8dc
RM
465 MAP is the object containing the reloc. */
466
bd9fad09
AJ
467auto inline void
468__attribute__ ((always_inline))
9077d4dc 469elf_machine_reloc (struct link_map *map, ElfW(Addr) r_info,
cb5bcf74
DJ
470 const ElfW(Sym) *sym, const struct r_found_version *version,
471 void *reloc_addr, ElfW(Addr) r_addend, int inplace_p)
3887a8dc 472{
cb5bcf74
DJ
473 const unsigned long int r_type = ELFW(R_TYPE) (r_info);
474 ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
85bdccdb 475
f71d7f57 476#if !defined RTLD_BOOTSTRAP && !defined SHARED
5166e402
AJ
477 /* This is defined in rtld.c, but nowhere in the static libc.a;
478 make the reference weak so static programs can still link. This
479 declaration cannot be done when compiling rtld.c (i.e. #ifdef
480 RTLD_BOOTSTRAP) because rtld.c contains the common defn for
481 _dl_rtld_map, which is incompatible with a weak decl in the same
482 file. */
f71d7f57 483 weak_extern (GL(dl_rtld_map));
5166e402 484#endif
3887a8dc 485
85bdccdb 486 switch (r_type)
3887a8dc 487 {
b8ead09a 488#if !defined (RTLD_BOOTSTRAP)
305fae3b
AJ
489# if _MIPS_SIM == _ABI64
490 case R_MIPS_TLS_DTPMOD64:
491 case R_MIPS_TLS_DTPREL64:
492 case R_MIPS_TLS_TPREL64:
493# else
494 case R_MIPS_TLS_DTPMOD32:
495 case R_MIPS_TLS_DTPREL32:
496 case R_MIPS_TLS_TPREL32:
497# endif
498 {
499 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
305fae3b
AJ
500
501 switch (r_type)
502 {
503 case R_MIPS_TLS_DTPMOD64:
504 case R_MIPS_TLS_DTPMOD32:
505 if (sym_map)
cb5bcf74 506 *addr_field = sym_map->l_tls_modid;
305fae3b
AJ
507 break;
508
509 case R_MIPS_TLS_DTPREL64:
510 case R_MIPS_TLS_DTPREL32:
cb5bcf74
DJ
511 if (sym)
512 {
513 if (inplace_p)
514 r_addend = *addr_field;
515 *addr_field = r_addend + TLS_DTPREL_VALUE (sym);
516 }
305fae3b
AJ
517 break;
518
519 case R_MIPS_TLS_TPREL32:
520 case R_MIPS_TLS_TPREL64:
cb5bcf74
DJ
521 if (sym)
522 {
523 CHECK_STATIC_TLS (map, sym_map);
524 if (inplace_p)
525 r_addend = *addr_field;
526 *addr_field = r_addend + TLS_TPREL_VALUE (sym_map, sym);
527 }
305fae3b
AJ
528 break;
529 }
530
531 break;
532 }
533#endif
534
b8ddf7a1 535#if _MIPS_SIM == _ABI64
0d5b7257
AO
536 case (R_MIPS_64 << 8) | R_MIPS_REL32:
537#else
3887a8dc 538 case R_MIPS_REL32:
0d5b7257 539#endif
9285ecc8 540 {
cb5bcf74 541 int symidx = ELFW(R_SYM) (r_info);
0d5b7257
AO
542 ElfW(Addr) reloc_value;
543
cb5bcf74
DJ
544 if (inplace_p)
545 /* Support relocations on mis-aligned offsets. */
546 __builtin_memcpy (&reloc_value, reloc_addr, sizeof (reloc_value));
547 else
548 reloc_value = r_addend;
9285ecc8
AJ
549
550 if (symidx)
551 {
552 const ElfW(Word) gotsym
553 = (const ElfW(Word)) map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
554
3d06657c 555 if ((ElfW(Word))symidx < gotsym)
9285ecc8 556 {
0d5b7257
AO
557 /* This wouldn't work for a symbol imported from other
558 libraries for which there's no GOT entry, but MIPS
559 requires every symbol referenced in a dynamic
560 relocation to have a GOT entry in the primary GOT,
561 so we only get here for locally-defined symbols.
562 For section symbols, we should *NOT* be adding
563 sym->st_value (per the definition of the meaning of
564 S in reloc expressions in the ELF64 MIPS ABI),
565 since it should have already been added to
566 reloc_value by the linker, but older versions of
567 GNU ld didn't add it, and newer versions don't emit
568 useless relocations to section symbols any more, so
569 it is safe to keep on adding sym->st_value, even
570 though it's not ABI compliant. Some day we should
571 bite the bullet and stop doing this. */
9285ecc8 572#ifndef RTLD_BOOTSTRAP
f71d7f57 573 if (map != &GL(dl_rtld_map))
9285ecc8 574#endif
0d5b7257 575 reloc_value += sym->st_value + map->l_addr;
9285ecc8
AJ
576 }
577 else
578 {
579#ifndef RTLD_BOOTSTRAP
580 const ElfW(Addr) *got
581 = (const ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
582 const ElfW(Word) local_gotno
583 = (const ElfW(Word))
584 map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
585
0d5b7257 586 reloc_value += got[symidx + local_gotno - gotsym];
9285ecc8
AJ
587#endif
588 }
589 }
590 else
3887a8dc 591#ifndef RTLD_BOOTSTRAP
f71d7f57 592 if (map != &GL(dl_rtld_map))
3887a8dc 593#endif
0d5b7257
AO
594 reloc_value += map->l_addr;
595
596 __builtin_memcpy (reloc_addr, &reloc_value, sizeof (reloc_value));
9285ecc8 597 }
3887a8dc 598 break;
cb5bcf74
DJ
599#ifndef RTLD_BOOTSTRAP
600#if _MIPS_SIM == _ABI64
601 case (R_MIPS_64 << 8) | R_MIPS_GLOB_DAT:
602#else
603 case R_MIPS_GLOB_DAT:
604#endif
605 {
606 int symidx = ELFW(R_SYM) (r_info);
607 const ElfW(Word) gotsym
608 = (const ElfW(Word)) map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
609
610 if (__builtin_expect ((ElfW(Word)) symidx >= gotsym, 1))
611 {
612 const ElfW(Addr) *got
613 = (const ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
614 const ElfW(Word) local_gotno
615 = ((const ElfW(Word))
616 map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val);
617
618 ElfW(Addr) reloc_value = got[symidx + local_gotno - gotsym];
619 __builtin_memcpy (reloc_addr, &reloc_value, sizeof (reloc_value));
620 }
621 }
622 break;
623#endif
3887a8dc
RM
624 case R_MIPS_NONE: /* Alright, Wilbur. */
625 break;
63fb881a
DJ
626
627 case R_MIPS_JUMP_SLOT:
628 {
629 struct link_map *sym_map;
630 ElfW(Addr) value;
631
632 /* The addend for a jump slot relocation must always be zero:
633 calls via the PLT always branch to the symbol's address and
634 not to the address plus a non-zero offset. */
635 if (r_addend != 0)
636 _dl_signal_error (0, map->l_name, NULL,
637 "found jump slot relocation with non-zero addend");
638
639 sym_map = RESOLVE_MAP (&sym, version, r_type);
640 value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
641 *addr_field = value;
642
643 break;
644 }
645
646 case R_MIPS_COPY:
647 {
648 const ElfW(Sym) *const refsym = sym;
649 struct link_map *sym_map;
650 ElfW(Addr) value;
651
652 /* Calculate the address of the symbol. */
653 sym_map = RESOLVE_MAP (&sym, version, r_type);
654 value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
655
656 if (__builtin_expect (sym == NULL, 0))
657 /* This can happen in trace mode if an object could not be
658 found. */
659 break;
660 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
661 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
662 && GLRO(dl_verbose)))
663 {
664 const char *strtab;
665
666 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
667 _dl_error_printf ("\
668 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
b9375348 669 RTLD_PROGNAME, strtab + refsym->st_name);
63fb881a
DJ
670 }
671 memcpy (reloc_addr, (void *) value,
9a7e1091 672 MIN (sym->st_size, refsym->st_size));
63fb881a
DJ
673 break;
674 }
675
b8ddf7a1 676#if _MIPS_SIM == _ABI64
0d5b7257
AO
677 case R_MIPS_64:
678 /* For full compliance with the ELF64 ABI, one must precede the
679 _REL32/_64 pair of relocations with a _64 relocation, such
680 that the in-place addend is read as a 64-bit value. IRIX
681 didn't pick up on this requirement, so we treat the
682 _REL32/_64 relocation as a 64-bit relocation even if it's by
683 itself. For ABI compliance, we ignore such _64 dummy
684 relocations. For RELA, this may be simply removed, since
685 it's totally unnecessary. */
cb5bcf74 686 if (ELFW(R_SYM) (r_info) == 0)
0d5b7257
AO
687 break;
688 /* Fall through. */
689#endif
3887a8dc 690 default:
85bdccdb 691 _dl_reloc_bad_type (map, r_type, 0);
3887a8dc
RM
692 break;
693 }
694}
695
cb5bcf74
DJ
696/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
697 MAP is the object containing the reloc. */
698
699auto inline void
700__attribute__ ((always_inline))
701elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
702 const ElfW(Sym) *sym, const struct r_found_version *version,
9a7e1091 703 void *const reloc_addr, int skip_ifunc)
cb5bcf74
DJ
704{
705 elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr, 0, 1);
706}
707
bd9fad09
AJ
708auto inline void
709__attribute__((always_inline))
335e9a00 710elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
5027ae10 711 void *const reloc_addr)
85bdccdb
UD
712{
713 /* XXX Nothing to do. There is no relative relocation, right? */
714}
715
bd9fad09
AJ
716auto inline void
717__attribute__((always_inline))
893f3d10 718elf_machine_lazy_rel (struct link_map *map,
9a7e1091
AS
719 ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
720 int skip_ifunc)
3887a8dc 721{
63fb881a
DJ
722 ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
723 const unsigned int r_type = ELFW(R_TYPE) (reloc->r_info);
724 /* Check for unexpected PLT reloc type. */
725 if (__builtin_expect (r_type == R_MIPS_JUMP_SLOT, 1))
726 {
727 if (__builtin_expect (map->l_mach.plt, 0) == 0)
728 {
729 /* Nothing is required here since we only support lazy
730 relocation in executables. */
731 }
732 else
733 *reloc_addr = map->l_mach.plt;
734 }
735 else
736 _dl_reloc_bad_type (map, r_type, 1);
3887a8dc
RM
737}
738
bd9fad09
AJ
739auto inline void
740__attribute__ ((always_inline))
741elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
742 const ElfW(Sym) *sym, const struct r_found_version *version,
9a7e1091 743 void *const reloc_addr, int skip_ifunc)
bd9fad09 744{
cb5bcf74
DJ
745 elf_machine_reloc (map, reloc->r_info, sym, version, reloc_addr,
746 reloc->r_addend, 0);
bd9fad09
AJ
747}
748
749auto inline void
750__attribute__((always_inline))
751elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
752 void *const reloc_addr)
753{
754}
755
760ab284 756#ifndef RTLD_BOOTSTRAP
bab23124 757/* Relocate GOT. */
bd9fad09
AJ
758auto inline void
759__attribute__((always_inline))
bab23124
AJ
760elf_machine_got_rel (struct link_map *map, int lazy)
761{
762 ElfW(Addr) *got;
763 ElfW(Sym) *sym;
760ab284 764 const ElfW(Half) *vernum;
12c4efc1 765 int i, n, symidx;
760ab284 766
63fb881a 767#define RESOLVE_GOTSYM(sym,vernum,sym_index,reloc) \
127035bb
AJ
768 ({ \
769 const ElfW(Sym) *ref = sym; \
c9c253d3 770 const struct r_found_version *version __attribute__ ((unused)) \
9a7e1091 771 = vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL; \
bd9fad09 772 struct link_map *sym_map; \
63fb881a 773 sym_map = RESOLVE_MAP (&ref, version, reloc); \
bd9fad09 774 ref ? sym_map->l_addr + ref->st_value : 0; \
bab23124 775 })
760ab284
UD
776
777 if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
778 vernum = (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
779 else
780 vernum = NULL;
bab23124 781
f5a37cdb 782 got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
bab23124 783
bab23124 784 n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
d9c1416a 785 /* The dynamic linker's local got entries have already been relocated. */
f71d7f57 786 if (map != &GL(dl_rtld_map))
043351e0 787 {
d9c1416a
AJ
788 /* got[0] is reserved. got[1] is also reserved for the dynamic object
789 generated by gnu ld. Skip these reserved entries from relocation. */
790 i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
791
9285ecc8 792 /* Add the run-time displacement to all local got entries if
9a7e1091 793 needed. */
d9c1416a
AJ
794 if (__builtin_expect (map->l_addr != 0, 0))
795 {
796 while (i < n)
797 got[i++] += map->l_addr;
798 }
043351e0 799 }
4f203842 800
bab23124
AJ
801 /* Handle global got entries. */
802 got += n;
127035bb
AJ
803 /* Keep track of the symbol index. */
804 symidx = map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
245bff94 805 sym = (ElfW(Sym) *) D_PTR (map, l_info[DT_SYMTAB]) + symidx;
bab23124
AJ
806 i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
807 - map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
4f203842
AJ
808
809 /* This loop doesn't handle Quickstart. */
bab23124
AJ
810 while (i--)
811 {
812 if (sym->st_shndx == SHN_UNDEF)
813 {
63fb881a
DJ
814 if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_value
815 && !(sym->st_other & STO_MIPS_PLT))
816 {
817 if (lazy)
818 *got = sym->st_value + map->l_addr;
819 else
820 /* This is a lazy-binding stub, so we don't need the
821 canonical address. */
822 *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_JUMP_SLOT);
823 }
4f203842 824 else
63fb881a 825 *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
bab23124
AJ
826 }
827 else if (sym->st_shndx == SHN_COMMON)
63fb881a 828 *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
bab23124 829 else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
63fb881a
DJ
830 && *got != sym->st_value)
831 {
832 if (lazy)
833 *got += map->l_addr;
834 else
835 /* This is a lazy-binding stub, so we don't need the
836 canonical address. */
837 *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_JUMP_SLOT);
838 }
bab23124
AJ
839 else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
840 {
841 if (sym->st_other == 0)
842 *got += map->l_addr;
843 }
844 else
63fb881a 845 *got = RESOLVE_GOTSYM (sym, vernum, symidx, R_MIPS_32);
bab23124 846
12c4efc1
AJ
847 ++got;
848 ++sym;
849 ++symidx;
bab23124
AJ
850 }
851
852#undef RESOLVE_GOTSYM
bab23124 853}
760ab284 854#endif
bab23124
AJ
855
856/* Set up the loaded object described by L so its stub function
5719e666 857 will jump to the on-demand fixup code __dl_runtime_resolve. */
bab23124 858
bd9fad09
AJ
859auto inline int
860__attribute__((always_inline))
bab23124
AJ
861elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
862{
863# ifndef RTLD_BOOTSTRAP
864 ElfW(Addr) *got;
865 extern void _dl_runtime_resolve (ElfW(Word));
63fb881a 866 extern void _dl_runtime_pltresolve (void);
bab23124
AJ
867 extern int _dl_mips_gnu_objects;
868
869 if (lazy)
870 {
871 /* The GOT entries for functions have not yet been filled in.
872 Their initial contents will arrange when called to put an
873 offset into the .dynsym section in t8, the return address
874 in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */
f5a37cdb 875 got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
bab23124
AJ
876
877 /* This function will get called to fix up the GOT entry indicated by
878 the register t8, and then jump to the resolved address. */
879 got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
880
881 /* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
882 of got[1] of a gnu object is set to identify gnu objects.
883 Where we can store l for non gnu objects? XXX */
884 if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
3d06657c 885 got[1] = ((ElfW(Addr)) l | ELF_MIPS_GNU_GOT1_MASK);
bab23124
AJ
886 else
887 _dl_mips_gnu_objects = 0;
888 }
889
890 /* Relocate global offset table. */
891 elf_machine_got_rel (l, lazy);
892
63fb881a
DJ
893 /* If using PLTs, fill in the first two entries of .got.plt. */
894 if (l->l_info[DT_JMPREL] && lazy)
895 {
896 ElfW(Addr) *gotplt;
897 gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_MIPS (PLTGOT)]);
898 /* If a library is prelinked but we have to relocate anyway,
899 we have to be able to undo the prelinking of .got.plt.
900 The prelinker saved the address of .plt for us here. */
901 if (gotplt[1])
902 l->l_mach.plt = gotplt[1] + l->l_addr;
903 gotplt[0] = (ElfW(Addr)) &_dl_runtime_pltresolve;
904 gotplt[1] = (ElfW(Addr)) l;
905 }
906
bab23124
AJ
907# endif
908 return lazy;
909}
910
bd9fad09 911#endif /* RESOLVE_MAP */