Sun Feb 27 15:22:36 1994 Stan Shebs (shebs@andros.cygnus.com)
[deliverable/binutils-gdb.git] / bfd / sunos.c
CommitLineData
0ee75d02
ILT
1/* BFD backend for SunOS binaries.
2 Copyright (C) 1990-1991 Free Software Foundation, Inc.
3 Written by Cygnus Support.
4a81b561 4
0ee75d02 5This file is part of BFD, the Binary File Descriptor library.
4a81b561 6
0ee75d02 7This program is free software; you can redistribute it and/or modify
4a81b561 8it under the terms of the GNU General Public License as published by
0ee75d02
ILT
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
4a81b561 11
0ee75d02 12This program is distributed in the hope that it will be useful,
4a81b561
DHW
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
0ee75d02
ILT
18along with this program; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
4a81b561 20
0ee75d02
ILT
21#define ARCH 32
22#define TARGETNAME "a.out-sunos-big"
23#define MY(OP) CAT(sunos_big_,OP)
4a81b561 24
4a81b561 25#include "bfd.h"
78aa64b1 26
0ee75d02 27/* Static routines defined in this file. */
4a81b561 28
0ee75d02 29struct external_nlist;
4a81b561 30
0ee75d02
ILT
31static boolean sunos_read_dynamic_info PARAMS ((bfd *));
32static bfd_size_type MY(read_dynamic_symbols)
33 PARAMS ((bfd *, struct external_nlist **, char **, bfd_size_type *));
34static bfd_size_type MY(read_dynamic_relocs) PARAMS ((bfd *, PTR *));
4a81b561 35
0ee75d02
ILT
36#define MY_read_dynamic_symbols MY(read_dynamic_symbols)
37#define MY_read_dynamic_relocs MY(read_dynamic_relocs)
4a81b561 38
0ee75d02
ILT
39/* Include the usual a.out support. */
40#include "aoutf1.h"
4a81b561 41
0ee75d02
ILT
42/* SunOS shared library support. We store a pointer to this structure
43 in obj_aout_dynamic_info (abfd). */
4a81b561 44
0ee75d02 45struct sunos_dynamic_info
78aa64b1 46{
0ee75d02
ILT
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};
4a81b561 63
0ee75d02
ILT
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. */
4a81b561 69
0ee75d02
ILT
70static boolean
71sunos_read_dynamic_info (abfd)
4a81b561
DHW
72 bfd *abfd;
73{
0ee75d02
ILT
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)));
9783e04a
DM
88 if (!info)
89 {
90 bfd_error = no_memory;
91 return false;
92 }
0ee75d02
ILT
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 /* We look for the __DYNAMIC symbol to locate the dynamic linking
100 information. It should be the first symbol if it is defined. If
101 we can't find it, don't sweat it. */
102 if ((abfd->flags & DYNAMIC) == 0
103 || bfd_get_symcount (abfd) <= 0
104 || bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
105 || (bfd_read ((PTR) &dynsym, 1, EXTERNAL_NLIST_SIZE, abfd)
106 != EXTERNAL_NLIST_SIZE)
107 || ((dynsym.e_type[0] & N_TYPE) != N_DATA
108 && (dynsym.e_type[0] & N_TYPE) != N_TEXT)
109 || bfd_seek (abfd,
110 obj_str_filepos (abfd) + GET_WORD (abfd, dynsym.e_strx),
111 SEEK_SET) != 0
112 || bfd_read ((PTR) buf, 1, sizeof buf, abfd) != sizeof buf
113 || buf[sizeof buf - 1] != '\0'
114 || strcmp (buf, "__DYNAMIC") != 0)
115 return true;
116
117 if ((dynsym.e_type[0] & N_TYPE) == N_DATA)
118 dynsec = obj_datasec (abfd);
119 else
120 dynsec = obj_textsec (abfd);
121 if (! bfd_get_section_contents (abfd, dynsec, (PTR) &dyninfo,
122 (GET_WORD (abfd, dynsym.e_value)
123 - bfd_get_section_vma (abfd, dynsec)),
124 sizeof dyninfo))
125 return true;
126
127 dynver = GET_WORD (abfd, dyninfo.ld_version);
128 if (dynver != 2 && dynver != 3)
129 return true;
130
131 dynoff = GET_WORD (abfd, dyninfo.ld);
132
133 /* dynoff is a virtual address. It is probably always in the .data
134 section, but this code should work even if it moves. */
135 if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
136 dynsec = obj_textsec (abfd);
137 else
138 dynsec = obj_datasec (abfd);
139 dynoff -= bfd_get_section_vma (abfd, dynsec);
140 if (dynoff < 0 || dynoff > bfd_section_size (abfd, dynsec))
141 return true;
142
143 /* This executable appears to be dynamically linked in a way that we
144 can understand. */
145 if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff,
146 (bfd_size_type) sizeof linkinfo))
147 return true;
148
149 /* Swap in the dynamic link information. */
150 info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded);
151 info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need);
152 info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules);
153 info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got);
154 info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt);
155 info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel);
156 info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash);
157 info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab);
158 info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash);
159 info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets);
160 info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols);
161 info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size);
162 info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text);
163 info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz);
164
165 /* The only way to get the size of the symbol information appears to
166 be to determine the distance between it and the string table. */
167 info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab)
168 / EXTERNAL_NLIST_SIZE);
169 BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE
170 == info->dyninfo.ld_symbols - info->dyninfo.ld_stab);
171
172 /* Similarly, the relocs end at the hash table. */
173 info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel)
174 / obj_reloc_entry_size (abfd));
175 BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
176 == info->dyninfo.ld_hash - info->dyninfo.ld_rel);
177
178 info->valid = true;
4a81b561
DHW
179
180 return true;
181}
182
0ee75d02 183/* Read in the dynamic symbols. */
4a81b561 184
0ee75d02
ILT
185static bfd_size_type
186MY(read_dynamic_symbols) (abfd, syms, strs, strsize)
4a81b561 187 bfd *abfd;
0ee75d02
ILT
188 struct external_nlist **syms;
189 char **strs;
190 bfd_size_type *strsize;
4a81b561 191{
0ee75d02 192 struct sunos_dynamic_info *info;
4a81b561 193
0ee75d02
ILT
194 if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
195 {
196 if (! sunos_read_dynamic_info (abfd))
197 return (bfd_size_type) -1;
4a81b561 198 }
c93595dd 199
0ee75d02
ILT
200 info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
201 if (! info->valid || info->dynsym_count == 0)
202 return 0;
10be52bf 203
0ee75d02
ILT
204 if (info->dynsym == (struct external_nlist *) NULL)
205 {
206 info->dynsym = ((struct external_nlist *)
207 bfd_alloc (abfd,
208 (info->dynsym_count
209 * EXTERNAL_NLIST_SIZE)));
210 info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size);
9783e04a
DM
211 if (!info->dynsym || !info->dynstr)
212 {
213 bfd_error = no_memory;
214 return 0;
215 }
0ee75d02
ILT
216 if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0
217 || (bfd_read ((PTR) info->dynsym, info->dynsym_count,
218 EXTERNAL_NLIST_SIZE, abfd)
219 != info->dynsym_count * EXTERNAL_NLIST_SIZE)
220 || bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0
221 || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size,
222 abfd)
223 != info->dyninfo.ld_symb_size))
224 return (bfd_size_type) -1;
225 }
1a602d6e 226
0ee75d02
ILT
227 *syms = info->dynsym;
228 *strs = info->dynstr;
229 *strsize = info->dyninfo.ld_symb_size;
4a81b561 230
0ee75d02
ILT
231#ifdef CHECK_DYNAMIC_HASH
232 /* Check my understanding of the dynamic hash table by making sure
233 that each symbol can be located in the hash table. */
234 {
235 bfd_size_type table_size;
236 bfd_byte *table;
237 bfd_size_type i;
238
239 if (info->dyninfo.ld_buckets > info->dynsym_count)
240 abort ();
241 table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
242 table = (bfd_byte *) alloca (table_size);
243 if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0
244 || bfd_read ((PTR) table, 1, table_size, abfd) != table_size)
245 abort ();
246 for (i = 0; i < info->dynsym_count; i++)
9846338e 247 {
0ee75d02
ILT
248 unsigned char *name;
249 unsigned long hash;
250
251 name = ((unsigned char *) info->dynstr
252 + GET_WORD (abfd, info->dynsym[i].e_strx));
253 hash = 0;
254 while (*name != '\0')
255 hash = (hash << 1) + *name++;
256 hash &= 0x7fffffff;
257 hash %= info->dyninfo.ld_buckets;
258 while (GET_WORD (abfd, table + 8 * hash) != i)
259 {
260 hash = GET_WORD (abfd, table + 8 * hash + 4);
261 if (hash == 0 || hash >= table_size / 8)
262 abort ();
263 }
9846338e 264 }
4a81b561 265 }
0ee75d02 266#endif /* CHECK_DYNAMIC_HASH */
4a81b561 267
0ee75d02 268 return info->dynsym_count;
4a81b561 269}
4a81b561 270
0ee75d02 271/* Read in the dynamic relocs for a section. */
4a81b561 272
0ee75d02
ILT
273static bfd_size_type
274MY(read_dynamic_relocs) (abfd, relocs)
4a81b561 275 bfd *abfd;
0ee75d02 276 PTR *relocs;
4a81b561 277{
0ee75d02 278 struct sunos_dynamic_info *info;
4a81b561 279
0ee75d02
ILT
280 if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
281 {
282 if (! sunos_read_dynamic_info (abfd))
283 return (bfd_size_type) -1;
284 }
4a81b561 285
0ee75d02
ILT
286 info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
287 if (! info->valid || info->dynrel_count == 0)
4a81b561 288 return 0;
4a81b561 289
9783e04a 290 if (info->dynrel == NULL)
0ee75d02
ILT
291 {
292 info->dynrel = (PTR) bfd_alloc (abfd,
293 (info->dynrel_count
294 * obj_reloc_entry_size (abfd)));
9783e04a
DM
295 if (!info->dynrel)
296 {
297 bfd_error = no_memory;
298 return (bfd_size_type) -1;
299 }
0ee75d02
ILT
300 if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0
301 || (bfd_read ((PTR) info->dynrel, info->dynrel_count,
302 obj_reloc_entry_size (abfd), abfd)
303 != info->dynrel_count * obj_reloc_entry_size (abfd)))
304 return (bfd_size_type) -1;
305 }
4a81b561 306
0ee75d02 307 *relocs = info->dynrel;
4a81b561 308
0ee75d02 309 return info->dynrel_count;
4a81b561 310}
This page took 0.122515 seconds and 4 git commands to generate.