b72a6a27d55c259840df7cda671b89f0e459bda5
[platform/upstream/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.  The chosen value can't be RELOC_ADDR.  If NOPLT is nonzero,
27    then a PLT entry cannot satisfy the reference; some different binding
28    must be found.  */
29
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                    Elf32_Addr reloc_addr,
35                    int noplt)
36 {
37   unsigned long int hash = elf_hash (undef_name);
38   struct link_map *map;
39   struct
40     {
41       Elf32_Addr a;
42       const Elf32_Sym *s;
43     } weak_value = { 0, NULL };
44
45   /* Search the relevant loaded objects for a definition.  */
46   for (map = symbol_scope; map; map = map->l_next)
47     {
48       const Elf32_Sym *symtab;
49       const char *strtab;
50       Elf32_Word symidx;
51
52       symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
53       strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
54
55       /* Search the appropriate hash bucket in this object's symbol table
56          for a definition for the same symbol name.  */
57       for (symidx = map->l_buckets[hash % map->l_nbuckets];
58            symidx != STN_UNDEF;
59            symidx = map->l_chain[symidx])
60         {
61           const Elf32_Sym *sym = &symtab[symidx];
62
63           if (sym->st_value == 0 || /* No value.  */
64               reloc_addr == map->l_addr + sym->st_value || /* Self ref.  */
65               (noplt && sym->st_shndx == SHN_UNDEF)) /* Unwanted PLT entry.  */
66             continue;
67
68           switch (ELF32_ST_TYPE (sym->st_info))
69             {
70             case STT_NOTYPE:
71             case STT_FUNC:
72             case STT_OBJECT:
73               break;
74             default:
75               /* Not a code/data definition.  */
76               continue;
77             }
78
79           if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
80             /* Not the symbol we are looking for.  */
81             continue;
82
83           switch (ELF32_ST_BIND (sym->st_info))
84             {
85             case STB_GLOBAL:
86               /* Global definition.  Just what we need.  */
87               *ref = sym;
88               return map->l_addr;
89             case STB_WEAK:
90               /* Weak definition.  Use this value if we don't find another.  */
91               if (! weak_value.s)
92                 {
93                   weak_value.s = sym;
94                   weak_value.a = map->l_addr;
95                 }
96               break;
97             default:
98               /* Local symbols are ignored.  */
99               break;
100             }
101         }
102     }
103
104   if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK)
105     {
106       const char msg[] = "undefined symbol: ";
107       char buf[sizeof msg + strlen (undef_name)];
108       memcpy (buf, msg, sizeof msg - 1);
109       memcpy (&buf[sizeof msg - 1], undef_name, sizeof buf - sizeof msg + 1);
110       _dl_signal_error (0, reference_name, buf);
111     }
112
113   *ref = weak_value.s;
114   return weak_value.a;
115 }
116
117
118 /* Cache the location of MAP's hash table.  */
119
120 void
121 _dl_setup_hash (struct link_map *map)
122 {
123   Elf32_Word *hash = (void *) map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr;
124   Elf32_Word nchain;
125   map->l_nbuckets = *hash++;
126   nchain = *hash++;
127   map->l_buckets = hash;
128   hash += map->l_nbuckets;
129   map->l_chain = hash;
130 }