fgetws implementation.
[kopensolaris-gnu/glibc.git] / elf / dl-runtime.c
1 /* On-demand PLT fixup for shared objects.
2    Copyright (C) 1995, 1996, 1997, 1998, 1999 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 #include "dynamic-link.h"
23
24 #if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
25 # define PLTREL  ElfW(Rela)
26 #else
27 # define PLTREL  ElfW(Rel)
28 #endif
29
30 #ifndef VERSYMIDX
31 # define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym))
32 #endif
33
34
35 /* This function is called through a special trampoline from the PLT the
36    first time each PLT entry is called.  We must perform the relocation
37    specified in the PLT of the given shared object, and return the resolved
38    function address to the trampoline, which will restart the original call
39    to that address.  Future calls will bounce directly from the PLT to the
40    function.  */
41
42 #ifndef ELF_MACHINE_NO_PLT
43 static ElfW(Addr) __attribute__ ((unused))
44 fixup (
45 # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
46         ELF_MACHINE_RUNTIME_FIXUP_ARGS,
47 # endif
48        struct link_map *l, ElfW(Word) reloc_offset)
49 {
50   const ElfW(Sym) *const symtab
51     = (const void *) l->l_info[DT_SYMTAB]->d_un.d_ptr;
52   const char *strtab = (const void *) l->l_info[DT_STRTAB]->d_un.d_ptr;
53
54   const PLTREL *const reloc
55     = (const void *) (l->l_info[DT_JMPREL]->d_un.d_ptr + reloc_offset);
56   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
57   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
58   ElfW(Addr) value;
59
60   /* Sanity check that we're really looking at a PLT relocation.  */
61   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
62
63    /* Look up the target symbol.  */
64   switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
65     {
66     default:
67       {
68         const ElfW(Half) *vernum =
69           (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
70         ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
71         const struct r_found_version *version = &l->l_versions[ndx];
72
73         if (version->hash != 0)
74           {
75             value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
76                                                 &sym, l->l_scope, l->l_name,
77                                                 version, ELF_MACHINE_JMP_SLOT);
78             break;
79           }
80       }
81     case 0:
82       value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
83                                  l->l_name, ELF_MACHINE_JMP_SLOT);
84     }
85
86   /* Currently value contains the base load address of the object
87      that defines sym.  Now add in the symbol offset.  */
88   value = (sym ? value + sym->st_value : 0);
89
90   /* And now perhaps the relocation addend.  */
91   value = elf_machine_plt_value (l, reloc, value);
92
93   /* Finally, fix up the plt itself.  */
94   elf_machine_fixup_plt (l, reloc, rel_addr, value);
95
96   return value;
97 }
98 #endif
99
100 #if !defined PROF && !defined ELF_MACHINE_NO_PLT
101
102 static ElfW(Addr) __attribute__ ((unused))
103 profile_fixup (
104 #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
105        ELF_MACHINE_RUNTIME_FIXUP_ARGS,
106 #endif
107        struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
108 {
109   void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount;
110   ElfW(Addr) *resultp;
111   ElfW(Addr) value;
112
113   /* This is the address in the array where we store the result of previous
114      relocations.  */
115   resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
116
117   value = *resultp;
118   if (value == 0)
119     {
120       /* This is the first time we have to relocate this object.  */
121       const ElfW(Sym) *const symtab
122         = (const void *) l->l_info[DT_SYMTAB]->d_un.d_ptr;
123       const char *strtab = (const void *) l->l_info[DT_STRTAB]->d_un.d_ptr;
124
125       const PLTREL *const reloc
126         = (const void *) (l->l_info[DT_JMPREL]->d_un.d_ptr + reloc_offset);
127       const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
128
129       /* Sanity check that we're really looking at a PLT relocation.  */
130       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
131
132       /* Look up the target symbol.  */
133       switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
134         {
135         default:
136           {
137             const ElfW(Half) *vernum =
138               (const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
139             ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
140             const struct r_found_version *version = &l->l_versions[ndx];
141
142             if (version->hash != 0)
143               {
144                 value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
145                                                     &sym, l->l_scope,
146                                                     l->l_name, version,
147                                                     ELF_MACHINE_JMP_SLOT);
148                 break;
149               }
150           }
151         case 0:
152           value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
153                                      l->l_name, ELF_MACHINE_JMP_SLOT);
154         }
155
156       /* Currently value contains the base load address of the object
157          that defines sym.  Now add in the symbol offset.  */
158       value = (sym ? value + sym->st_value : 0);
159
160       /* And now perhaps the relocation addend.  */
161       value = elf_machine_plt_value (l, reloc, value);
162
163       /* Store the result for later runs.  */
164       *resultp = value;
165     }
166
167   (*mcount_fct) (retaddr, value);
168
169   return value;
170 }
171
172 #endif /* PROF && ELF_MACHINE_NO_PLT */
173
174
175 /* This macro is defined in dl-machine.h to define the entry point called
176    by the PLT.  The `fixup' function above does the real work, but a little
177    more twiddling is needed to get the stack right and jump to the address
178    finally resolved.  */
179
180 ELF_MACHINE_RUNTIME_TRAMPOLINE