* sunos.c (sunos_read_dynamic_info): Assume that dynamic info
[external/binutils.git] / bfd / sunos.c
1 /* BFD backend for SunOS binaries.
2    Copyright (C) 1990-1991 Free Software Foundation, Inc.
3    Written by Cygnus Support.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #define ARCH 32
22 #define TARGETNAME "a.out-sunos-big"
23 #define MY(OP) CAT(sunos_big_,OP)
24
25 #include "bfd.h"
26
27 /* Static routines defined in this file.  */
28
29 struct external_nlist;
30
31 static boolean sunos_read_dynamic_info PARAMS ((bfd *));
32 static bfd_size_type MY(read_dynamic_symbols)
33      PARAMS ((bfd *, struct external_nlist **, char **, bfd_size_type *));
34 static bfd_size_type MY(read_dynamic_relocs) PARAMS ((bfd *, PTR *));
35
36 #define MY_read_dynamic_symbols MY(read_dynamic_symbols)
37 #define MY_read_dynamic_relocs MY(read_dynamic_relocs)
38
39 /* Include the usual a.out support.  */
40 #include "aoutf1.h"
41
42 /* SunOS shared library support.  We store a pointer to this structure
43    in obj_aout_dynamic_info (abfd).  */
44
45 struct sunos_dynamic_info
46 {
47   /* Whether we found any dynamic information.  */
48   boolean valid;
49   /* Dynamic information.  */
50   struct internal_sun4_dynamic_link dyninfo;
51   /* Number of dynamic symbols.  */
52   bfd_size_type dynsym_count;
53   /* Read in nlists for dynamic symbols.  */
54   struct external_nlist *dynsym;
55   /* Read in dynamic string table.  */
56   char *dynstr;
57   /* Number of dynamic relocs.  */
58   bfd_size_type dynrel_count;
59   /* Read in dynamic relocs.  This may be reloc_std_external or
60      reloc_ext_external.  */
61   PTR dynrel;
62 };
63
64 /* Read in the basic dynamic information.  This locates the __DYNAMIC
65    structure and uses it to find the dynamic_link structure.  It
66    creates and saves a sunos_dynamic_info structure.  If it can't find
67    __DYNAMIC, it sets the valid field of the sunos_dynamic_info
68    structure to false to avoid doing this work again.  */
69
70 static boolean
71 sunos_read_dynamic_info (abfd)
72      bfd *abfd;
73 {
74   struct sunos_dynamic_info *info;
75   struct external_nlist dynsym;
76   char buf[sizeof "__DYNAMIC"];
77   asection *dynsec;
78   file_ptr dynoff;
79   struct external_sun4_dynamic dyninfo;
80   unsigned long dynver;
81   struct external_sun4_dynamic_link linkinfo;
82
83   if (obj_aout_dynamic_info (abfd) != (PTR) NULL)
84     return true;
85
86   info = ((struct sunos_dynamic_info *)
87           bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info)));
88   if (!info)
89     {
90       bfd_set_error (bfd_error_no_memory);
91       return false;
92     }
93   info->valid = false;
94   info->dynsym = NULL;
95   info->dynstr = NULL;
96   info->dynrel = NULL;
97   obj_aout_dynamic_info (abfd) = (PTR) info;
98
99   /* This code used to look for the __DYNAMIC symbol to locate the dynamic
100      linking information.
101      However this inhibits recovering the dynamic symbols from a
102      stripped object file, so blindly assume that the dynamic linking
103      information is located at the start of the data section.
104      We could verify this assumption later by looking through the dynamic
105      symbols for the __DYNAMIC symbol.  */
106   if ((abfd->flags & DYNAMIC) == 0)
107     return true;
108   if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (PTR) &dyninfo,
109                                   (file_ptr) 0, sizeof dyninfo))
110     return true;
111
112   dynver = GET_WORD (abfd, dyninfo.ld_version);
113   if (dynver != 2 && dynver != 3)
114     return true;
115
116   dynoff = GET_WORD (abfd, dyninfo.ld);
117
118   /* dynoff is a virtual address.  It is probably always in the .data
119      section, but this code should work even if it moves.  */
120   if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
121     dynsec = obj_textsec (abfd);
122   else
123     dynsec = obj_datasec (abfd);
124   dynoff -= bfd_get_section_vma (abfd, dynsec);
125   if (dynoff < 0 || dynoff > bfd_section_size (abfd, dynsec))
126     return true;
127
128   /* This executable appears to be dynamically linked in a way that we
129      can understand.  */
130   if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff,
131                                   (bfd_size_type) sizeof linkinfo))
132     return true;
133
134   /* Swap in the dynamic link information.  */
135   info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded);
136   info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need);
137   info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules);
138   info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got);
139   info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt);
140   info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel);
141   info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash);
142   info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab);
143   info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash);
144   info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets);
145   info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols);
146   info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size);
147   info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text);
148   info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz);
149
150   /* The only way to get the size of the symbol information appears to
151      be to determine the distance between it and the string table.  */
152   info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab)
153                         / EXTERNAL_NLIST_SIZE);
154   BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE
155               == info->dyninfo.ld_symbols - info->dyninfo.ld_stab);
156
157   /* Similarly, the relocs end at the hash table.  */
158   info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel)
159                         / obj_reloc_entry_size (abfd));
160   BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
161               == info->dyninfo.ld_hash - info->dyninfo.ld_rel);
162
163   info->valid = true;
164
165   return true;
166 }
167
168 /* Read in the dynamic symbols.  */
169
170 static bfd_size_type
171 MY(read_dynamic_symbols) (abfd, syms, strs, strsize)
172      bfd *abfd;
173      struct external_nlist **syms;
174      char **strs;
175      bfd_size_type *strsize;
176 {
177   struct sunos_dynamic_info *info;
178
179   if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
180     {
181       if (! sunos_read_dynamic_info (abfd))
182           return (bfd_size_type) -1;
183     }
184
185   info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
186   if (! info->valid || info->dynsym_count == 0)
187     return 0;
188
189   if (info->dynsym == (struct external_nlist *) NULL)
190     {
191       info->dynsym = ((struct external_nlist *)
192                       bfd_alloc (abfd,
193                                  (info->dynsym_count
194                                   * EXTERNAL_NLIST_SIZE)));
195       info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size);
196       if (!info->dynsym || !info->dynstr)
197         {
198           bfd_set_error (bfd_error_no_memory);
199           return 0;
200         }
201       if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0
202           || (bfd_read ((PTR) info->dynsym, info->dynsym_count,
203                         EXTERNAL_NLIST_SIZE, abfd)
204               != info->dynsym_count * EXTERNAL_NLIST_SIZE)
205           || bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0
206           || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size,
207                         abfd)
208               != info->dyninfo.ld_symb_size))
209         return (bfd_size_type) -1;
210     }
211
212   *syms = info->dynsym;
213   *strs = info->dynstr;
214   *strsize = info->dyninfo.ld_symb_size;
215
216 #ifdef CHECK_DYNAMIC_HASH
217   /* Check my understanding of the dynamic hash table by making sure
218      that each symbol can be located in the hash table.  */
219   {
220     bfd_size_type table_size;
221     bfd_byte *table;
222     bfd_size_type i;
223
224     if (info->dyninfo.ld_buckets > info->dynsym_count)
225       abort ();
226     table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
227     table = (bfd_byte *) malloc (table_size);
228     if (table == NULL)
229       abort ();
230     if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0
231         || bfd_read ((PTR) table, 1, table_size, abfd) != table_size)
232       abort ();
233     for (i = 0; i < info->dynsym_count; i++)
234       {
235         unsigned char *name;
236         unsigned long hash;
237
238         name = ((unsigned char *) info->dynstr
239                 + GET_WORD (abfd, info->dynsym[i].e_strx));
240         hash = 0;
241         while (*name != '\0')
242           hash = (hash << 1) + *name++;
243         hash &= 0x7fffffff;
244         hash %= info->dyninfo.ld_buckets;
245         while (GET_WORD (abfd, table + 8 * hash) != i)
246           {
247             hash = GET_WORD (abfd, table + 8 * hash + 4);
248             if (hash == 0 || hash >= table_size / 8)
249               abort ();
250           }
251       }
252     free (table);
253   }
254 #endif /* CHECK_DYNAMIC_HASH */
255
256   return info->dynsym_count;
257 }
258
259 /* Read in the dynamic relocs for a section.  */
260
261 static bfd_size_type
262 MY(read_dynamic_relocs) (abfd, relocs)
263      bfd *abfd;
264      PTR *relocs;
265 {
266   struct sunos_dynamic_info *info;
267
268   if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
269     {
270       if (! sunos_read_dynamic_info (abfd))
271           return (bfd_size_type) -1;
272     }
273
274   info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
275   if (! info->valid || info->dynrel_count == 0)
276     return 0;
277
278   if (info->dynrel == NULL)
279     {
280       info->dynrel = (PTR) bfd_alloc (abfd,
281                                       (info->dynrel_count
282                                        * obj_reloc_entry_size (abfd)));
283       if (!info->dynrel)
284         {
285           bfd_set_error (bfd_error_no_memory);
286           return (bfd_size_type) -1;
287         }
288       if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0
289           || (bfd_read ((PTR) info->dynrel, info->dynrel_count,
290                         obj_reloc_entry_size (abfd), abfd)
291               != info->dynrel_count * obj_reloc_entry_size (abfd)))
292         return (bfd_size_type) -1;
293     }
294
295   *relocs = info->dynrel;
296
297   return info->dynrel_count;
298 }