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