Remove mips VERSYMIDX macro definition
[glibc.git] / ports / sysdeps / mips / dl-trampoline.c
blobe4886cc9bd87db0fb79ff6e59726142bac04826b
1 /* PLT trampoline. MIPS version.
2 Copyright (C) 1996-2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library. If not, see
19 <http://www.gnu.org/licenses/>. */
21 /* FIXME: Profiling of shared libraries is not implemented yet. */
23 #include <sysdep.h>
24 #include <link.h>
25 #include <elf.h>
26 #include <ldsodefs.h>
27 #include <dl-machine.h>
28 #include <sysdep-cancel.h>
30 /* Get link map for callers object containing STUB_PC. */
31 static inline struct link_map *
32 elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
34 extern int _dl_mips_gnu_objects;
36 /* got[1] is reserved to keep its link map address for the shared
37 object generated by the gnu linker. If all are such objects, we
38 can find the link map from current GPREG simply. If not so, get
39 the link map for caller's object containing STUB_PC. */
41 if (_dl_mips_gnu_objects)
43 ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
44 ElfW(Word) g1;
46 g1 = ((ElfW(Word) *) got)[1];
48 if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
50 struct link_map *l =
51 (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
52 ElfW(Addr) base, limit;
53 const ElfW(Phdr) *p = l->l_phdr;
54 ElfW(Half) this, nent = l->l_phnum;
56 /* For the common case of a stub being called from the containing
57 object, STUB_PC will point to somewhere within the object that
58 is described by the link map fetched via got[1]. Otherwise we
59 have to scan all maps. */
60 for (this = 0; this < nent; this++)
62 if (p[this].p_type == PT_LOAD)
64 base = p[this].p_vaddr + l->l_addr;
65 limit = base + p[this].p_memsz;
66 if (stub_pc >= base && stub_pc < limit)
67 return l;
73 struct link_map *l;
74 Lmid_t nsid;
76 for (nsid = 0; nsid < DL_NNS; ++nsid)
77 for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
79 ElfW(Addr) base, limit;
80 const ElfW(Phdr) *p = l->l_phdr;
81 ElfW(Half) this, nent = l->l_phnum;
83 for (this = 0; this < nent; ++this)
85 if (p[this].p_type == PT_LOAD)
87 base = p[this].p_vaddr + l->l_addr;
88 limit = base + p[this].p_memsz;
89 if (stub_pc >= base && stub_pc < limit)
90 return l;
95 _dl_signal_error (0, NULL, NULL, "cannot find runtime link map");
96 return NULL;
99 /* Define mips specific runtime resolver. The function __dl_runtime_resolve
100 is called from assembler function _dl_runtime_resolve which converts
101 special argument registers t7 ($15) and t8 ($24):
102 t7 address to return to the caller of the function
103 t8 index for this function symbol in .dynsym
104 to usual c arguments.
106 Other architectures call fixup from dl-runtime.c in
107 _dl_runtime_resolve. MIPS instead calls __dl_runtime_resolve. We
108 have to use our own version because of the way the got section is
109 treated on MIPS (we've also got ELF_MACHINE_PLT defined). */
111 /* The flag _dl_mips_gnu_objects is set if all dynamic objects are
112 generated by the gnu linker. */
113 int _dl_mips_gnu_objects = 1;
115 /* This is called from assembly stubs below which the compiler can't see. */
116 static ElfW(Addr)
117 __dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))
118 __attribute_used__;
120 static ElfW(Addr)
121 __dl_runtime_resolve (ElfW(Word) sym_index,
122 ElfW(Word) return_address,
123 ElfW(Addr) old_gpreg,
124 ElfW(Addr) stub_pc)
126 struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);
127 const ElfW(Sym) *const symtab
128 = (const ElfW(Sym) *) D_PTR (l, l_info[DT_SYMTAB]);
129 const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
130 ElfW(Addr) *got
131 = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
132 const ElfW(Word) local_gotno
133 = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
134 const ElfW(Word) gotsym
135 = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
136 const ElfW(Sym) *sym = &symtab[sym_index];
137 struct link_map *sym_map;
138 ElfW(Addr) value;
140 /* FIXME: The symbol versioning stuff is not tested yet. */
141 if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
143 switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
145 default:
147 const ElfW(Half) *vernum =
148 (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
149 ElfW(Half) ndx = vernum[sym_index] & 0x7fff;
150 const struct r_found_version *version = &l->l_versions[ndx];
152 if (version->hash != 0)
154 /* We need to keep the scope around so do some locking. This is
155 not necessary for objects which cannot be unloaded or when
156 we are not using any threads (yet). */
157 if (!RTLD_SINGLE_THREAD_P)
158 THREAD_GSCOPE_SET_FLAG ();
160 sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l,
161 &sym, l->l_scope, version,
162 ELF_RTYPE_CLASS_PLT, 0, 0);
164 /* We are done with the global scope. */
165 if (!RTLD_SINGLE_THREAD_P)
166 THREAD_GSCOPE_RESET_FLAG ();
168 break;
170 /* Fall through. */
172 case 0:
174 /* We need to keep the scope around so do some locking. This is
175 not necessary for objects which cannot be unloaded or when
176 we are not using any threads (yet). */
177 int flags = DL_LOOKUP_ADD_DEPENDENCY;
178 if (!RTLD_SINGLE_THREAD_P)
180 THREAD_GSCOPE_SET_FLAG ();
181 flags |= DL_LOOKUP_GSCOPE_LOCK;
184 sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
185 l->l_scope, 0, ELF_RTYPE_CLASS_PLT,
186 flags, 0);
188 /* We are done with the global scope. */
189 if (!RTLD_SINGLE_THREAD_P)
190 THREAD_GSCOPE_RESET_FLAG ();
194 /* Currently value contains the base load address of the object
195 that defines sym. Now add in the symbol offset. */
196 value = (sym ? sym_map->l_addr + sym->st_value : 0);
198 else
199 /* We already found the symbol. The module (and therefore its load
200 address) is also known. */
201 value = l->l_addr + sym->st_value;
203 /* Apply the relocation with that value. */
204 *(got + local_gotno + sym_index - gotsym) = value;
206 return value;
209 #if _MIPS_SIM == _ABIO32
210 #define ELF_DL_FRAME_SIZE 40
212 #define ELF_DL_SAVE_ARG_REGS "\
213 sw $15, 36($29)\n \
214 sw $4, 16($29)\n \
215 sw $5, 20($29)\n \
216 sw $6, 24($29)\n \
217 sw $7, 28($29)\n \
220 #define ELF_DL_RESTORE_ARG_REGS "\
221 lw $31, 36($29)\n \
222 lw $4, 16($29)\n \
223 lw $5, 20($29)\n \
224 lw $6, 24($29)\n \
225 lw $7, 28($29)\n \
228 /* The PLT resolver should also save and restore $2 and $3, which are used
229 as arguments to MIPS16 stub functions. */
230 #define ELF_DL_PLT_FRAME_SIZE 48
232 #define ELF_DL_PLT_SAVE_ARG_REGS \
233 ELF_DL_SAVE_ARG_REGS "\
234 sw $2, 40($29)\n \
235 sw $3, 44($29)\n \
238 #define ELF_DL_PLT_RESTORE_ARG_REGS \
239 ELF_DL_RESTORE_ARG_REGS "\
240 lw $2, 40($29)\n \
241 lw $3, 44($29)\n \
244 #define IFABIO32(X) X
245 #define IFNEWABI(X)
247 #else /* _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64 */
249 #define ELF_DL_FRAME_SIZE 80
251 #define ELF_DL_SAVE_ARG_REGS "\
252 sd $15, 72($29)\n \
253 sd $4, 8($29)\n \
254 sd $5, 16($29)\n \
255 sd $6, 24($29)\n \
256 sd $7, 32($29)\n \
257 sd $8, 40($29)\n \
258 sd $9, 48($29)\n \
259 sd $10, 56($29)\n \
260 sd $11, 64($29)\n \
263 #define ELF_DL_RESTORE_ARG_REGS "\
264 ld $31, 72($29)\n \
265 ld $4, 8($29)\n \
266 ld $5, 16($29)\n \
267 ld $6, 24($29)\n \
268 ld $7, 32($29)\n \
269 ld $8, 40($29)\n \
270 ld $9, 48($29)\n \
271 ld $10, 56($29)\n \
272 ld $11, 64($29)\n \
275 /* The PLT resolver should also save and restore $2 and $3, which are used
276 as arguments to MIPS16 stub functions. */
277 #define ELF_DL_PLT_FRAME_SIZE 96
279 #define ELF_DL_PLT_SAVE_ARG_REGS \
280 ELF_DL_SAVE_ARG_REGS "\
281 sd $2, 80($29)\n \
282 sd $3, 88($29)\n \
285 #define ELF_DL_PLT_RESTORE_ARG_REGS \
286 ELF_DL_RESTORE_ARG_REGS "\
287 ld $2, 80($29)\n \
288 ld $3, 88($29)\n \
291 #define IFABIO32(X)
292 #define IFNEWABI(X) X
294 #endif
296 asm ("\n\
297 .text\n\
298 .align 2\n\
299 .globl _dl_runtime_resolve\n\
300 .type _dl_runtime_resolve,@function\n\
301 .ent _dl_runtime_resolve\n\
302 _dl_runtime_resolve:\n\
303 .frame $29, " STRINGXP(ELF_DL_FRAME_SIZE) ", $31\n\
304 .set noreorder\n\
305 # Save GP.\n\
306 1: move $3, $28\n\
307 # Save arguments and sp value in stack.\n\
308 " STRINGXP(PTR_SUBIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
309 # Modify t9 ($25) so as to point .cpload instruction.\n\
310 " IFABIO32(STRINGXP(PTR_ADDIU) " $25, (2f-1b)\n") "\
311 # Compute GP.\n\
312 2: " STRINGXP(SETUP_GP) "\n\
313 " STRINGXV(SETUP_GP64 (0, _dl_runtime_resolve)) "\n\
314 .set reorder\n\
315 # Save slot call pc.\n\
316 move $2, $31\n\
317 " IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
318 " ELF_DL_SAVE_ARG_REGS "\
319 move $4, $24\n\
320 move $5, $15\n\
321 move $6, $3\n\
322 move $7, $2\n\
323 jal __dl_runtime_resolve\n\
324 " ELF_DL_RESTORE_ARG_REGS "\
325 " STRINGXP(RESTORE_GP64) "\n\
326 " STRINGXP(PTR_ADDIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
327 move $25, $2\n\
328 jr $25\n\
329 .end _dl_runtime_resolve\n\
330 .previous\n\
333 /* Assembler veneer called from the PLT header code when using PLTs.
335 Code in each PLT entry and the PLT header fills in the arguments to
336 this function:
338 - $15 (o32 t7, n32/n64 t3) - caller's return address
339 - $24 (t8) - PLT entry index
340 - $25 (t9) - address of _dl_runtime_pltresolve
341 - o32 $28 (gp), n32/n64 $14 (t2) - address of .got.plt
343 Different registers are used for .got.plt because the ABI was
344 originally designed for o32, where gp was available (call
345 clobbered). On n32/n64 gp is call saved.
347 _dl_fixup needs:
349 - $4 (a0) - link map address
350 - $5 (a1) - .rel.plt offset (== PLT entry index * 8) */
352 asm ("\n\
353 .text\n\
354 .align 2\n\
355 .globl _dl_runtime_pltresolve\n\
356 .type _dl_runtime_pltresolve,@function\n\
357 .ent _dl_runtime_pltresolve\n\
358 _dl_runtime_pltresolve:\n\
359 .frame $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $31\n\
360 .set noreorder\n\
361 # Save arguments and sp value in stack.\n\
362 1: " STRINGXP(PTR_SUBIU) " $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
363 " IFABIO32(STRINGXP(PTR_L) " $13, " STRINGXP(PTRSIZE) "($28)") "\n\
364 " IFNEWABI(STRINGXP(PTR_L) " $13, " STRINGXP(PTRSIZE) "($14)") "\n\
365 # Modify t9 ($25) so as to point .cpload instruction.\n\
366 " IFABIO32(STRINGXP(PTR_ADDIU) " $25, (2f-1b)\n") "\
367 # Compute GP.\n\
368 2: " STRINGXP(SETUP_GP) "\n\
369 " STRINGXV(SETUP_GP64 (0, _dl_runtime_pltresolve)) "\n\
370 .set reorder\n\
371 " IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
372 " ELF_DL_PLT_SAVE_ARG_REGS "\
373 move $4, $13\n\
374 sll $5, $24, " STRINGXP(PTRLOG) " + 1\n\
375 jal _dl_fixup\n\
376 move $25, $2\n\
377 " ELF_DL_PLT_RESTORE_ARG_REGS "\
378 " STRINGXP(RESTORE_GP64) "\n\
379 " STRINGXP(PTR_ADDIU) " $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
380 jr $25\n\
381 .end _dl_runtime_pltresolve\n\
382 .previous\n\