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