(dl_main): Grok --list flag.
[kopensolaris-gnu/glibc.git] / elf / dl-lookup.c
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.
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 
26    the symbol UNDEF_NAME.  If NOSELF is nonzero, then *REF
27    cannot satisfy the reference itself; 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                    int noself)
35 {
36   unsigned long int hash = elf_hash (undef_name);
37   struct link_map *map;
38   struct
39     {
40       Elf32_Addr a;
41       const Elf32_Sym *s;
42     } weak_value = { 0, NULL };
43
44   /* Search the relevant loaded objects for a definition.  */
45   for (map = symbol_scope; map; map = map->l_next)
46     {
47       const Elf32_Sym *symtab;
48       const char *strtab;
49       Elf32_Word symidx;
50
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);
53
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])
59         {
60           const Elf32_Sym *sym = &symtab[symidx];
61
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;
66
67           switch (ELF32_ST_TYPE (sym->st_info))
68             {
69             case STT_NOTYPE:
70             case STT_FUNC:
71             case STT_OBJECT:
72               break;
73             default:
74               /* Not a code/data definition.  */
75               continue;
76             }
77
78           if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
79             /* Not the symbol we are looking for.  */
80             continue;
81
82           switch (ELF32_ST_BIND (sym->st_info))
83             {
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)
91                 {
92                   weak_value.s = sym;
93                   weak_value.a = map->l_addr;
94                 }
95               break;
96             default:
97               /* Local symbols are ignored.  */
98               break;
99             }
100         }
101     }
102
103   if (weak_value.s == NULL)
104     {
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);
110     }
111
112   *ref = weak_value.s;
113   return weak_value.a;
114 }
115
116
117 /* Cache the location of MAP's hash table.  */
118
119 void
120 _dl_setup_hash (struct link_map *map)
121 {
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;
129 }