[BZ #2510, BZ #2830, BZ #3137, BZ #3313, BZ #3426, BZ #3465, BZ #3480, BZ #3483,...
[platform/upstream/glibc.git] / elf / dl-runtime.c
1 /* On-demand PLT fixup for shared objects.
2    Copyright (C) 1995-2002,2003,2004,2005,2006 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 <sys/param.h>
26 #include <ldsodefs.h>
27 #include <sysdep-cancel.h>
28 #include "dynamic-link.h"
29
30 #if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
31     || ELF_MACHINE_NO_REL
32 # define PLTREL  ElfW(Rela)
33 #else
34 # define PLTREL  ElfW(Rel)
35 #endif
36
37 #ifndef VERSYMIDX
38 # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
39 #endif
40
41 /* The fixup functions might have need special attributes.  If none
42    are provided define the macro as empty.  */
43 #ifndef ARCH_FIXUP_ATTRIBUTE
44 # define ARCH_FIXUP_ATTRIBUTE
45 #endif
46
47
48 /* This function is called through a special trampoline from the PLT the
49    first time each PLT entry is called.  We must perform the relocation
50    specified in the PLT of the given shared object, and return the resolved
51    function address to the trampoline, which will restart the original call
52    to that address.  Future calls will bounce directly from the PLT to the
53    function.  */
54
55 #ifndef ELF_MACHINE_NO_PLT
56 DL_FIXUP_VALUE_TYPE
57 __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
58 _dl_fixup (
59 # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
60            ELF_MACHINE_RUNTIME_FIXUP_ARGS,
61 # endif
62            /* GKM FIXME: Fix trampoline to pass bounds so we can do
63               without the `__unbounded' qualifier.  */
64            struct link_map *__unbounded l, ElfW(Word) reloc_offset)
65 {
66   const ElfW(Sym) *const symtab
67     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
68   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
69
70   const PLTREL *const reloc
71     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
72   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
73   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
74   lookup_t result;
75   DL_FIXUP_VALUE_TYPE value;
76
77   /* Sanity check that we're really looking at a PLT relocation.  */
78   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
79
80    /* Look up the target symbol.  If the normal lookup rules are not
81       used don't look in the global scope.  */
82   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
83     {
84       const struct r_found_version *version = NULL;
85
86       if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
87         {
88           const ElfW(Half) *vernum =
89             (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
90           ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
91           version = &l->l_versions[ndx];
92           if (version->hash == 0)
93             version = NULL;
94         }
95
96       if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
97         __rtld_mrlock_lock (l->l_scope_lock);
98
99       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
100                                     l->l_scope, version, ELF_RTYPE_CLASS_PLT,
101                                     DL_LOOKUP_ADD_DEPENDENCY, NULL);
102
103       if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
104         __rtld_mrlock_unlock (l->l_scope_lock);
105
106       /* Currently result contains the base load address (or link map)
107          of the object that defines sym.  Now add in the symbol
108          offset.  */
109       value = DL_FIXUP_MAKE_VALUE (result,
110                                    sym ? (LOOKUP_VALUE_ADDRESS (result)
111                                           + sym->st_value) : 0);
112     }
113   else
114     {
115       /* We already found the symbol.  The module (and therefore its load
116          address) is also known.  */
117       value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value);
118       result = l;
119     }
120
121   /* And now perhaps the relocation addend.  */
122   value = elf_machine_plt_value (l, reloc, value);
123
124   /* Finally, fix up the plt itself.  */
125   if (__builtin_expect (GLRO(dl_bind_not), 0))
126     return value;
127
128   return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
129 }
130 #endif
131
132 #if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
133
134 DL_FIXUP_VALUE_TYPE
135 __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
136 _dl_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,
141                    ElfW(Addr) retaddr, void *regs, long int *framesizep)
142 {
143   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
144
145   /* This is the address in the array where we store the result of previous
146      relocations.  */
147   struct reloc_result *reloc_result
148     = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
149   DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
150
151   DL_FIXUP_VALUE_TYPE value = *resultp;
152   if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0)
153     {
154       /* This is the first time we have to relocate this object.  */
155       const ElfW(Sym) *const symtab
156         = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
157       const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
158
159       const PLTREL *const reloc
160         = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
161       const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
162       const ElfW(Sym) *defsym = refsym;
163       lookup_t result;
164
165       /* Sanity check that we're really looking at a PLT relocation.  */
166       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
167
168       /* Look up the target symbol.  If the symbol is marked STV_PROTECTED
169          don't look in the global scope.  */
170       if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
171         {
172           const struct r_found_version *version = NULL;
173
174           if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
175             {
176               const ElfW(Half) *vernum =
177                 (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
178               ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
179               version = &l->l_versions[ndx];
180               if (version->hash == 0)
181                 version = NULL;
182             }
183
184           if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
185             __rtld_mrlock_lock (l->l_scope_lock);
186
187           result = _dl_lookup_symbol_x (strtab + refsym->st_name, l, &defsym,
188                                         l->l_scope, version,
189                                         ELF_RTYPE_CLASS_PLT,
190                                         DL_LOOKUP_ADD_DEPENDENCY, NULL);
191
192           if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
193             __rtld_mrlock_unlock (l->l_scope_lock);
194
195           /* Currently result contains the base load address (or link map)
196              of the object that defines sym.  Now add in the symbol
197              offset.  */
198           value = DL_FIXUP_MAKE_VALUE (result,
199                                        defsym != NULL
200                                        ? LOOKUP_VALUE_ADDRESS (result)
201                                          + defsym->st_value : 0);
202         }
203       else
204         {
205           /* We already found the symbol.  The module (and therefore its load
206              address) is also known.  */
207           value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + refsym->st_value);
208           result = l;
209         }
210       /* And now perhaps the relocation addend.  */
211       value = elf_machine_plt_value (l, reloc, value);
212
213 #ifdef SHARED
214       /* Auditing checkpoint: we have a new binding.  Provide the
215          auditing libraries the possibility to change the value and
216          tell us whether further auditing is wanted.  */
217       if (defsym != NULL && GLRO(dl_naudit) > 0)
218         {
219           reloc_result->bound = result;
220           /* Compute index of the symbol entry in the symbol table of
221              the DSO with the definition.  */
222           reloc_result->boundndx = (defsym
223                                     - (ElfW(Sym) *) D_PTR (result,
224                                                            l_info[DT_SYMTAB]));
225
226           /* Determine whether any of the two participating DSOs is
227              interested in auditing.  */
228           if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
229             {
230               unsigned int altvalue = 0;
231               struct audit_ifaces *afct = GLRO(dl_audit);
232               /* Synthesize a symbol record where the st_value field is
233                  the result.  */
234               ElfW(Sym) sym = *defsym;
235               sym.st_value = DL_FIXUP_VALUE_ADDR (value);
236
237               /* Keep track whether there is any interest in tracing
238                  the call in the lower two bits.  */
239               assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
240               assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
241               reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
242
243               const char *strtab2 = (const void *) D_PTR (result,
244                                                           l_info[DT_STRTAB]);
245
246               for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
247                 {
248                   /* XXX Check whether both DSOs must request action or
249                      only one */
250                   if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
251                       && (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
252                     {
253                       unsigned int flags = altvalue;
254                       if (afct->symbind != NULL)
255                         {
256                           uintptr_t new_value
257                             = afct->symbind (&sym, reloc_result->boundndx,
258                                              &l->l_audit[cnt].cookie,
259                                              &result->l_audit[cnt].cookie,
260                                              &flags,
261                                              strtab2 + defsym->st_name);
262                           if (new_value != (uintptr_t) sym.st_value)
263                             {
264                               altvalue = LA_SYMB_ALTVALUE;
265                               sym.st_value = new_value;
266                             }
267                         }
268
269                       /* Remember the results for every audit library and
270                          store a summary in the first two bits.  */
271                       reloc_result->enterexit
272                         &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
273                       reloc_result->enterexit
274                         |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
275                             << ((cnt + 1) * 2));
276                     }
277                   else
278                     /* If the bind flags say this auditor is not interested,
279                        set the bits manually.  */
280                     reloc_result->enterexit
281                       |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
282                           << ((cnt + 1) * 2));
283
284                   afct = afct->next;
285                 }
286
287               reloc_result->flags = altvalue;
288               value = DL_FIXUP_ADDR_VALUE (sym.st_value);
289             }
290           else
291             /* Set all bits since this symbol binding is not interesting.  */
292             reloc_result->enterexit = (1u << DL_NNS) - 1;
293         }
294 #endif
295
296       /* Store the result for later runs.  */
297       if (__builtin_expect (! GLRO(dl_bind_not), 1))
298         *resultp = value;
299     }
300
301   /* By default we do not call the pltexit function.  */
302   long int framesize = -1;
303
304 #ifdef SHARED
305   /* Auditing checkpoint: report the PLT entering and allow the
306      auditors to change the value.  */
307   if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0
308       /* Don't do anything if no auditor wants to intercept this call.  */
309       && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
310     {
311       ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
312                                                 l_info[DT_SYMTAB])
313                            + reloc_result->boundndx);
314
315       /* Set up the sym parameter.  */
316       ElfW(Sym) sym = *defsym;
317       sym.st_value = DL_FIXUP_VALUE_ADDR (value);
318
319       /* Get the symbol name.  */
320       const char *strtab = (const void *) D_PTR (reloc_result->bound,
321                                                  l_info[DT_STRTAB]);
322       const char *symname = strtab + sym.st_name;
323
324       /* Keep track of overwritten addresses.  */
325       unsigned int altvalue = reloc_result->flags;
326
327       struct audit_ifaces *afct = GLRO(dl_audit);
328       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
329         {
330           if (afct->ARCH_LA_PLTENTER != NULL
331               && (reloc_result->enterexit
332                   & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
333             {
334               unsigned int flags = altvalue;
335               long int new_framesize = -1;
336               uintptr_t new_value
337                 = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
338                                           &l->l_audit[cnt].cookie,
339                                           &reloc_result->bound->l_audit[cnt].cookie,
340                                           regs, &flags, symname,
341                                           &new_framesize);
342               if (new_value != (uintptr_t) sym.st_value)
343                 {
344                   altvalue = LA_SYMB_ALTVALUE;
345                   sym.st_value = new_value;
346                 }
347
348               /* Remember the results for every audit library and
349                  store a summary in the first two bits.  */
350               reloc_result->enterexit
351                 |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
352                     << (2 * (cnt + 1)));
353
354               if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
355                                               << (2 * (cnt + 1))))
356                   == 0 && new_framesize != -1 && framesize != -2)
357                 {
358                   /* If this is the first call providing information,
359                      use it.  */
360                   if (framesize == -1)
361                     framesize = new_framesize;
362                   /* If two pltenter calls provide conflicting information,
363                      use the larger value.  */
364                   else if (new_framesize != framesize)
365                     framesize = MAX (new_framesize, framesize);
366                 }
367             }
368
369           afct = afct->next;
370         }
371
372       value = DL_FIXUP_ADDR_VALUE (sym.st_value);
373     }
374 #endif
375
376   /* Store the frame size information.  */
377   *framesizep = framesize;
378
379   (*mcount_fct) (retaddr, DL_FIXUP_VALUE_CODE_ADDR (value));
380
381   return value;
382 }
383
384 #endif /* PROF && ELF_MACHINE_NO_PLT */
385
386
387 #include <stdio.h>
388 void
389 ARCH_FIXUP_ATTRIBUTE
390 _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_offset,
391                   const void *inregs, void *outregs)
392 {
393 #ifdef SHARED
394   /* This is the address in the array where we store the result of previous
395      relocations.  */
396   // XXX Maybe the bound information must be stored on the stack since
397   // XXX with bind_not a new value could have been stored in the meantime.
398   struct reloc_result *reloc_result
399     = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
400   ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
401                                             l_info[DT_SYMTAB])
402                        + reloc_result->boundndx);
403
404   /* Set up the sym parameter.  */
405   ElfW(Sym) sym = *defsym;
406
407   /* Get the symbol name.  */
408   const char *strtab = (const void *) D_PTR (reloc_result->bound,
409                                              l_info[DT_STRTAB]);
410   const char *symname = strtab + sym.st_name;
411
412   struct audit_ifaces *afct = GLRO(dl_audit);
413   for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
414     {
415       if (afct->ARCH_LA_PLTEXIT != NULL
416           && (reloc_result->enterexit
417               & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
418         {
419           afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
420                                  &l->l_audit[cnt].cookie,
421                                  &reloc_result->bound->l_audit[cnt].cookie,
422                                  inregs, outregs, symname);
423         }
424
425       afct = afct->next;
426     }
427 #endif
428 }