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