]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-runtime.c
Update.
[thirdparty/glibc.git] / elf / dl-runtime.c
CommitLineData
38334018 1/* On-demand PLT fixup for shared objects.
f420344c 2 Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
afd4eb37 3 This file is part of the GNU C Library.
d66e34cd 4
afd4eb37
UD
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
d66e34cd 9
afd4eb37
UD
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
d66e34cd 14
afd4eb37
UD
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
d66e34cd 19
3db52d94 20#include <unistd.h>
a853022c 21#include <elf/ldsodefs.h>
f51d1dfd
RM
22#include "dynamic-link.h"
23
a2b08ee5
UD
24#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
25# define PLTREL ElfW(Rela)
38334018 26#else
a2b08ee5 27# define PLTREL ElfW(Rel)
38334018 28#endif
38334018 29
c84142e8
UD
30#ifndef VERSYMIDX
31# define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym))
32#endif
33
38334018
RM
34
35/* This function is called through a special trampoline from the PLT the
36 first time each PLT entry is called. We must perform the relocation
37 specified in the PLT of the given shared object, and return the resolved
38 function address to the trampoline, which will restart the original call
39 to that address. Future calls will bounce directly from the PLT to the
40 function. */
41
cb0509a8 42#ifndef ELF_MACHINE_NO_PLT
a2b08ee5 43static ElfW(Addr) __attribute__ ((unused))
01f3e03b 44fixup (
cb0509a8
UD
45# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
46 ELF_MACHINE_RUNTIME_FIXUP_ARGS,
47# endif
266180eb 48 struct link_map *l, ElfW(Word) reloc_offset)
d66e34cd 49{
266180eb 50 const ElfW(Sym) *const symtab
f420344c
UD
51 = (const void *) l->l_info[DT_SYMTAB]->d_un.d_ptr;
52 const char *strtab = (const void *) l->l_info[DT_STRTAB]->d_un.d_ptr;
d66e34cd 53
38334018 54 const PLTREL *const reloc
f420344c 55 = (const void *) (l->l_info[DT_JMPREL]->d_un.d_ptr + reloc_offset);
a2b08ee5
UD
56 const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
57 void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
58 ElfW(Addr) value;
d66e34cd 59
c33bd012
UD
60 /* The use of `alloca' here looks ridiculous but it helps. The goal is
61 to prevent the function from being inlined and thus optimized out.
62 There is no official way to do this so we use this trick. gcc never
63 inlines functions which use `alloca'. */
64 alloca (sizeof (int));
65
a2b08ee5
UD
66 /* Sanity check that we're really looking at a PLT relocation. */
67 assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
f51d1dfd 68
a2b08ee5
UD
69 /* Look up the target symbol. */
70 switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
71 {
72 default:
c84142e8 73 {
f420344c
UD
74 const ElfW(Half) *vernum =
75 (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
a2b08ee5
UD
76 ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
77 const struct r_found_version *version = &l->l_versions[ndx];
78
79 if (version->hash != 0)
80 {
81 value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
be935610 82 &sym, l->l_scope, l->l_name,
27a5bb33 83 version, ELF_MACHINE_JMP_SLOT);
a2b08ee5
UD
84 break;
85 }
c84142e8 86 }
a2b08ee5 87 case 0:
be935610 88 value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
27a5bb33 89 l->l_name, ELF_MACHINE_JMP_SLOT);
a2b08ee5
UD
90 }
91
92 /* Currently value contains the base load address of the object
93 that defines sym. Now add in the symbol offset. */
94 value = (sym ? value + sym->st_value : 0);
95
dfd2257a
UD
96 /* And now perhaps the relocation addend. */
97 value = elf_machine_plt_value (l, reloc, value);
650425ce 98
a2b08ee5
UD
99 /* Finally, fix up the plt itself. */
100 elf_machine_fixup_plt (l, reloc, rel_addr, value);
d66e34cd 101
a2b08ee5 102 return value;
38334018 103}
cb0509a8 104#endif
d66e34cd 105
cb0509a8 106#if !defined PROF && !defined ELF_MACHINE_NO_PLT
8f2ece69 107
a2b08ee5 108static ElfW(Addr) __attribute__ ((unused))
3996f34b
UD
109profile_fixup (
110#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
111 ELF_MACHINE_RUNTIME_FIXUP_ARGS,
112#endif
113 struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
114{
115 void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount;
ea7eb7e3 116 ElfW(Addr) *resultp;
a2b08ee5 117 ElfW(Addr) value;
3996f34b 118
c33bd012
UD
119 /* The use of `alloca' here looks ridiculous but it helps. The goal is
120 to prevent the function from being inlined, and thus optimized out.
121 There is no official way to do this so we use this trick. gcc never
122 inlines functions which use `alloca'. */
123 alloca (sizeof (int));
124
ea7eb7e3
UD
125 /* This is the address in the array where we store the result of previous
126 relocations. */
127 resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
3996f34b 128
ea7eb7e3
UD
129 value = *resultp;
130 if (value == 0)
a2b08ee5 131 {
ea7eb7e3
UD
132 /* This is the first time we have to relocate this object. */
133 const ElfW(Sym) *const symtab
f420344c
UD
134 = (const void *) l->l_info[DT_SYMTAB]->d_un.d_ptr;
135 const char *strtab = (const void *) l->l_info[DT_STRTAB]->d_un.d_ptr;
ea7eb7e3
UD
136
137 const PLTREL *const reloc
f420344c 138 = (const void *) (l->l_info[DT_JMPREL]->d_un.d_ptr + reloc_offset);
ea7eb7e3
UD
139 const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
140
ea7eb7e3
UD
141 /* Sanity check that we're really looking at a PLT relocation. */
142 assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
143
144 /* Look up the target symbol. */
145 switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
146 {
147 default:
a2b08ee5 148 {
f420344c
UD
149 const ElfW(Half) *vernum =
150 (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
ea7eb7e3
UD
151 ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
152 const struct r_found_version *version = &l->l_versions[ndx];
153
154 if (version->hash != 0)
155 {
156 value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
be935610
UD
157 &sym, l->l_scope,
158 l->l_name, version,
27a5bb33 159 ELF_MACHINE_JMP_SLOT);
ea7eb7e3
UD
160 break;
161 }
a2b08ee5 162 }
ea7eb7e3 163 case 0:
be935610 164 value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
27a5bb33 165 l->l_name, ELF_MACHINE_JMP_SLOT);
ea7eb7e3 166 }
a2b08ee5 167
ea7eb7e3
UD
168 /* Currently value contains the base load address of the object
169 that defines sym. Now add in the symbol offset. */
170 value = (sym ? value + sym->st_value : 0);
650425ce 171
ea7eb7e3
UD
172 /* And now perhaps the relocation addend. */
173 value = elf_machine_plt_value (l, reloc, value);
174
ea7eb7e3
UD
175 /* Store the result for later runs. */
176 *resultp = value;
177 }
3996f34b 178
a2b08ee5 179 (*mcount_fct) (retaddr, value);
3996f34b 180
a2b08ee5 181 return value;
3996f34b 182}
a2b08ee5 183
cb0509a8 184#endif /* PROF && ELF_MACHINE_NO_PLT */
3996f34b
UD
185
186
38334018
RM
187/* This macro is defined in dl-machine.h to define the entry point called
188 by the PLT. The `fixup' function above does the real work, but a little
189 more twiddling is needed to get the stack right and jump to the address
190 finally resolved. */
d66e34cd 191
38334018 192ELF_MACHINE_RUNTIME_TRAMPOLINE