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