fgetws implementation.
[kopensolaris-gnu/glibc.git] / elf / dynamic-link.h
1 /* Inline functions for dynamic linking.
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 <elf.h>
21 #include <dl-machine.h>
22 #include <assert.h>
23
24 #ifndef VERSYMIDX
25 # define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym))
26 #endif
27
28
29 /* Global read-only variable defined in rtld.c which is nonzero if we
30    shall give more warning messages.  */
31 extern int _dl_verbose __attribute__ ((unused));
32
33
34 /* Read the dynamic section at DYN and fill in INFO with indices DT_*.  */
35
36 static inline void __attribute__ ((unused))
37 elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
38                       ElfW(Dyn) *info[DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM
39                                      + DT_EXTRANUM])
40 {
41   if (! dyn)
42     return;
43
44   while (dyn->d_tag != DT_NULL)
45     {
46       if (dyn->d_tag < DT_NUM)
47         info[dyn->d_tag] = dyn;
48       else if (dyn->d_tag >= DT_LOPROC &&
49                dyn->d_tag < DT_LOPROC + DT_PROCNUM)
50         info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
51       else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
52         info[VERSYMIDX (dyn->d_tag)] = dyn;
53       else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
54         info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_PROCNUM
55              + DT_VERSIONTAGNUM] = dyn;
56       else
57         assert (! "bad dynamic tag");
58       ++dyn;
59     }
60
61   if (info[DT_PLTGOT] != NULL)
62     info[DT_PLTGOT]->d_un.d_ptr += l_addr;
63   if (info[DT_STRTAB] != NULL)
64     info[DT_STRTAB]->d_un.d_ptr += l_addr;
65   if (info[DT_SYMTAB] != NULL)
66     info[DT_SYMTAB]->d_un.d_ptr += l_addr;
67 #if ! ELF_MACHINE_NO_RELA
68   if (info[DT_RELA] != NULL)
69     {
70       assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
71       info[DT_RELA]->d_un.d_ptr += l_addr;
72     }
73 #endif
74 #if ! ELF_MACHINE_NO_REL
75   if (info[DT_REL] != NULL)
76     {
77       assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
78       info[DT_REL]->d_un.d_ptr += l_addr;
79     }
80 #endif
81   if (info[DT_PLTREL] != NULL)
82     {
83 #if ELF_MACHINE_NO_RELA
84       assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
85 #elif ELF_MACHINE_NO_REL
86       assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
87 #else
88       assert (info[DT_PLTREL]->d_un.d_val == DT_REL
89               || info[DT_PLTREL]->d_un.d_val == DT_RELA);
90 #endif
91     }
92   if (info[DT_JMPREL] != NULL)
93     info[DT_JMPREL]->d_un.d_ptr += l_addr;
94   if (info[VERSYMIDX (DT_VERSYM)] != NULL)
95     info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
96 }
97
98 #ifdef RESOLVE
99
100 /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
101    These functions are almost identical, so we use cpp magic to avoid
102    duplicating their code.  It cannot be done in a more general function
103    because we must be able to completely inline.  */
104
105 /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
106    range.  Note that according to the ELF spec, this is completely legal!
107    But conditionally define things so that on machines we know this will
108    not happen we do something more optimal.  */
109
110 # ifdef ELF_MACHINE_PLTREL_OVERLAP
111 #  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
112   do {                                                                        \
113     struct { ElfW(Addr) start, size; int lazy; } ranges[3];                   \
114     int ranges_index;                                                         \
115                                                                               \
116     ranges[0].lazy = ranges[2].lazy = 0;                                      \
117     ranges[1].lazy = 1;                                                       \
118     ranges[0].size = ranges[1].size = ranges[2].size = 0;                     \
119                                                                               \
120     if ((map)->l_info[DT_##RELOC])                                            \
121       {                                                                       \
122         ranges[0].start = (map)->l_info[DT_##RELOC]->d_un.d_ptr;              \
123         ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;           \
124       }                                                                       \
125                                                                               \
126      if ((do_lazy)                                                            \
127         && (map)->l_info[DT_PLTREL]                                           \
128         && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
129       {                                                                       \
130         ranges[1].start = (map)->l_info[DT_JMPREL]->d_un.d_ptr;               \
131         ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;              \
132         ranges[2].start = ranges[1].start + ranges[1].size;                   \
133         ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start;  \
134         ranges[0].size = ranges[1].start - ranges[0].start;                   \
135       }                                                                       \
136                                                                               \
137     for (ranges_index = 0; ranges_index < 3; ++ranges_index)                  \
138       elf_dynamic_do_##reloc ((map),                                          \
139                               ranges[ranges_index].start,                     \
140                               ranges[ranges_index].size,                      \
141                               ranges[ranges_index].lazy);                     \
142   } while (0)
143 # else
144 #  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
145   do {                                                                        \
146     struct { ElfW(Addr) start, size; int lazy; } ranges[2];                   \
147     int ranges_index;                                                         \
148     ranges[0].lazy = 0;                                                       \
149     ranges[0].size = ranges[1].size = 0;                                      \
150     ranges[0].start = 0;                                                      \
151                                                                               \
152     if ((map)->l_info[DT_##RELOC])                                            \
153       {                                                                       \
154         ranges[0].start = (map)->l_info[DT_##RELOC]->d_un.d_ptr;              \
155         ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;           \
156       }                                                                       \
157     if ((map)->l_info[DT_PLTREL]                                              \
158         && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
159       {                                                                       \
160         ElfW(Addr) start = (map)->l_info[DT_JMPREL]->d_un.d_ptr;              \
161                                                                               \
162         if ((do_lazy)                                                         \
163             /* This test does not only detect whether the relocation          \
164                sections are in the right order, it also checks whether        \
165                there is a DT_REL/DT_RELA section.  */                         \
166             || ranges[0].start + ranges[0].size != start)                     \
167           {                                                                   \
168             ranges[1].start = start;                                          \
169             ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;          \
170             ranges[1].lazy = (do_lazy);                                       \
171           }                                                                   \
172         else                                                                  \
173           /* Combine processing the sections.  */                             \
174           ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val;           \
175       }                                                                       \
176                                                                               \
177     for (ranges_index = 0; ranges_index < 2; ++ranges_index)                  \
178       elf_dynamic_do_##reloc ((map),                                          \
179                               ranges[ranges_index].start,                     \
180                               ranges[ranges_index].size,                      \
181                               ranges[ranges_index].lazy);                     \
182   } while (0)
183 # endif
184
185 # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
186 #  define _ELF_CHECK_REL 0
187 # else
188 #  define _ELF_CHECK_REL 1
189 # endif
190
191 # if ! ELF_MACHINE_NO_REL
192 #  include "do-rel.h"
193 #  define ELF_DYNAMIC_DO_REL(map, lazy) \
194   _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
195 # else
196 #  define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do.  */
197 # endif
198
199 # if ! ELF_MACHINE_NO_RELA
200 #  define DO_RELA
201 #  include "do-rel.h"
202 #  define ELF_DYNAMIC_DO_RELA(map, lazy) \
203   _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
204 # else
205 #  define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do.  */
206 # endif
207
208 /* This can't just be an inline function because GCC is too dumb
209    to inline functions containing inlines themselves.  */
210 # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
211   do {                                                                        \
212     int edr_lazy = elf_machine_runtime_setup ((map), (lazy),                  \
213                                               (consider_profile));            \
214     ELF_DYNAMIC_DO_REL ((map), edr_lazy);                                     \
215     ELF_DYNAMIC_DO_RELA ((map), edr_lazy);                                    \
216   } while (0)
217
218 #endif