Commit | Line | Data |
---|---|---|
1136f72d | 1 | /* |
6a61ea88 | 2 | * $Id: lib.c,v 1.8 1993/12/22 23:28:11 jkh Exp $ - library routines |
1136f72d PR |
3 | */ |
4 | ||
5 | #include <sys/param.h> | |
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
8 | #include <sys/types.h> | |
9 | #include <sys/stat.h> | |
10 | #include <sys/file.h> | |
11 | #include <sys/time.h> | |
12 | #include <fcntl.h> | |
13 | #include <ar.h> | |
14 | #include <ranlib.h> | |
15 | #include <a.out.h> | |
16 | #include <stab.h> | |
17 | #include <string.h> | |
18 | #include <dirent.h> | |
19 | ||
20 | #include "ld.h" | |
21 | ||
6a61ea88 JH |
22 | static void linear_library __P((int, struct file_entry *)); |
23 | static void symdef_library __P((int, struct file_entry *, int)); | |
24 | static struct file_entry *decode_library_subfile __P((int, | |
25 | struct file_entry *, | |
26 | int, int *)); | |
1136f72d PR |
27 | |
28 | /* | |
29 | * Search the library ENTRY, already open on descriptor DESC. This means | |
30 | * deciding which library members to load, making a chain of `struct | |
31 | * file_entry' for those members, and entering their global symbols in the | |
32 | * hash table. | |
33 | */ | |
34 | ||
35 | void | |
36 | search_library(desc, entry) | |
37 | int desc; | |
38 | struct file_entry *entry; | |
39 | { | |
40 | int member_length; | |
41 | register char *name; | |
42 | register struct file_entry *subentry; | |
43 | ||
44 | if (!(link_mode & FORCEARCHIVE) && !undefined_global_sym_count) | |
45 | return; | |
46 | ||
47 | /* Examine its first member, which starts SARMAG bytes in. */ | |
48 | subentry = decode_library_subfile(desc, entry, SARMAG, &member_length); | |
49 | if (!subentry) | |
50 | return; | |
51 | ||
52 | name = subentry->filename; | |
53 | free(subentry); | |
54 | ||
55 | /* Search via __.SYMDEF if that exists, else linearly. */ | |
56 | ||
57 | if (!strcmp(name, "__.SYMDEF")) | |
58 | symdef_library(desc, entry, member_length); | |
59 | else | |
60 | linear_library(desc, entry); | |
61 | } | |
62 | ||
63 | /* | |
64 | * Construct and return a file_entry for a library member. The library's | |
65 | * file_entry is library_entry, and the library is open on DESC. | |
66 | * SUBFILE_OFFSET is the byte index in the library of this member's header. | |
67 | * We store the length of the member into *LENGTH_LOC. | |
68 | */ | |
69 | ||
6a61ea88 | 70 | static struct file_entry * |
1136f72d PR |
71 | decode_library_subfile(desc, library_entry, subfile_offset, length_loc) |
72 | int desc; | |
73 | struct file_entry *library_entry; | |
74 | int subfile_offset; | |
75 | int *length_loc; | |
76 | { | |
77 | int bytes_read; | |
78 | register int namelen; | |
0f052032 JH |
79 | int member_length, content_length; |
80 | int starting_offset; | |
1136f72d PR |
81 | register char *name; |
82 | struct ar_hdr hdr1; | |
83 | register struct file_entry *subentry; | |
1558d71a | 84 | |
1136f72d PR |
85 | lseek(desc, subfile_offset, 0); |
86 | ||
87 | bytes_read = read(desc, &hdr1, sizeof hdr1); | |
88 | if (!bytes_read) | |
89 | return 0; /* end of archive */ | |
90 | ||
91 | if (sizeof hdr1 != bytes_read) | |
92 | fatal_with_file("malformed library archive ", library_entry); | |
93 | ||
94 | if (sscanf(hdr1.ar_size, "%d", &member_length) != 1) | |
95 | fatal_with_file("malformatted header of archive member in ", library_entry); | |
96 | ||
97 | subentry = (struct file_entry *) xmalloc(sizeof(struct file_entry)); | |
98 | bzero(subentry, sizeof(struct file_entry)); | |
99 | ||
100 | for (namelen = 0; | |
101 | namelen < sizeof hdr1.ar_name | |
102 | && hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' ' | |
103 | && hdr1.ar_name[namelen] != '/'; | |
104 | namelen++); | |
105 | ||
0f052032 JH |
106 | starting_offset = subfile_offset + sizeof hdr1; |
107 | content_length = member_length; | |
108 | ||
109 | #ifdef AR_EFMT1 | |
110 | /* | |
111 | * BSD 4.4 extended AR format: #1/<namelen>, with name as the | |
112 | * first <namelen> bytes of the file | |
113 | */ | |
6a61ea88 JH |
114 | if (strncmp(hdr1.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && |
115 | isdigit(hdr1.ar_name[sizeof(AR_EFMT1) - 1])) { | |
0f052032 | 116 | |
6a61ea88 | 117 | namelen = atoi(&hdr1.ar_name[sizeof(AR_EFMT1) - 1]); |
0f052032 JH |
118 | name = (char *)xmalloc(namelen + 1); |
119 | if (read(desc, name, namelen) != namelen) | |
120 | fatal_with_file( | |
121 | "malformatted header of archive member in ", | |
122 | library_entry); | |
123 | name[namelen] = 0; | |
124 | content_length -= namelen; | |
125 | starting_offset += namelen; | |
126 | } else | |
127 | ||
128 | #endif | |
129 | { | |
130 | name = (char *)xmalloc(namelen + 1); | |
131 | strncpy(name, hdr1.ar_name, namelen); | |
132 | name[namelen] = 0; | |
133 | } | |
1558d71a | 134 | |
1136f72d PR |
135 | subentry->filename = name; |
136 | subentry->local_sym_name = name; | |
137 | subentry->symbols = 0; | |
138 | subentry->strings = 0; | |
139 | subentry->subfiles = 0; | |
0f052032 | 140 | subentry->starting_offset = starting_offset; |
1136f72d | 141 | subentry->superfile = library_entry; |
1136f72d | 142 | subentry->chain = 0; |
6a61ea88 | 143 | subentry->flags = 0; |
0f052032 | 144 | subentry->total_size = content_length; |
1136f72d PR |
145 | |
146 | (*length_loc) = member_length; | |
147 | ||
148 | return subentry; | |
149 | } | |
150 | ||
6a61ea88 | 151 | static int subfile_wanted_p __P((struct file_entry *)); |
1136f72d PR |
152 | |
153 | /* | |
154 | * Search a library that has a __.SYMDEF member. DESC is a descriptor on | |
155 | * which the library is open. The file pointer is assumed to point at the | |
156 | * __.SYMDEF data. ENTRY is the library's file_entry. MEMBER_LENGTH is the | |
157 | * length of the __.SYMDEF data. | |
158 | */ | |
159 | ||
6a61ea88 | 160 | static void |
1136f72d PR |
161 | symdef_library(desc, entry, member_length) |
162 | int desc; | |
163 | struct file_entry *entry; | |
164 | int member_length; | |
165 | { | |
166 | int *symdef_data = (int *) xmalloc(member_length); | |
167 | register struct ranlib *symdef_base; | |
168 | char *sym_name_base; | |
6a61ea88 | 169 | int nsymdefs; |
1136f72d PR |
170 | int length_of_strings; |
171 | int not_finished; | |
172 | int bytes_read; | |
173 | register int i; | |
174 | struct file_entry *prev = 0; | |
175 | int prev_offset = 0; | |
176 | ||
177 | bytes_read = read(desc, symdef_data, member_length); | |
178 | if (bytes_read != member_length) | |
179 | fatal_with_file("malformatted __.SYMDEF in ", entry); | |
180 | ||
6a61ea88 JH |
181 | nsymdefs = md_swap_long(*symdef_data) / sizeof(struct ranlib); |
182 | if (nsymdefs < 0 || | |
183 | nsymdefs * sizeof(struct ranlib) + 2 * sizeof(int) > member_length) | |
1136f72d PR |
184 | fatal_with_file("malformatted __.SYMDEF in ", entry); |
185 | ||
186 | symdef_base = (struct ranlib *) (symdef_data + 1); | |
6a61ea88 | 187 | length_of_strings = md_swap_long(*(int *) (symdef_base + nsymdefs)); |
1136f72d PR |
188 | |
189 | if (length_of_strings < 0 | |
6a61ea88 | 190 | || nsymdefs * sizeof(struct ranlib) + length_of_strings |
1136f72d PR |
191 | + 2 * sizeof(int) > member_length) |
192 | fatal_with_file("malformatted __.SYMDEF in ", entry); | |
193 | ||
6a61ea88 | 194 | sym_name_base = sizeof(int) + (char *) (symdef_base + nsymdefs); |
1136f72d PR |
195 | |
196 | /* Check all the string indexes for validity. */ | |
6a61ea88 JH |
197 | md_swapin_ranlib_hdr(symdef_base, nsymdefs); |
198 | for (i = 0; i < nsymdefs; i++) { | |
1136f72d PR |
199 | register int index = symdef_base[i].ran_un.ran_strx; |
200 | if (index < 0 || index >= length_of_strings | |
201 | || (index && *(sym_name_base + index - 1))) | |
202 | fatal_with_file("malformatted __.SYMDEF in ", entry); | |
203 | } | |
204 | ||
205 | /* | |
206 | * Search the symdef data for members to load. Do this until one | |
207 | * whole pass finds nothing to load. | |
208 | */ | |
209 | ||
210 | not_finished = 1; | |
211 | while (not_finished) { | |
212 | ||
213 | not_finished = 0; | |
214 | ||
215 | /* | |
216 | * Scan all the symbols mentioned in the symdef for ones that | |
217 | * we need. Load the library members that contain such | |
218 | * symbols. | |
219 | */ | |
220 | ||
6a61ea88 | 221 | for (i = 0; (i < nsymdefs && |
1136f72d PR |
222 | ((link_mode & FORCEARCHIVE) || |
223 | undefined_global_sym_count || | |
224 | common_defined_global_count)); i++) { | |
225 | ||
226 | register symbol *sp; | |
227 | int junk; | |
228 | register int j; | |
229 | register int offset = symdef_base[i].ran_off; | |
230 | struct file_entry *subentry; | |
231 | ||
232 | ||
233 | if (symdef_base[i].ran_un.ran_strx < 0) | |
234 | continue; | |
235 | ||
236 | sp = getsym_soft(sym_name_base | |
237 | + symdef_base[i].ran_un.ran_strx); | |
238 | ||
239 | /* | |
240 | * If we find a symbol that appears to be needed, | |
241 | * think carefully about the archive member that the | |
242 | * symbol is in. | |
243 | */ | |
244 | ||
245 | /* | |
246 | * Per Mike Karels' recommendation, we no longer load | |
247 | * library files if the only reference(s) that would | |
248 | * be satisfied are 'common' references. This | |
249 | * prevents some problems with name pollution (e.g. a | |
250 | * global common 'utime' linked to a function). | |
251 | */ | |
252 | if (!(link_mode & FORCEARCHIVE) && | |
6a61ea88 JH |
253 | (!sp || sp->defined || |
254 | (!(sp->flags & GS_REFERENCED) && | |
255 | !sp->sorefs))) | |
1136f72d PR |
256 | continue; |
257 | ||
258 | /* | |
259 | * Don't think carefully about any archive member | |
260 | * more than once in a given pass. | |
261 | */ | |
262 | ||
263 | if (prev_offset == offset) | |
264 | continue; | |
265 | prev_offset = offset; | |
266 | ||
267 | /* | |
268 | * Read the symbol table of the archive member. | |
269 | */ | |
270 | ||
271 | subentry = decode_library_subfile(desc, | |
272 | entry, offset, &junk); | |
273 | if (subentry == 0) | |
274 | fatal( | |
6a61ea88 | 275 | "invalid offset for %s in symbol table of %s", |
1136f72d PR |
276 | sym_name_base |
277 | + symdef_base[i].ran_un.ran_strx, | |
278 | entry->filename); | |
6a61ea88 | 279 | |
1136f72d PR |
280 | read_entry_symbols(desc, subentry); |
281 | subentry->strings = (char *) | |
282 | malloc(subentry->string_size); | |
283 | read_entry_strings(desc, subentry); | |
284 | ||
285 | /* | |
286 | * Now scan the symbol table and decide whether to | |
287 | * load. | |
288 | */ | |
289 | ||
290 | if (!(link_mode & FORCEARCHIVE) && | |
291 | !subfile_wanted_p(subentry)) { | |
292 | free(subentry->symbols); | |
293 | free(subentry); | |
294 | } else { | |
295 | /* | |
296 | * This member is needed; load it. Since we | |
297 | * are loading something on this pass, we | |
298 | * must make another pass through the symdef | |
299 | * data. | |
300 | */ | |
301 | ||
302 | not_finished = 1; | |
303 | ||
304 | read_entry_relocation(desc, subentry); | |
305 | enter_file_symbols(subentry); | |
306 | ||
307 | if (prev) | |
308 | prev->chain = subentry; | |
309 | else | |
310 | entry->subfiles = subentry; | |
311 | prev = subentry; | |
312 | ||
313 | /* | |
314 | * Clear out this member's symbols from the | |
315 | * symdef data so that following passes won't | |
316 | * waste time on them. | |
317 | */ | |
318 | ||
6a61ea88 | 319 | for (j = 0; j < nsymdefs; j++) { |
1136f72d PR |
320 | if (symdef_base[j].ran_off == offset) |
321 | symdef_base[j].ran_un.ran_strx = -1; | |
322 | } | |
323 | } | |
324 | ||
325 | /* | |
326 | * We'll read the strings again if we need them | |
327 | * again. | |
328 | */ | |
329 | free(subentry->strings); | |
330 | subentry->strings = 0; | |
331 | } | |
332 | } | |
333 | ||
334 | free(symdef_data); | |
335 | } | |
336 | ||
337 | /* | |
338 | * Search a library that has no __.SYMDEF. ENTRY is the library's file_entry. | |
339 | * DESC is the descriptor it is open on. | |
340 | */ | |
341 | ||
6a61ea88 | 342 | static void |
1136f72d PR |
343 | linear_library(desc, entry) |
344 | int desc; | |
345 | struct file_entry *entry; | |
346 | { | |
347 | register struct file_entry *prev = 0; | |
348 | register int this_subfile_offset = SARMAG; | |
349 | ||
350 | while ((link_mode & FORCEARCHIVE) || | |
351 | undefined_global_sym_count || common_defined_global_count) { | |
352 | ||
6a61ea88 JH |
353 | int member_length; |
354 | register struct file_entry *subentry; | |
1136f72d | 355 | |
6a61ea88 JH |
356 | subentry = decode_library_subfile(desc, entry, |
357 | this_subfile_offset, &member_length); | |
1136f72d PR |
358 | |
359 | if (!subentry) | |
360 | return; | |
361 | ||
362 | read_entry_symbols(desc, subentry); | |
363 | subentry->strings = (char *) alloca(subentry->string_size); | |
364 | read_entry_strings(desc, subentry); | |
365 | ||
366 | if (!(link_mode & FORCEARCHIVE) && | |
367 | !subfile_wanted_p(subentry)) { | |
368 | free(subentry->symbols); | |
369 | free(subentry); | |
370 | } else { | |
371 | read_entry_relocation(desc, subentry); | |
372 | enter_file_symbols(subentry); | |
373 | ||
374 | if (prev) | |
375 | prev->chain = subentry; | |
376 | else | |
377 | entry->subfiles = subentry; | |
378 | prev = subentry; | |
379 | subentry->strings = 0; /* Since space will dissapear | |
380 | * on return */ | |
381 | } | |
382 | ||
383 | this_subfile_offset += member_length + sizeof(struct ar_hdr); | |
384 | if (this_subfile_offset & 1) | |
385 | this_subfile_offset++; | |
386 | } | |
387 | } | |
388 | ||
389 | /* | |
390 | * ENTRY is an entry for a library member. Its symbols have been read into | |
391 | * core, but not entered. Return nonzero if we ought to load this member. | |
392 | */ | |
393 | ||
6a61ea88 | 394 | static int |
1136f72d PR |
395 | subfile_wanted_p(entry) |
396 | struct file_entry *entry; | |
397 | { | |
398 | struct localsymbol *lsp, *lspend; | |
399 | #ifdef DOLLAR_KLUDGE | |
400 | register int dollar_cond = 0; | |
401 | #endif | |
402 | ||
403 | lspend = entry->symbols + entry->nsymbols; | |
404 | ||
405 | for (lsp = entry->symbols; lsp < lspend; lsp++) { | |
406 | register struct nlist *p = &lsp->nzlist.nlist; | |
6a61ea88 JH |
407 | register int type = p->n_type; |
408 | register char *name = p->n_un.n_strx + entry->strings; | |
409 | register symbol *sp = getsym_soft(name); | |
1136f72d PR |
410 | |
411 | /* | |
412 | * If the symbol has an interesting definition, we could | |
413 | * potentially want it. | |
414 | */ | |
415 | if (! (type & N_EXT) | |
416 | || (type == (N_UNDF | N_EXT) && p->n_value == 0 | |
417 | ||
418 | #ifdef DOLLAR_KLUDGE | |
419 | && name[1] != '$' | |
420 | #endif | |
421 | ) | |
422 | #ifdef SET_ELEMENT_P | |
423 | || SET_ELEMENT_P(type) | |
424 | || set_element_prefixed_p(name) | |
425 | #endif | |
426 | ) | |
427 | continue; | |
428 | ||
429 | ||
430 | #ifdef DOLLAR_KLUDGE | |
431 | if (name[1] == '$') { | |
432 | sp = getsym_soft(&name[2]); | |
433 | dollar_cond = 1; | |
434 | if (!sp) | |
435 | continue; | |
6a61ea88 | 436 | if (sp->flags & SP_REFERENCED) { |
1136f72d PR |
437 | if (write_map) { |
438 | print_file_name(entry, stdout); | |
439 | fprintf(stdout, " needed due to $-conditional %s\n", name); | |
440 | } | |
441 | return 1; | |
442 | } | |
443 | continue; | |
444 | } | |
445 | #endif | |
446 | ||
447 | /* | |
448 | * If this symbol has not been hashed, we can't be | |
449 | * looking for it. | |
450 | */ | |
451 | ||
452 | if (!sp) | |
453 | continue; | |
454 | ||
455 | /* | |
456 | * We don't load a file if it merely satisfies a | |
457 | * common reference (see explanation above in | |
458 | * symdef_library()). | |
459 | */ | |
6a61ea88 | 460 | if ((sp->flags & GS_REFERENCED) && !sp->defined) { |
1136f72d PR |
461 | /* |
462 | * This is a symbol we are looking for. It | |
463 | * is either not yet defined or defined as a | |
464 | * common. | |
465 | */ | |
466 | #ifdef DOLLAR_KLUDGE | |
467 | if (dollar_cond) | |
468 | continue; | |
469 | #endif | |
470 | if (type == (N_UNDF | N_EXT)) { | |
471 | /* | |
472 | * Symbol being defined as common. | |
473 | * Remember this, but don't load | |
474 | * subfile just for this. | |
475 | */ | |
476 | ||
477 | /* | |
478 | * If it didn't used to be common, up | |
479 | * the count of common symbols. | |
480 | */ | |
6a61ea88 | 481 | if (!sp->common_size) |
1136f72d PR |
482 | common_defined_global_count++; |
483 | ||
6a61ea88 JH |
484 | if (sp->common_size < p->n_value) |
485 | sp->common_size = p->n_value; | |
1136f72d PR |
486 | if (!sp->defined) |
487 | undefined_global_sym_count--; | |
488 | sp->defined = type; | |
489 | continue; | |
490 | } | |
491 | if (write_map) { | |
492 | print_file_name(entry, stdout); | |
493 | fprintf(stdout, " needed due to %s\n", sp->name); | |
494 | } | |
495 | return 1; | |
496 | } else { | |
6a61ea88 JH |
497 | /* |
498 | * Check for undefined symbols or commons | |
499 | * in shared objects. | |
500 | */ | |
1136f72d | 501 | struct localsymbol *lsp; |
6a61ea88 JH |
502 | int wascommon = sp->defined && sp->common_size; |
503 | int iscommon = type == (N_UNDF|N_EXT) && p->n_value; | |
504 | ||
505 | if (wascommon) { | |
506 | /* | |
507 | * sp was defined as common by shared object. | |
508 | */ | |
509 | if (iscommon && p->n_value < sp->common_size) | |
510 | sp->common_size = p->n_value; | |
511 | continue; | |
512 | } | |
1136f72d | 513 | |
0f052032 JH |
514 | if (sp->sorefs == NULL) |
515 | continue; | |
516 | ||
1136f72d | 517 | for (lsp = sp->sorefs; lsp; lsp = lsp->next) { |
6a61ea88 | 518 | int type = lsp->nzlist.nlist.n_type; |
1136f72d PR |
519 | if ( (type & N_EXT) && |
520 | (type & N_STAB) == 0 && | |
521 | type != (N_UNDF | N_EXT)) | |
6a61ea88 JH |
522 | break; /* We don't need it */ |
523 | } | |
524 | if (lsp != NULL) { | |
525 | /* There's a real definition */ | |
526 | if (iscommon) | |
527 | /* | |
528 | * But this member wants it to be | |
529 | * a common; ignore it. | |
530 | continue; | |
531 | } | |
532 | ||
533 | if (iscommon) { | |
534 | /* | |
535 | * New symbol is common, just takes its | |
536 | * size, but don't load. | |
537 | */ | |
538 | sp->common_size = p->n_value; | |
539 | sp->defined = type; | |
540 | continue; | |
1136f72d | 541 | } |
6a61ea88 JH |
542 | |
543 | /* | |
544 | * THIS STILL MISSES the case where one shared | |
545 | * object defines a common and the next defines | |
546 | * more strongly; fix this someday by making | |
547 | * `struct glosym' and enter_global_ref() more | |
548 | * symmetric. | |
549 | */ | |
7fc7155d | 550 | |
1136f72d PR |
551 | if (write_map) { |
552 | print_file_name(entry, stdout); | |
553 | fprintf(stdout, " needed due to shared lib ref %s\n", sp->name); | |
554 | } | |
555 | return 1; | |
1136f72d PR |
556 | } |
557 | } | |
558 | ||
559 | return 0; | |
560 | } | |
561 | ||
562 | /* | |
563 | * Read the symbols of dynamic entity ENTRY into core. Assume it is already | |
564 | * open, on descriptor DESC. | |
565 | */ | |
566 | void | |
567 | read_shared_object (desc, entry) | |
568 | struct file_entry *entry; | |
569 | int desc; | |
570 | { | |
6a61ea88 JH |
571 | struct _dynamic dyn; |
572 | struct section_dispatch_table sdt; | |
573 | struct nlist *np; | |
574 | struct nzlist *nzp; | |
575 | int n, i, has_nz = 0; | |
1136f72d | 576 | |
6a61ea88 | 577 | if (!(entry->flags & E_HEADER_VALID)) |
1136f72d PR |
578 | read_header (desc, entry); |
579 | ||
580 | /* Read DYNAMIC structure (first in data segment) */ | |
581 | lseek (desc, | |
582 | text_offset (entry) + entry->header.a_text, | |
583 | L_SET); | |
584 | if (read(desc, &dyn, sizeof dyn) != sizeof dyn) { | |
585 | fatal_with_file ( | |
586 | "premature eof in data segment of ", entry); | |
587 | } | |
6a61ea88 | 588 | md_swapin__dynamic(&dyn); |
1136f72d PR |
589 | |
590 | /* Check version */ | |
6a61ea88 | 591 | switch (dyn.d_version) { |
1136f72d PR |
592 | default: |
593 | fatal_with_file( "unsupported _DYNAMIC version ", entry); | |
594 | break; | |
595 | case LD_VERSION_SUN: | |
596 | break; | |
597 | case LD_VERSION_BSD: | |
598 | has_nz = 1; | |
599 | break; | |
600 | } | |
601 | ||
6a61ea88 | 602 | /* Read Section Dispatch Table (from data segment) */ |
1136f72d | 603 | lseek (desc, |
6a61ea88 JH |
604 | text_offset(entry) + (long)dyn.d_un.d_sdt - |
605 | (DATA_START(entry->header) - N_DATOFF(entry->header)), | |
1136f72d | 606 | L_SET); |
6a61ea88 | 607 | if (read(desc, &sdt, sizeof sdt) != sizeof sdt) { |
1136f72d PR |
608 | fatal_with_file( "premature eof in data segment of ", entry); |
609 | } | |
6a61ea88 | 610 | md_swapin_section_dispatch_table(&sdt); |
1136f72d PR |
611 | |
612 | /* Read symbols (text segment) */ | |
6a61ea88 | 613 | n = sdt.sdt_strings - sdt.sdt_nzlist; |
1136f72d PR |
614 | entry->nsymbols = n / |
615 | (has_nz ? sizeof(struct nzlist) : sizeof(struct nlist)); | |
616 | nzp = (struct nzlist *)(np = (struct nlist *) alloca (n)); | |
617 | entry->symbols = (struct localsymbol *) | |
618 | xmalloc(entry->nsymbols * sizeof(struct localsymbol)); | |
6a61ea88 JH |
619 | lseek(desc, text_offset(entry) + (long)sdt.sdt_nzlist - |
620 | (TEXT_START(entry->header) - N_TXTOFF(entry->header)), | |
621 | L_SET); | |
1136f72d PR |
622 | if (read(desc, (char *)nzp, n) != n) { |
623 | fatal_with_file( | |
6a61ea88 | 624 | "premature eof while reading object symbols ", entry); |
1136f72d PR |
625 | } |
626 | if (has_nz) | |
627 | md_swapin_zsymbols(nzp, entry->nsymbols); | |
628 | else | |
629 | md_swapin_symbols(np, entry->nsymbols); | |
630 | ||
631 | /* Convert to structs localsymbol */ | |
632 | for (i = 0; i < entry->nsymbols; i++) { | |
633 | if (has_nz) { | |
634 | entry->symbols[i].nzlist = *nzp++; | |
635 | } else { | |
636 | entry->symbols[i].nzlist.nlist = *np++; | |
637 | entry->symbols[i].nzlist.nz_size = 0; | |
638 | } | |
639 | entry->symbols[i].symbol = NULL; | |
640 | entry->symbols[i].next = NULL; | |
6a61ea88 | 641 | entry->symbols[i].entry = entry; |
1136f72d | 642 | entry->symbols[i].gotslot_offset = -1; |
6a61ea88 | 643 | entry->symbols[i].flags = 0; |
1136f72d PR |
644 | } |
645 | ||
646 | /* Read strings (text segment) */ | |
6a61ea88 | 647 | n = entry->string_size = sdt.sdt_str_sz; |
1136f72d | 648 | entry->strings = (char *) alloca(n); |
6a61ea88 JH |
649 | entry->strings_offset = text_offset(entry) + sdt.sdt_strings; |
650 | lseek(desc, entry->strings_offset - | |
651 | (TEXT_START(entry->header) - N_TXTOFF(entry->header)), | |
652 | L_SET); | |
1136f72d PR |
653 | if (read(desc, entry->strings, n) != n) { |
654 | fatal_with_file( | |
6a61ea88 | 655 | "premature eof while reading object strings ", entry); |
1136f72d PR |
656 | } |
657 | enter_file_symbols (entry); | |
658 | entry->strings = 0; | |
659 | ||
0f052032 JH |
660 | /* |
661 | * Load any subsidiary shared objects. | |
662 | */ | |
6a61ea88 JH |
663 | if (sdt.sdt_sods) { |
664 | struct sod sod; | |
0f052032 | 665 | off_t offset; |
6a61ea88 | 666 | struct file_entry *prev = NULL; |
0f052032 | 667 | |
6a61ea88 | 668 | offset = (off_t)sdt.sdt_sods; |
0f052032 | 669 | while (1) { |
6a61ea88 | 670 | struct file_entry *subentry; |
0f052032 JH |
671 | char *libname, name[MAXPATHLEN]; /*XXX*/ |
672 | ||
6a61ea88 JH |
673 | subentry = (struct file_entry *) |
674 | xmalloc(sizeof(struct file_entry)); | |
675 | bzero(subentry, sizeof(struct file_entry)); | |
676 | subentry->superfile = entry; | |
677 | ||
678 | lseek(desc, offset - | |
679 | (TEXT_START(entry->header) - N_TXTOFF(entry->header)), | |
680 | L_SET); | |
681 | if (read(desc, &sod, sizeof(sod)) != sizeof(sod)) { | |
0f052032 | 682 | fatal_with_file( |
6a61ea88 | 683 | "premature eof while reading sod ", |
0f052032 JH |
684 | entry); |
685 | } | |
6a61ea88 JH |
686 | md_swapin_sod(&sod, 1); |
687 | (void)lseek(desc, (off_t)sod.sod_name - | |
688 | (TEXT_START(entry->header) - N_TXTOFF(entry->header)), | |
689 | L_SET); | |
0f052032 | 690 | (void)read(desc, name, sizeof(name)); /*XXX*/ |
6a61ea88 JH |
691 | if (sod.sod_library) { |
692 | int sod_major = sod.sod_major; | |
693 | int sod_minor = sod.sod_minor; | |
0f052032 JH |
694 | |
695 | libname = findshlib(name, | |
6a61ea88 | 696 | &sod_major, &sod_minor, 0); |
0f052032 JH |
697 | if (libname == NULL) |
698 | fatal("no shared -l%s.%d.%d available", | |
6a61ea88 | 699 | name, sod.sod_major, sod.sod_minor); |
0f052032 JH |
700 | subentry->filename = libname; |
701 | subentry->local_sym_name = concat("-l", name, ""); | |
702 | } else { | |
703 | subentry->filename = strdup(name); | |
704 | subentry->local_sym_name = strdup(name); | |
705 | } | |
706 | read_file_symbols(subentry); | |
707 | ||
708 | if (prev) | |
709 | prev->chain = subentry; | |
710 | else | |
711 | entry->subfiles = subentry; | |
712 | prev = subentry; | |
92575836 | 713 | desc = file_open(entry); |
6a61ea88 | 714 | if ((offset = (off_t)sod.sod_next) == 0) |
0f052032 JH |
715 | break; |
716 | } | |
717 | } | |
718 | #ifdef SUN_COMPAT | |
719 | if (link_mode & SILLYARCHIVE) { | |
720 | char *cp, *sa_name; | |
721 | char armag[SARMAG]; | |
722 | int fd; | |
723 | struct file_entry *subentry; | |
724 | ||
725 | sa_name = strdup(entry->filename); | |
726 | if (sa_name == NULL) | |
727 | goto out; | |
728 | cp = sa_name + strlen(sa_name) - 1; | |
729 | while (cp > sa_name) { | |
730 | if (!isdigit(*cp) && *cp != '.') | |
731 | break; | |
732 | --cp; | |
733 | } | |
734 | if (cp <= sa_name || *cp != 'o') { | |
735 | /* Not in `libxxx.so.n.m' form */ | |
736 | free(sa_name); | |
737 | goto out; | |
738 | } | |
739 | ||
740 | *cp = 'a'; | |
741 | if ((fd = open(sa_name, O_RDONLY, 0)) < 0) | |
742 | goto out; | |
743 | ||
744 | /* Read archive magic */ | |
745 | bzero(armag, SARMAG); | |
746 | (void)read(fd, armag, SARMAG); | |
747 | (void)close(fd); | |
748 | if (strncmp(armag, ARMAG, SARMAG) != 0) { | |
749 | error("%s: malformed silly archive", | |
750 | get_file_name(entry)); | |
751 | goto out; | |
752 | } | |
753 | ||
754 | subentry = (struct file_entry *) | |
755 | xmalloc(sizeof(struct file_entry)); | |
756 | bzero(subentry, sizeof(struct file_entry)); | |
757 | ||
758 | entry->silly_archive = subentry; | |
759 | subentry->superfile = entry; | |
760 | subentry->filename = sa_name; | |
761 | subentry->local_sym_name = sa_name; | |
6a61ea88 | 762 | subentry->flags |= E_IS_LIBRARY; |
0f052032 JH |
763 | search_library(file_open(subentry), subentry); |
764 | out: | |
765 | ; | |
1136f72d | 766 | } |
0f052032 | 767 | #endif |
1136f72d PR |
768 | } |
769 | ||
770 | #undef major | |
771 | #undef minor | |
772 | ||
773 | int | |
774 | findlib(p) | |
775 | struct file_entry *p; | |
776 | { | |
777 | int desc; | |
778 | int i; | |
779 | int len; | |
780 | int major = -1, minor = -1; | |
781 | char *cp, *fname = NULL; | |
782 | ||
6a61ea88 | 783 | if (!(p->flags & E_SEARCH_DYNAMIC)) |
1136f72d PR |
784 | goto dot_a; |
785 | ||
0f052032 | 786 | fname = findshlib(p->filename, &major, &minor, 1); |
1136f72d PR |
787 | |
788 | if (fname && (desc = open (fname, O_RDONLY, 0)) > 0) { | |
789 | p->filename = fname; | |
790 | p->lib_major = major; | |
791 | p->lib_minor = minor; | |
6a61ea88 | 792 | p->flags &= ~E_SEARCH_DIRS; |
1136f72d PR |
793 | return desc; |
794 | } | |
795 | free (fname); | |
796 | ||
797 | dot_a: | |
6a61ea88 | 798 | p->flags &= ~E_SEARCH_DYNAMIC; |
1136f72d PR |
799 | if (cp = strrchr(p->filename, '/')) { |
800 | *cp++ = '\0'; | |
801 | fname = concat(concat(p->filename, "/lib", cp), ".a", ""); | |
802 | *(--cp) = '/'; | |
803 | } else | |
804 | fname = concat("lib", p->filename, ".a"); | |
805 | ||
806 | for (i = 0; i < n_search_dirs; i++) { | |
807 | register char *string | |
808 | = concat (search_dirs[i], "/", fname); | |
809 | desc = open (string, O_RDONLY, 0); | |
810 | if (desc > 0) { | |
811 | p->filename = string; | |
6a61ea88 | 812 | p->flags &= ~E_SEARCH_DIRS; |
1136f72d PR |
813 | break; |
814 | } | |
815 | free (string); | |
816 | } | |
817 | return desc; | |
818 | } | |
819 |