Regenerated
[kopensolaris-gnu/glibc.git] / elf / dl-runtime.c
1 /* On-demand PLT fixup for shared objects.
2    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
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.
9
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.
14
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.  */
19
20 #include <unistd.h>
21 #include <elf/ldsodefs.h>
22
23
24 /* The global scope we will use for symbol lookups.
25    This will be modified by _dl_open if RTLD_GLOBAL is used.  */
26 struct link_map **_dl_global_scope = _dl_default_scope;
27 struct link_map **_dl_global_scope_end = &_dl_default_scope[3];
28
29
30 /* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
31    _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
32    references made in the object L's relocations.  */
33 inline struct link_map **
34 internal_function
35 _dl_object_relocation_scope (struct link_map *l)
36 {
37   if (l->l_info[DT_SYMBOLIC])
38     {
39       /* This object's global references are to be resolved first
40          in the object itself, and only secondarily in more global
41          scopes.  */
42
43       if (! l->l_searchlist)
44         /* We must construct the searchlist for this object.  */
45         _dl_map_object_deps (l, NULL, 0, 0);
46
47       /* The primary scope is this object itself and its
48          dependencies.  */
49       _dl_global_scope[0] = l;
50
51       /* Secondary is the dependency tree that reached L; the object
52          requested directly by the user is at the root of that tree.  */
53       while (l->l_loader)
54         l = l->l_loader;
55       _dl_global_scope[1] = l;
56
57       /* Finally, the global scope follows.  */
58
59       return _dl_global_scope;
60     }
61   else
62     {
63       /* Use first the global scope, and then the scope of the root of the
64          dependency tree that first caused this object to be loaded.  */
65       while (l->l_loader)
66         l = l->l_loader;
67       *_dl_global_scope_end = l;
68       return &_dl_global_scope[2];
69     }
70 }
71 \f
72 #include "dynamic-link.h"
73
74 #if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
75 # define PLTREL  ElfW(Rela)
76 #else
77 # define PLTREL  ElfW(Rel)
78 #endif
79
80 #ifndef VERSYMIDX
81 # define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym))
82 #endif
83
84
85 /* This function is called through a special trampoline from the PLT the
86    first time each PLT entry is called.  We must perform the relocation
87    specified in the PLT of the given shared object, and return the resolved
88    function address to the trampoline, which will restart the original call
89    to that address.  Future calls will bounce directly from the PLT to the
90    function.  */
91
92 static ElfW(Addr) __attribute__ ((unused))
93 fixup (
94 #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
95        ELF_MACHINE_RUNTIME_FIXUP_ARGS,
96 #endif
97        struct link_map *l, ElfW(Word) reloc_offset)
98 {
99   const ElfW(Sym) *const symtab
100     = (const ElfW(Sym) *) (l->l_addr + l->l_info[DT_SYMTAB]->d_un.d_ptr);
101   const char *strtab =
102     (const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
103
104   const PLTREL *const reloc
105     = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr +
106                       reloc_offset);
107   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
108   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
109   ElfW(Addr) value;
110
111   /* Set up the scope to find symbols referenced by this object.  */
112   struct link_map **scope = _dl_object_relocation_scope (l);
113
114   /* Sanity check that we're really looking at a PLT relocation.  */
115   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
116
117    /* Look up the target symbol.  */
118   switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
119     {
120     default:
121       {
122         const ElfW(Half) *vernum = (const ElfW(Half) *)
123           (l->l_addr + l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr);
124         ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
125         const struct r_found_version *version = &l->l_versions[ndx];
126
127         if (version->hash != 0)
128           {
129             value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
130                                                 &sym, scope, l->l_name,
131                                                 version, ELF_MACHINE_JMP_SLOT);
132             break;
133           }
134       }
135     case 0:
136       value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope,
137                                  l->l_name, ELF_MACHINE_JMP_SLOT);
138     }
139
140   /* Currently value contains the base load address of the object
141      that defines sym.  Now add in the symbol offset.  */
142   value = (sym ? value + sym->st_value : 0);
143
144   /* And now perhaps the relocation addend.  */
145   value = elf_machine_plt_value (l, reloc, value);
146
147   /* Finally, fix up the plt itself.  */
148   elf_machine_fixup_plt (l, reloc, rel_addr, value);
149
150   *_dl_global_scope_end = NULL;
151
152   return value;
153 }
154
155
156 #ifndef PROF
157
158 static ElfW(Addr) __attribute__ ((unused))
159 profile_fixup (
160 #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
161        ELF_MACHINE_RUNTIME_FIXUP_ARGS,
162 #endif
163        struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
164 {
165   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount;
166   ElfW(Addr) *resultp;
167   ElfW(Addr) value;
168
169   /* This is the address in the array where we store the result of previous
170      relocations.  */
171   resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
172
173   value = *resultp;
174   if (value == 0)
175     {
176       /* This is the first time we have to relocate this object.  */
177       const ElfW(Sym) *const symtab
178         = (const ElfW(Sym) *) (l->l_addr + l->l_info[DT_SYMTAB]->d_un.d_ptr);
179       const char *strtab =
180         (const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
181
182       const PLTREL *const reloc
183         = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr +
184                           reloc_offset);
185       const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
186
187       /* Set up the scope to find symbols referenced by this object.  */
188       struct link_map **scope = _dl_object_relocation_scope (l);
189
190       /* Sanity check that we're really looking at a PLT relocation.  */
191       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
192
193       /* Look up the target symbol.  */
194       switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
195         {
196         default:
197           {
198             const ElfW(Half) *vernum = (const ElfW(Half) *)
199               (l->l_addr + l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr);
200             ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
201             const struct r_found_version *version = &l->l_versions[ndx];
202
203             if (version->hash != 0)
204               {
205                 value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
206                                                     &sym, scope, l->l_name,
207                                                     version,
208                                                     ELF_MACHINE_JMP_SLOT);
209                 break;
210               }
211           }
212         case 0:
213           value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope,
214                                      l->l_name, ELF_MACHINE_JMP_SLOT);
215         }
216
217       /* Currently value contains the base load address of the object
218          that defines sym.  Now add in the symbol offset.  */
219       value = (sym ? value + sym->st_value : 0);
220
221       /* And now perhaps the relocation addend.  */
222       value = elf_machine_plt_value (l, reloc, value);
223
224       *_dl_global_scope_end = NULL;
225
226       /* Store the result for later runs.  */
227       *resultp = value;
228     }
229
230   (*mcount_fct) (retaddr, value);
231
232   return value;
233 }
234
235 #endif /* PROF */
236
237
238 /* This macro is defined in dl-machine.h to define the entry point called
239    by the PLT.  The `fixup' function above does the real work, but a little
240    more twiddling is needed to get the stack right and jump to the address
241    finally resolved.  */
242
243 ELF_MACHINE_RUNTIME_TRAMPOLINE