]>
Commit | Line | Data |
---|---|---|
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 | 43 | static ElfW(Addr) __attribute__ ((unused)) |
01f3e03b | 44 | fixup ( |
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 | 108 | static ElfW(Addr) __attribute__ ((unused)) |
3996f34b UD |
109 | profile_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 | 192 | ELF_MACHINE_RUNTIME_TRAMPOLINE |