Rewritten.
[glibc.git] / elf / dl-lookup.c
blobcb337d47cd762296776a61ea12ea4bdc883bce62
1 /* Look up a symbol in the loaded objects.
2 Copyright (C) 1995 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA. */
20 #include <stddef.h>
21 #include <libelf.h>
22 #include <link.h>
23 #include <assert.h>
25 /* Search loaded objects' symbol tables for a definition of
26 the symbol UNDEF_NAME. If NOSELF is nonzero, then *REF
27 cannot satisfy the reference itself; some different binding
28 must be found. */
30 Elf32_Addr
31 _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
32 struct link_map *symbol_scope,
33 const char *reference_name,
34 int noself)
36 unsigned long int hash = elf_hash (undef_name);
37 struct link_map *map;
38 struct
40 Elf32_Addr a;
41 const Elf32_Sym *s;
42 } weak_value = { 0, NULL };
44 /* Search the relevant loaded objects for a definition. */
45 for (map = symbol_scope; map; map = map->l_next)
47 const Elf32_Sym *symtab;
48 const char *strtab;
49 Elf32_Word symidx;
51 symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
52 strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
54 /* Search the appropriate hash bucket in this object's symbol table
55 for a definition for the same symbol name. */
56 for (symidx = map->l_buckets[hash % map->l_nbuckets];
57 symidx != STN_UNDEF;
58 symidx = map->l_chain[symidx])
60 const Elf32_Sym *sym = &symtab[symidx];
62 if (sym->st_value == 0 || /* No value. */
63 sym->st_shndx == SHN_UNDEF || /* PLT entry. */
64 (noself && sym == *ref)) /* The reference can't define it. */
65 continue;
67 switch (ELF32_ST_TYPE (sym->st_info))
69 case STT_NOTYPE:
70 case STT_FUNC:
71 case STT_OBJECT:
72 break;
73 default:
74 /* Not a code/data definition. */
75 continue;
78 if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
79 /* Not the symbol we are looking for. */
80 continue;
82 switch (ELF32_ST_BIND (sym->st_info))
84 case STB_GLOBAL:
85 /* Global definition. Just what we need. */
86 *ref = sym;
87 return map->l_addr;
88 case STB_WEAK:
89 /* Weak definition. Use this value if we don't find another. */
90 if (! weak_value.s)
92 weak_value.s = sym;
93 weak_value.a = map->l_addr;
95 break;
96 default:
97 /* Local symbols are ignored. */
98 break;
103 if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK)
105 const char msg[] = "undefined symbol: ";
106 char buf[sizeof msg + strlen (undef_name)];
107 memcpy (buf, msg, sizeof msg - 1);
108 memcpy (&buf[sizeof msg - 1], undef_name, sizeof buf - sizeof msg + 1);
109 _dl_signal_error (0, reference_name, buf);
112 *ref = weak_value.s;
113 return weak_value.a;
117 /* Cache the location of MAP's hash table. */
119 void
120 _dl_setup_hash (struct link_map *map)
122 Elf32_Word *hash = (void *) map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr;
123 Elf32_Word nchain;
124 map->l_nbuckets = *hash++;
125 nchain = *hash++;
126 map->l_buckets = hash;
127 hash += map->l_nbuckets;
128 map->l_chain = hash;