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