]> sourceware.org Git - glibc.git/blame - elf/dl-runtime.c
Update.
[glibc.git] / elf / dl-runtime.c
CommitLineData
38334018 1/* On-demand PLT fixup for shared objects.
101edd3f 2 Copyright (C) 1995-1999, 2000 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
53308042 20#include <alloca.h>
101edd3f 21#include <stdlib.h>
3db52d94 22#include <unistd.h>
a42195db 23#include <ldsodefs.h>
f51d1dfd
RM
24#include "dynamic-link.h"
25
a2b08ee5
UD
26#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
27# define PLTREL ElfW(Rela)
38334018 28#else
a2b08ee5 29# define PLTREL ElfW(Rel)
38334018 30#endif
38334018 31
c84142e8
UD
32#ifndef VERSYMIDX
33# define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym))
34#endif
35
38334018
RM
36
37/* This function is called through a special trampoline from the PLT the
38 first time each PLT entry is called. We must perform the relocation
39 specified in the PLT of the given shared object, and return the resolved
40 function address to the trampoline, which will restart the original call
41 to that address. Future calls will bounce directly from the PLT to the
42 function. */
43
cb0509a8 44#ifndef ELF_MACHINE_NO_PLT
a2b08ee5 45static ElfW(Addr) __attribute__ ((unused))
01f3e03b 46fixup (
cb0509a8
UD
47# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
48 ELF_MACHINE_RUNTIME_FIXUP_ARGS,
49# endif
266180eb 50 struct link_map *l, ElfW(Word) reloc_offset)
d66e34cd 51{
266180eb 52 const ElfW(Sym) *const symtab
a42195db
UD
53 = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
54 const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
d66e34cd 55
38334018 56 const PLTREL *const reloc
a42195db 57 = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
a2b08ee5
UD
58 const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
59 void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
c0282c06 60 lookup_t result;
a2b08ee5 61 ElfW(Addr) value;
d66e34cd 62
c33bd012
UD
63 /* The use of `alloca' here looks ridiculous but it helps. The goal is
64 to prevent the function from being inlined and thus optimized out.
65 There is no official way to do this so we use this trick. gcc never
66 inlines functions which use `alloca'. */
67 alloca (sizeof (int));
68
a2b08ee5
UD
69 /* Sanity check that we're really looking at a PLT relocation. */
70 assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
f51d1dfd 71
736d0841
UD
72 /* Look up the target symbol. If the normal lookup rules are not
73 used don't look in the global scope. */
74 if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
a2b08ee5 75 {
06535ae9
UD
76 switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
77 {
78 default:
a2b08ee5 79 {
06535ae9 80 const ElfW(Half) *vernum =
a42195db 81 (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
06535ae9
UD
82 ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
83 const struct r_found_version *version = &l->l_versions[ndx];
84
85 if (version->hash != 0)
86 {
c0282c06
UD
87 result = _dl_lookup_versioned_symbol (strtab + sym->st_name,
88 l, &sym, l->l_scope,
89 version,
90 ELF_MACHINE_JMP_SLOT);
06535ae9
UD
91 break;
92 }
a2b08ee5 93 }
06535ae9 94 case 0:
c0282c06
UD
95 result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,
96 l->l_scope, ELF_MACHINE_JMP_SLOT);
06535ae9 97 }
a2b08ee5 98
c0282c06
UD
99 /* Currently result contains the base load address (or link map)
100 of the object that defines sym. Now add in the symbol
101 offset. */
102 value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
06535ae9
UD
103 }
104 else
c0282c06 105 {
06535ae9
UD
106 /* We already found the symbol. The module (and therefore its load
107 address) is also known. */
c0282c06
UD
108 value = l->l_addr + sym->st_value;
109#ifdef DL_LOOKUP_RETURNS_MAP
110 result = l;
111#endif
112 }
a2b08ee5 113
dfd2257a
UD
114 /* And now perhaps the relocation addend. */
115 value = elf_machine_plt_value (l, reloc, value);
650425ce 116
a2b08ee5 117 /* Finally, fix up the plt itself. */
c0282c06 118 return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
38334018 119}
cb0509a8 120#endif
d66e34cd 121
cb0509a8 122#if !defined PROF && !defined ELF_MACHINE_NO_PLT
8f2ece69 123
a2b08ee5 124static ElfW(Addr) __attribute__ ((unused))
3996f34b
UD
125profile_fixup (
126#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
127 ELF_MACHINE_RUNTIME_FIXUP_ARGS,
128#endif
129 struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
130{
131 void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount;
ea7eb7e3 132 ElfW(Addr) *resultp;
c0282c06 133 lookup_t result;
a2b08ee5 134 ElfW(Addr) value;
3996f34b 135
c33bd012
UD
136 /* The use of `alloca' here looks ridiculous but it helps. The goal is
137 to prevent the function from being inlined, and thus optimized out.
138 There is no official way to do this so we use this trick. gcc never
139 inlines functions which use `alloca'. */
140 alloca (sizeof (int));
141
ea7eb7e3
UD
142 /* This is the address in the array where we store the result of previous
143 relocations. */
144 resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
3996f34b 145
ea7eb7e3
UD
146 value = *resultp;
147 if (value == 0)
a2b08ee5 148 {
ea7eb7e3
UD
149 /* This is the first time we have to relocate this object. */
150 const ElfW(Sym) *const symtab
a42195db
UD
151 = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
152 const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
ea7eb7e3
UD
153
154 const PLTREL *const reloc
a42195db 155 = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
ea7eb7e3
UD
156 const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
157
ea7eb7e3
UD
158 /* Sanity check that we're really looking at a PLT relocation. */
159 assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
160
06535ae9
UD
161 /* Look up the target symbol. If the symbol is marked STV_PROTEXTED
162 don't look in the global scope. */
736d0841 163 if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
ea7eb7e3 164 {
06535ae9
UD
165 switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
166 {
167 default:
ea7eb7e3 168 {
06535ae9 169 const ElfW(Half) *vernum =
a42195db 170 (const void *) D_PTR (l,l_info[VERSYMIDX (DT_VERSYM)]);
06535ae9
UD
171 ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
172 const struct r_found_version *version = &l->l_versions[ndx];
173
174 if (version->hash != 0)
175 {
c0282c06
UD
176 result = _dl_lookup_versioned_symbol(strtab + sym->st_name,
177 l, &sym, l->l_scope,
178 version,
179 ELF_MACHINE_JMP_SLOT);
06535ae9
UD
180 break;
181 }
ea7eb7e3 182 }
06535ae9 183 case 0:
c0282c06
UD
184 result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,
185 l->l_scope, ELF_MACHINE_JMP_SLOT);
06535ae9
UD
186 }
187
c0282c06
UD
188 /* Currently result contains the base load address (or link map)
189 of the object that defines sym. Now add in the symbol
190 offset. */
191 value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
ea7eb7e3 192 }
06535ae9 193 else
c0282c06 194 {
06535ae9
UD
195 /* We already found the symbol. The module (and therefore its load
196 address) is also known. */
197 value = l->l_addr + sym->st_value;
c0282c06
UD
198#ifdef DL_LOOKUP_RETURNS_MAP
199 result = l;
200#endif
201 }
ea7eb7e3
UD
202 /* And now perhaps the relocation addend. */
203 value = elf_machine_plt_value (l, reloc, value);
204
ea7eb7e3
UD
205 /* Store the result for later runs. */
206 *resultp = value;
207 }
3996f34b 208
a2b08ee5 209 (*mcount_fct) (retaddr, value);
3996f34b 210
a2b08ee5 211 return value;
3996f34b 212}
a2b08ee5 213
cb0509a8 214#endif /* PROF && ELF_MACHINE_NO_PLT */
3996f34b
UD
215
216
38334018
RM
217/* This macro is defined in dl-machine.h to define the entry point called
218 by the PLT. The `fixup' function above does the real work, but a little
219 more twiddling is needed to get the stack right and jump to the address
220 finally resolved. */
d66e34cd 221
38334018 222ELF_MACHINE_RUNTIME_TRAMPOLINE
This page took 0.124947 seconds and 5 git commands to generate.