fgetws implementation.
[kopensolaris-gnu/glibc.git] / elf / do-lookup.h
1 /* Look up a symbol in the loaded 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 #if VERSIONED
21 # define FCT do_lookup_versioned
22 # define ARG const struct r_found_version *const version,
23 #else
24 # define FCT do_lookup
25 # define ARG
26 #endif
27
28 /* Inner part of the lookup functions.  We return a value > 0 if we
29    found the symbol, the value 0 if nothing is found and < 0 if
30    something bad happened.  */
31 static inline int
32 FCT (const char *undef_name, unsigned long int hash,
33      const ElfW(Sym) *ref, struct sym_val *result,
34      struct r_scope_elem *scope, size_t i, const char *reference_name,
35      ARG struct link_map *skip, int reloc_type)
36 {
37   struct link_map **list = scope->r_list;
38   size_t n = scope->r_nlist;
39   struct link_map *map;
40
41   do
42     {
43       const ElfW(Sym) *symtab;
44       const char *strtab;
45       const ElfW(Half) *verstab;
46       ElfW(Symndx) symidx;
47       const ElfW(Sym) *sym;
48 #if ! VERSIONED
49       int num_versions = 0;
50       const ElfW(Sym) *versioned_sym = NULL;
51 #endif
52
53       map = list[i];
54
55       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
56       if (skip != NULL && map == skip)
57         continue;
58
59       /* Don't search the executable when resolving a copy reloc.  */
60       if (elf_machine_lookup_noexec_p (reloc_type)
61           && map->l_type == lt_executable)
62         continue;
63
64       /* Print some debugging info if wanted.  */
65       if (_dl_debug_symbols)
66         _dl_debug_message (1, "symbol=", undef_name, ";  lookup in file=",
67                            map->l_name[0] ? map->l_name : _dl_argv[0],
68                            "\n", NULL);
69
70       symtab = (const void *) map->l_info[DT_SYMTAB]->d_un.d_ptr;
71       strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
72       verstab = map->l_versyms;
73
74       /* Search the appropriate hash bucket in this object's symbol table
75          for a definition for the same symbol name.  */
76       for (symidx = map->l_buckets[hash % map->l_nbuckets];
77            symidx != STN_UNDEF;
78            symidx = map->l_chain[symidx])
79         {
80           sym = &symtab[symidx];
81
82           if (sym->st_value == 0 || /* No value.  */
83               (elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry.  */
84                && sym->st_shndx == SHN_UNDEF))
85             continue;
86
87           if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC)
88             /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
89                since these are no code/data definitions.  */
90             continue;
91
92           if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
93             /* Not the symbol we are looking for.  */
94             continue;
95
96 #if VERSIONED
97           if (verstab == NULL)
98             {
99               /* We need a versioned symbol but haven't found any.  If
100                  this is the object which is referenced in the verneed
101                  entry it is a bug in the library since a symbol must
102                  not simply disappear.
103
104                  It would also be a bug in the object since it means that
105                  the list of required versions is incomplete and so the
106                  tests in dl-version.c haven't found a problem.*/
107               assert (version->filename == NULL
108                       || ! _dl_name_match_p (version->filename, map));
109
110               /* Otherwise we accept the symbol.  */
111             }
112           else
113             {
114               /* We can match the version information or use the
115                  default one if it is not hidden.  */
116               ElfW(Half) ndx = verstab[symidx] & 0x7fff;
117               if ((map->l_versions[ndx].hash != version->hash
118                    || strcmp (map->l_versions[ndx].name, version->name))
119                   && (version->hidden || map->l_versions[ndx].hash
120                       || (verstab[symidx] & 0x8000)))
121                 /* It's not the version we want.  */
122                 continue;
123             }
124 #else
125           /* No specific version is selected.  When the object file
126              also does not define a version we have a match.
127              Otherwise we accept the default version, or in case there
128              is only one version defined, this one version.  */
129           if (verstab != NULL)
130             {
131               ElfW(Half) ndx = verstab[symidx] & 0x7fff;
132               if (ndx > 2) /* map->l_versions[ndx].hash != 0) */
133                 {
134                   /* Don't accept hidden symbols.  */
135                   if ((verstab[symidx] & 0x8000) == 0 && num_versions++ == 0)
136                     /* No version so far.  */
137                     versioned_sym = sym;
138                   continue;
139                 }
140             }
141 #endif
142
143           /* There cannot be another entry for this symbol so stop here.  */
144           goto found_it;
145         }
146
147       /* If we have seen exactly one versioned symbol while we are
148          looking for an unversioned symbol and the version is not the
149          default version we still accept this symbol since there are
150          no possible ambiguities.  */
151 #if VERSIONED
152         sym = NULL;
153 #else
154         sym = num_versions == 1 ? versioned_sym : NULL;
155 #endif
156
157       if (sym != NULL)
158         {
159         found_it:
160           switch (ELFW(ST_BIND) (sym->st_info))
161             {
162             case STB_GLOBAL:
163               /* Global definition.  Just what we need.  */
164               result->s = sym;
165               result->m = map;
166               return 1;
167             case STB_WEAK:
168               /* Weak definition.  Use this value if we don't find another.  */
169               if (! result->s)
170                 {
171                   result->s = sym;
172                   result->m = map;
173                 }
174               break;
175             default:
176               /* Local symbols are ignored.  */
177               break;
178             }
179         }
180
181 #if VERSIONED
182       /* If this current map is the one mentioned in the verneed entry
183          and we have not found a weak entry, it is a bug.  */
184       if (symidx == STN_UNDEF && version->filename != NULL
185           && _dl_name_match_p (version->filename, map))
186         return -1;
187 #endif
188     }
189   while (++i < n);
190
191   /* We have not found anything until now.  */
192   return 0;
193 }
194
195 #undef FCT
196 #undef ARG
197 #undef VERSIONED