* elf/dl-runtime.c (IN_DL_RUNTIME): Define this macro first thing.
[platform/upstream/glibc.git] / elf / dl-runtime.c
1 /* On-demand PLT fixup for shared objects.
2    Copyright (C) 1995-1999, 2000, 2001, 2002 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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #define IN_DL_RUNTIME 1         /* This can be tested in dl-machine.h.  */
21
22 #include <alloca.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <ldsodefs.h>
26 #include "dynamic-link.h"
27
28 #if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
29     || ELF_MACHINE_NO_REL
30 # define PLTREL  ElfW(Rela)
31 #else
32 # define PLTREL  ElfW(Rel)
33 #endif
34
35 #ifndef VERSYMIDX
36 # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
37 #endif
38
39
40 /* This function is called through a special trampoline from the PLT the
41    first time each PLT entry is called.  We must perform the relocation
42    specified in the PLT of the given shared object, and return the resolved
43    function address to the trampoline, which will restart the original call
44    to that address.  Future calls will bounce directly from the PLT to the
45    function.  */
46
47 #ifndef ELF_MACHINE_NO_PLT
48 static ElfW(Addr) __attribute_used__
49 fixup (
50 # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
51         ELF_MACHINE_RUNTIME_FIXUP_ARGS,
52 # endif
53         /* GKM FIXME: Fix trampoline to pass bounds so we can do
54            without the `__unbounded' qualifier.  */
55        struct link_map *__unbounded l, ElfW(Word) reloc_offset)
56 {
57   const ElfW(Sym) *const symtab
58     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
59   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
60
61   const PLTREL *const reloc
62     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
63   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
64   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
65   lookup_t result;
66   ElfW(Addr) value;
67
68   /* The use of `alloca' here looks ridiculous but it helps.  The goal is
69      to prevent the function from being inlined and thus optimized out.
70      There is no official way to do this so we use this trick.  gcc never
71      inlines functions which use `alloca'.  */
72   alloca (sizeof (int));
73
74   /* Sanity check that we're really looking at a PLT relocation.  */
75   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
76
77    /* Look up the target symbol.  If the normal lookup rules are not
78       used don't look in the global scope.  */
79   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
80     {
81       switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
82         {
83         default:
84           {
85             const ElfW(Half) *vernum =
86               (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
87             ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
88             const struct r_found_version *version = &l->l_versions[ndx];
89
90             if (version->hash != 0)
91               {
92                 result = INTUSE(_dl_lookup_versioned_symbol) (strtab
93                                                               + sym->st_name,
94                                                               l, &sym, l->l_scope,
95                                                               version,
96                                                               ELF_RTYPE_CLASS_PLT,
97                                                               0);
98                 break;
99               }
100           }
101         case 0:
102           result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym,
103                                               l->l_scope, ELF_RTYPE_CLASS_PLT,
104                                               DL_LOOKUP_ADD_DEPENDENCY);
105         }
106
107       /* Currently result contains the base load address (or link map)
108          of the object that defines sym.  Now add in the symbol
109          offset.  */
110       value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
111     }
112   else
113     {
114       /* We already found the symbol.  The module (and therefore its load
115          address) is also known.  */
116       value = l->l_addr + sym->st_value;
117 #ifdef DL_LOOKUP_RETURNS_MAP
118       result = l;
119 #endif
120     }
121
122   /* And now perhaps the relocation addend.  */
123   value = elf_machine_plt_value (l, reloc, value);
124
125   /* Finally, fix up the plt itself.  */
126   if (__builtin_expect (GL(dl_bind_not), 0))
127     return value;
128
129   return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
130 }
131 #endif
132
133 #if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
134
135 static ElfW(Addr) __attribute_used__
136 profile_fixup (
137 #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
138        ELF_MACHINE_RUNTIME_FIXUP_ARGS,
139 #endif
140        struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
141 {
142   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
143   ElfW(Addr) *resultp;
144   lookup_t result;
145   ElfW(Addr) value;
146
147   /* The use of `alloca' here looks ridiculous but it helps.  The goal is
148      to prevent the function from being inlined, and thus optimized out.
149      There is no official way to do this so we use this trick.  gcc never
150      inlines functions which use `alloca'.  */
151   alloca (sizeof (int));
152
153   /* This is the address in the array where we store the result of previous
154      relocations.  */
155   resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
156
157   value = *resultp;
158   if (value == 0)
159     {
160       /* This is the first time we have to relocate this object.  */
161       const ElfW(Sym) *const symtab
162         = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
163       const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
164
165       const PLTREL *const reloc
166         = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
167       const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
168
169       /* Sanity check that we're really looking at a PLT relocation.  */
170       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
171
172       /* Look up the target symbol.  If the symbol is marked STV_PROTECTED
173          don't look in the global scope.  */
174       if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
175         {
176           switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
177             {
178             default:
179               {
180                 const ElfW(Half) *vernum =
181                   (const void *) D_PTR (l,l_info[VERSYMIDX (DT_VERSYM)]);
182                 ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
183                 const struct r_found_version *version = &l->l_versions[ndx];
184
185                 if (version->hash != 0)
186                   {
187                     result = INTUSE(_dl_lookup_versioned_symbol) (strtab
188                                                                   + sym->st_name,
189                                                                   l, &sym,
190                                                                   l->l_scope,
191                                                                   version,
192                                                                   ELF_RTYPE_CLASS_PLT,
193                                                                   0);
194                     break;
195                   }
196               }
197             case 0:
198               result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l,
199                                                   &sym, l->l_scope,
200                                                   ELF_RTYPE_CLASS_PLT,
201                                                   DL_LOOKUP_ADD_DEPENDENCY);
202             }
203
204           /* Currently result contains the base load address (or link map)
205              of the object that defines sym.  Now add in the symbol
206              offset.  */
207           value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
208         }
209       else
210         {
211           /* We already found the symbol.  The module (and therefore its load
212              address) is also known.  */
213           value = l->l_addr + sym->st_value;
214 #ifdef DL_LOOKUP_RETURNS_MAP
215           result = l;
216 #endif
217         }
218       /* And now perhaps the relocation addend.  */
219       value = elf_machine_plt_value (l, reloc, value);
220
221       /* Store the result for later runs.  */
222       if (__builtin_expect (! GL(dl_bind_not), 1))
223         *resultp = value;
224     }
225
226   (*mcount_fct) (retaddr, value);
227
228   return value;
229 }
230
231 #endif /* PROF && ELF_MACHINE_NO_PLT */
232
233
234 /* This macro is defined in dl-machine.h to define the entry point called
235    by the PLT.  The `fixup' function above does the real work, but a little
236    more twiddling is needed to get the stack right and jump to the address
237    finally resolved.  */
238
239 ELF_MACHINE_RUNTIME_TRAMPOLINE