Commit | Line | Data |
---|---|---|
fb459a62 NW |
1 | /*- |
2 | * This code is derived from software copyrighted by the Free Software | |
3 | * Foundation. | |
4 | * | |
5 | * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. | |
1136f72d PR |
6 | * |
7 | * Modified 1993 by Paul Kranenburg, Erasmus University | |
fb459a62 NW |
8 | */ |
9 | ||
10 | #ifndef lint | |
11 | static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91"; | |
12 | #endif /* not lint */ | |
13 | ||
14 | /* Linker `ld' for GNU | |
15 | Copyright (C) 1988 Free Software Foundation, Inc. | |
16 | ||
17 | This program is free software; you can redistribute it and/or modify | |
18 | it under the terms of the GNU General Public License as published by | |
19 | the Free Software Foundation; either version 1, or (at your option) | |
20 | any later version. | |
21 | ||
22 | This program is distributed in the hope that it will be useful, | |
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | GNU General Public License for more details. | |
26 | ||
27 | You should have received a copy of the GNU General Public License | |
28 | along with this program; if not, write to the Free Software | |
29 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
30 | ||
31 | /* Written by Richard Stallman with some help from Eric Albert. | |
7fc7155d | 32 | Set, indirect, and warning symbol features added by Randy Smith. */ |
1136f72d PR |
33 | |
34 | /* | |
27b6ced7 | 35 | * $Id: ld.c,v 1.10 1993/11/22 19:04:40 jkh Exp $ |
1136f72d | 36 | */ |
fb459a62 NW |
37 | |
38 | /* Define how to initialize system-dependent header fields. */ | |
39 | ||
1136f72d | 40 | #include <sys/param.h> |
fb459a62 | 41 | #include <stdio.h> |
1136f72d | 42 | #include <stdlib.h> |
fb459a62 NW |
43 | #include <sys/types.h> |
44 | #include <sys/stat.h> | |
45 | #include <sys/file.h> | |
46 | #include <sys/time.h> | |
47 | #include <sys/resource.h> | |
48 | #include <fcntl.h> | |
1136f72d PR |
49 | #include <ar.h> |
50 | #include <ranlib.h> | |
fb459a62 NW |
51 | #include <a.out.h> |
52 | #include <stab.h> | |
53 | #include <string.h> | |
1136f72d | 54 | #include <strings.h> |
fb459a62 | 55 | |
1136f72d | 56 | #include "ld.h" |
fb459a62 | 57 | |
1136f72d | 58 | int building_shared_object; |
fb459a62 | 59 | |
1136f72d PR |
60 | /* 1 => write relocation into output file so can re-input it later. */ |
61 | int relocatable_output; | |
fb459a62 | 62 | |
1136f72d PR |
63 | /* Non zero means to create the output executable. */ |
64 | /* Cleared by nonfatal errors. */ | |
65 | int make_executable; | |
fb459a62 | 66 | |
1136f72d PR |
67 | /* Force the executable to be output, even if there are non-fatal errors */ |
68 | int force_executable; | |
fb459a62 | 69 | |
1136f72d PR |
70 | /* 1 => assign space to common symbols even if `relocatable_output'. */ |
71 | int force_common_definition; | |
72 | ||
73 | /* 1 => assign jmp slots to text symbols in shared objects even if non-PIC */ | |
74 | int force_alias_definition; | |
fb459a62 | 75 | |
27b6ced7 JH |
76 | /* 1 => some files contain PIC code, affects relocation bits |
77 | if `relocatable_output'. */ | |
78 | int pic_code_seen; | |
79 | ||
1136f72d PR |
80 | /* |
81 | * Which symbols should be stripped (omitted from the output): none, all, or | |
82 | * debugger symbols. | |
83 | */ | |
84 | enum { | |
85 | STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER | |
86 | } strip_symbols; | |
fb459a62 | 87 | |
1136f72d PR |
88 | /* |
89 | * Which local symbols should be omitted: none, all, or those starting with L. | |
90 | * This is irrelevant if STRIP_NONE. | |
91 | */ | |
92 | enum { | |
93 | DISCARD_NONE, DISCARD_ALL, DISCARD_L | |
94 | } discard_locals; | |
fb459a62 | 95 | |
1136f72d PR |
96 | /* Nonzero means print names of input files as processed. */ |
97 | int trace_files; | |
fb459a62 | 98 | |
1136f72d PR |
99 | /* Magic number to use for the output file, set by switch. */ |
100 | int magic; | |
fb459a62 | 101 | |
fb459a62 | 102 | /* |
1136f72d PR |
103 | * `text-start' address is normally this much plus a page boundary. |
104 | * This is not a user option; it is fixed for each system. | |
fb459a62 | 105 | */ |
1136f72d | 106 | int text_start_alignment; |
fb459a62 | 107 | |
1136f72d PR |
108 | /* |
109 | * Nonzero if -T was specified in the command line. | |
110 | * This prevents text_start from being set later to default values. | |
111 | */ | |
112 | int T_flag_specified; | |
113 | ||
114 | /* | |
115 | * Nonzero if -Tdata was specified in the command line. | |
116 | * This prevents data_start from being set later to default values. | |
117 | */ | |
118 | int Tdata_flag_specified; | |
fb459a62 | 119 | |
1136f72d PR |
120 | /* |
121 | * Size to pad data section up to. | |
122 | * We simply increase the size of the data section, padding with zeros, | |
123 | * and reduce the size of the bss section to match. | |
124 | */ | |
125 | int specified_data_size; | |
fb459a62 | 126 | |
1136f72d PR |
127 | long *set_vectors; |
128 | int setv_fill_count; | |
fb459a62 | 129 | |
1136f72d PR |
130 | int |
131 | main(argc, argv) | |
132 | char **argv; | |
133 | int argc; | |
134 | { | |
fb459a62 | 135 | |
1136f72d PR |
136 | if ((progname = strrchr(argv[0], '/')) == NULL) |
137 | progname = argv[0]; | |
138 | else | |
139 | progname++; | |
fb459a62 | 140 | |
1136f72d PR |
141 | /* Added this to stop ld core-dumping on very large .o files. */ |
142 | #ifdef RLIMIT_STACK | |
143 | /* Get rid of any avoidable limit on stack size. */ | |
144 | { | |
145 | struct rlimit rlim; | |
fb459a62 | 146 | |
1136f72d PR |
147 | /* Set the stack limit huge so that alloca does not fail. */ |
148 | getrlimit(RLIMIT_STACK, &rlim); | |
149 | rlim.rlim_cur = rlim.rlim_max; | |
150 | setrlimit(RLIMIT_STACK, &rlim); | |
151 | } | |
152 | #endif /* RLIMIT_STACK */ | |
153 | ||
154 | page_size = PAGSIZ; | |
155 | ||
156 | /* Clear the cumulative info on the output file. */ | |
157 | ||
158 | text_size = 0; | |
159 | data_size = 0; | |
160 | bss_size = 0; | |
161 | text_reloc_size = 0; | |
162 | data_reloc_size = 0; | |
fb459a62 | 163 | |
1136f72d PR |
164 | data_pad = 0; |
165 | text_pad = 0; | |
fb459a62 | 166 | |
1136f72d | 167 | /* Initialize the data about options. */ |
fb459a62 | 168 | |
1136f72d PR |
169 | specified_data_size = 0; |
170 | strip_symbols = STRIP_NONE; | |
171 | trace_files = 0; | |
172 | discard_locals = DISCARD_NONE; | |
173 | entry_symbol = 0; | |
174 | write_map = 0; | |
175 | relocatable_output = 0; | |
176 | force_common_definition = 0; | |
177 | T_flag_specified = 0; | |
178 | Tdata_flag_specified = 0; | |
179 | magic = DEFAULT_MAGIC; | |
180 | make_executable = 1; | |
181 | force_executable = 0; | |
182 | link_mode = DYNAMIC; | |
27b6ced7 JH |
183 | #ifdef SUNOS4 |
184 | link_mode |= SILLYARCHIVE; | |
185 | #endif | |
1136f72d | 186 | soversion = LD_VERSION_BSD; |
fb459a62 | 187 | |
1136f72d | 188 | /* Initialize the cumulative counts of symbols. */ |
fb459a62 | 189 | |
1136f72d PR |
190 | local_sym_count = 0; |
191 | non_L_local_sym_count = 0; | |
192 | debugger_sym_count = 0; | |
193 | undefined_global_sym_count = 0; | |
194 | warning_count = 0; | |
195 | multiple_def_count = 0; | |
196 | common_defined_global_count = 0; | |
fb459a62 | 197 | |
1136f72d PR |
198 | /* Keep a list of symbols referenced from the command line */ |
199 | cl_refs_allocated = 10; | |
200 | cmdline_references | |
201 | = (struct glosym **) xmalloc(cl_refs_allocated | |
202 | * sizeof(struct glosym *)); | |
203 | *cmdline_references = 0; | |
fb459a62 | 204 | |
1136f72d PR |
205 | /* Completely decode ARGV. */ |
206 | decode_command(argc, argv); | |
fb459a62 | 207 | |
1136f72d PR |
208 | building_shared_object = |
209 | (!relocatable_output && (link_mode & SHAREABLE)); | |
fb459a62 | 210 | |
27b6ced7 JH |
211 | if (building_shared_object && entry_symbol) { |
212 | fatal("`-Bshareable' and `-e' options are mutually exclusive"); | |
213 | } | |
214 | ||
1136f72d PR |
215 | /* Create the symbols `etext', `edata' and `end'. */ |
216 | symtab_init(relocatable_output); | |
fb459a62 | 217 | |
1136f72d PR |
218 | /* Prepare for the run-time linking support. */ |
219 | init_rrs(); | |
fb459a62 | 220 | |
1136f72d PR |
221 | /* |
222 | * Determine whether to count the header as part of the text size, | |
223 | * and initialize the text size accordingly. This depends on the kind | |
224 | * of system and on the output format selected. | |
225 | */ | |
fb459a62 | 226 | |
1136f72d | 227 | md_init_header(&outheader, magic, 0); |
fb459a62 | 228 | |
1136f72d PR |
229 | text_size = sizeof(struct exec); |
230 | text_size -= N_TXTOFF(outheader); | |
fb459a62 | 231 | |
1136f72d PR |
232 | if (text_size < 0) |
233 | text_size = 0; | |
234 | entry_offset = text_size; | |
fb459a62 | 235 | |
1136f72d PR |
236 | if (!T_flag_specified && !relocatable_output) |
237 | text_start = TEXT_START(outheader); | |
fb459a62 | 238 | |
1136f72d PR |
239 | /* The text-start address is normally this far past a page boundary. */ |
240 | text_start_alignment = text_start % page_size; | |
fb459a62 | 241 | |
1136f72d PR |
242 | /* |
243 | * Load symbols of all input files. Also search all libraries and | |
244 | * decide which library members to load. | |
245 | */ | |
246 | load_symbols(); | |
fb459a62 | 247 | |
1136f72d PR |
248 | /* Compute where each file's sections go, and relocate symbols. */ |
249 | digest_symbols(); | |
fb459a62 | 250 | |
1136f72d PR |
251 | /* |
252 | * Print error messages for any missing symbols, for any warning | |
253 | * symbols, and possibly multiple definitions | |
254 | */ | |
255 | make_executable = do_warnings(stderr); | |
fb459a62 | 256 | |
1136f72d PR |
257 | /* Print a map, if requested. */ |
258 | if (write_map) | |
259 | print_symbols(stdout); | |
fb459a62 | 260 | |
1136f72d PR |
261 | /* Write the output file. */ |
262 | if (make_executable || force_executable) | |
263 | write_output(); | |
fb459a62 | 264 | |
1136f72d PR |
265 | exit(!make_executable); |
266 | } | |
fb459a62 | 267 | |
1136f72d | 268 | void decode_option(); |
fb459a62 | 269 | |
1136f72d PR |
270 | /* |
271 | * Analyze a command line argument. Return 0 if the argument is a filename. | |
272 | * Return 1 if the argument is a option complete in itself. Return 2 if the | |
273 | * argument is a option which uses an argument. | |
274 | * | |
275 | * Thus, the value is the number of consecutive arguments that are part of | |
276 | * options. | |
277 | */ | |
fb459a62 | 278 | |
1136f72d PR |
279 | int |
280 | classify_arg(arg) | |
281 | register char *arg; | |
282 | { | |
283 | if (*arg != '-') | |
284 | return 0; | |
285 | switch (arg[1]) { | |
286 | case 'a': | |
287 | if (!strcmp(&arg[2], "ssert")) | |
288 | return 2; | |
289 | case 'A': | |
290 | case 'D': | |
291 | case 'e': | |
292 | case 'L': | |
293 | case 'l': | |
294 | case 'o': | |
295 | case 'u': | |
296 | case 'V': | |
297 | case 'y': | |
298 | if (arg[2]) | |
299 | return 1; | |
300 | return 2; | |
301 | ||
302 | case 'B': | |
303 | if (!strcmp(&arg[2], "static")) | |
304 | return 1; | |
305 | if (!strcmp(&arg[2], "dynamic")) | |
306 | return 1; | |
307 | ||
308 | case 'T': | |
309 | if (arg[2] == 0) | |
310 | return 2; | |
311 | if (!strcmp(&arg[2], "text")) | |
312 | return 2; | |
313 | if (!strcmp(&arg[2], "data")) | |
314 | return 2; | |
315 | return 1; | |
316 | } | |
fb459a62 | 317 | |
1136f72d PR |
318 | return 1; |
319 | } | |
fb459a62 | 320 | |
1136f72d PR |
321 | /* |
322 | * Process the command arguments, setting up file_table with an entry for | |
323 | * each input file, and setting variables according to the options. | |
324 | */ | |
fb459a62 | 325 | |
1136f72d PR |
326 | void |
327 | decode_command(argc, argv) | |
328 | char **argv; | |
329 | int argc; | |
330 | { | |
331 | register int i; | |
332 | register struct file_entry *p; | |
333 | char *cp; | |
fb459a62 | 334 | |
1136f72d PR |
335 | number_of_files = 0; |
336 | output_filename = "a.out"; | |
fb459a62 | 337 | |
1136f72d PR |
338 | /* |
339 | * First compute number_of_files so we know how long to make | |
340 | * file_table. | |
341 | * Also process most options completely. | |
342 | */ | |
fb459a62 | 343 | |
1136f72d PR |
344 | for (i = 1; i < argc; i++) { |
345 | register int code = classify_arg(argv[i]); | |
346 | if (code) { | |
347 | if (i + code > argc) | |
348 | fatal("no argument following %s\n", argv[i]); | |
fb459a62 | 349 | |
1136f72d | 350 | decode_option(argv[i], argv[i + 1]); |
fb459a62 | 351 | |
1136f72d PR |
352 | if (argv[i][1] == 'l' || argv[i][1] == 'A') |
353 | number_of_files++; | |
fb459a62 | 354 | |
1136f72d PR |
355 | i += code - 1; |
356 | } else | |
357 | number_of_files++; | |
358 | } | |
fb459a62 | 359 | |
1136f72d PR |
360 | if (!number_of_files) |
361 | fatal("no input files"); | |
fb459a62 | 362 | |
1136f72d PR |
363 | p = file_table = (struct file_entry *) |
364 | xmalloc(number_of_files * sizeof(struct file_entry)); | |
365 | bzero(p, number_of_files * sizeof(struct file_entry)); | |
fb459a62 | 366 | |
1136f72d PR |
367 | /* Now scan again and fill in file_table. */ |
368 | /* All options except -A and -l are ignored here. */ | |
fb459a62 | 369 | |
1136f72d PR |
370 | for (i = 1; i < argc; i++) { |
371 | char *string; | |
372 | register int code = classify_arg(argv[i]); | |
fb459a62 | 373 | |
1136f72d PR |
374 | if (code == 0) { |
375 | p->filename = argv[i]; | |
376 | p->local_sym_name = argv[i]; | |
377 | p++; | |
378 | continue; | |
379 | } | |
380 | if (code == 2) | |
381 | string = argv[i + 1]; | |
382 | else | |
383 | string = &argv[i][2]; | |
384 | ||
385 | if (argv[i][1] == 'B') { | |
386 | if (strcmp(string, "static") == 0) | |
387 | link_mode &= ~DYNAMIC; | |
388 | else if (strcmp(string, "dynamic") == 0) | |
389 | link_mode |= DYNAMIC; | |
390 | else if (strcmp(string, "symbolic") == 0) | |
391 | link_mode |= SYMBOLIC; | |
392 | else if (strcmp(string, "forcearchive") == 0) | |
393 | link_mode |= FORCEARCHIVE; | |
394 | else if (strcmp(string, "shareable") == 0) | |
395 | link_mode |= SHAREABLE; | |
27b6ced7 JH |
396 | #ifdef SUN_COMPAT |
397 | else if (strcmp(string, "silly") == 0) | |
398 | link_mode |= SILLYARCHIVE; | |
399 | else if (strcmp(string, "~silly") == 0) | |
400 | link_mode &= ~SILLYARCHIVE; | |
401 | #endif | |
1136f72d PR |
402 | } |
403 | if (argv[i][1] == 'A') { | |
404 | if (p != file_table) | |
405 | fatal("-A specified before an input file other than the first"); | |
406 | p->filename = string; | |
407 | p->local_sym_name = string; | |
408 | p->just_syms_flag = 1; | |
409 | p++; | |
410 | } | |
411 | if (argv[i][1] == 'l') { | |
412 | p->filename = string; | |
413 | p->local_sym_name = concat("-l", string, ""); | |
414 | p->search_dirs_flag = 1; | |
415 | if (link_mode & DYNAMIC && !relocatable_output) | |
416 | p->search_dynamic_flag = 1; | |
417 | p++; | |
418 | } | |
419 | i += code - 1; | |
420 | } | |
fb459a62 | 421 | |
1136f72d | 422 | /* Now check some option settings for consistency. */ |
fb459a62 | 423 | |
1136f72d PR |
424 | if ((magic != OMAGIC) |
425 | && (text_start - text_start_alignment) & (page_size - 1)) | |
426 | fatal("-T argument not multiple of page size, with sharable output"); | |
fb459a62 | 427 | |
1136f72d PR |
428 | /* Append the standard search directories to the user-specified ones. */ |
429 | std_search_dirs(getenv("LD_LIBRARY_PATH")); | |
430 | } | |
fb459a62 | 431 | |
1136f72d PR |
432 | void |
433 | add_cmdline_ref(sp) | |
434 | struct glosym *sp; | |
fb459a62 | 435 | { |
1136f72d | 436 | struct glosym **ptr; |
fb459a62 | 437 | |
1136f72d PR |
438 | for (ptr = cmdline_references; |
439 | ptr < cmdline_references + cl_refs_allocated && *ptr; | |
440 | ptr++); | |
fb459a62 | 441 | |
1136f72d PR |
442 | if (ptr >= cmdline_references + cl_refs_allocated - 1) { |
443 | int diff = ptr - cmdline_references; | |
fb459a62 | 444 | |
1136f72d PR |
445 | cl_refs_allocated *= 2; |
446 | cmdline_references = (struct glosym **) | |
447 | xrealloc(cmdline_references, | |
448 | cl_refs_allocated * sizeof(struct glosym *)); | |
449 | ptr = cmdline_references + diff; | |
450 | } | |
451 | *ptr++ = sp; | |
452 | *ptr = (struct glosym *) 0; | |
fb459a62 | 453 | } |
fb459a62 NW |
454 | |
455 | int | |
1136f72d PR |
456 | set_element_prefixed_p(name) |
457 | char *name; | |
fb459a62 | 458 | { |
1136f72d PR |
459 | struct string_list_element *p; |
460 | int i; | |
fb459a62 | 461 | |
1136f72d | 462 | for (p = set_element_prefixes; p; p = p->next) { |
fb459a62 | 463 | |
1136f72d PR |
464 | for (i = 0; p->str[i] != '\0' && (p->str[i] == name[i]); i++); |
465 | if (p->str[i] == '\0') | |
466 | return 1; | |
467 | } | |
468 | return 0; | |
fb459a62 NW |
469 | } |
470 | ||
1136f72d PR |
471 | /* |
472 | * Record an option and arrange to act on it later. ARG should be the | |
473 | * following command argument, which may or may not be used by this option. | |
474 | * | |
475 | * The `l' and `A' options are ignored here since they actually specify input | |
476 | * files. | |
477 | */ | |
fb459a62 NW |
478 | |
479 | void | |
1136f72d PR |
480 | decode_option(swt, arg) |
481 | register char *swt, *arg; | |
482 | { | |
483 | /* We get Bstatic from gcc on suns. */ | |
484 | if (!strcmp(swt + 1, "Bstatic")) | |
485 | return; | |
486 | if (!strcmp(swt + 1, "Bdynamic")) | |
487 | return; | |
488 | if (!strcmp(swt + 1, "Bsymbolic")) | |
489 | return; | |
490 | if (!strcmp(swt + 1, "Bforcearchive")) | |
491 | return; | |
492 | if (!strcmp(swt + 1, "Bshareable")) | |
493 | return; | |
494 | if (!strcmp(swt + 1, "assert")) | |
495 | return; | |
27b6ced7 JH |
496 | #ifdef SUN_COMPAT |
497 | if (!strcmp(swt + 1, "Bsilly")) | |
498 | return; | |
499 | #endif | |
1136f72d PR |
500 | if (!strcmp(swt + 1, "Ttext")) { |
501 | text_start = parse(arg, "%x", "invalid argument to -Ttext"); | |
502 | T_flag_specified = 1; | |
503 | return; | |
fb459a62 | 504 | } |
1136f72d PR |
505 | if (!strcmp(swt + 1, "Tdata")) { |
506 | rrs_data_start = parse(arg, "%x", "invalid argument to -Tdata"); | |
507 | Tdata_flag_specified = 1; | |
508 | return; | |
509 | } | |
510 | if (!strcmp(swt + 1, "noinhibit-exec")) { | |
511 | force_executable = 1; | |
512 | return; | |
513 | } | |
514 | if (swt[2] != 0) | |
515 | arg = &swt[2]; | |
516 | ||
517 | switch (swt[1]) { | |
518 | case 'A': | |
519 | return; | |
520 | ||
521 | case 'D': | |
522 | specified_data_size = parse(arg, "%x", "invalid argument to -D"); | |
523 | return; | |
524 | ||
525 | case 'd': | |
526 | if (*arg == 'c') | |
527 | force_common_definition = 1; | |
528 | else if (*arg == 'p') | |
529 | force_alias_definition = 1; | |
530 | else | |
531 | fatal("-d option takes 'c' or 'p' argument"); | |
532 | return; | |
fb459a62 | 533 | |
1136f72d PR |
534 | case 'e': |
535 | entry_symbol = getsym(arg); | |
536 | if (!entry_symbol->defined && !entry_symbol->referenced) | |
537 | undefined_global_sym_count++; | |
538 | entry_symbol->referenced = 1; | |
539 | add_cmdline_ref(entry_symbol); | |
540 | return; | |
fb459a62 | 541 | |
1136f72d PR |
542 | case 'l': |
543 | return; | |
fb459a62 | 544 | |
1136f72d PR |
545 | case 'L': |
546 | add_search_dir(arg); | |
547 | return; | |
fb459a62 | 548 | |
1136f72d PR |
549 | case 'M': |
550 | write_map = 1; | |
551 | return; | |
fb459a62 | 552 | |
1136f72d PR |
553 | case 'N': |
554 | magic = OMAGIC; | |
555 | return; | |
fb459a62 NW |
556 | |
557 | #ifdef NMAGIC | |
1136f72d PR |
558 | case 'n': |
559 | magic = NMAGIC; | |
560 | return; | |
fb459a62 | 561 | #endif |
fb459a62 | 562 | |
1136f72d PR |
563 | #ifdef QMAGIC |
564 | case 'Q': | |
565 | magic = oldmagic = QMAGIC; | |
566 | return; | |
d97e3ca8 | 567 | #endif |
1136f72d | 568 | case 'Z': |
d97e3ca8 PR |
569 | magic = ZMAGIC; |
570 | oldmagic = 0; | |
1136f72d | 571 | return; |
fb459a62 | 572 | |
1136f72d PR |
573 | case 'o': |
574 | output_filename = arg; | |
575 | return; | |
fb459a62 | 576 | |
1136f72d PR |
577 | case 'r': |
578 | relocatable_output = 1; | |
579 | magic = OMAGIC; | |
580 | text_start = 0; | |
581 | return; | |
fb459a62 | 582 | |
1136f72d PR |
583 | case 'S': |
584 | strip_symbols = STRIP_DEBUGGER; | |
585 | return; | |
fb459a62 | 586 | |
1136f72d PR |
587 | case 's': |
588 | strip_symbols = STRIP_ALL; | |
589 | return; | |
fb459a62 | 590 | |
1136f72d PR |
591 | case 'T': |
592 | text_start = parse(arg, "%x", "invalid argument to -T"); | |
593 | T_flag_specified = 1; | |
594 | return; | |
fb459a62 | 595 | |
1136f72d PR |
596 | case 't': |
597 | trace_files = 1; | |
598 | return; | |
fb459a62 | 599 | |
1136f72d PR |
600 | case 'u': |
601 | { | |
602 | register symbol *sp = getsym(arg); | |
fb459a62 | 603 | |
1136f72d PR |
604 | if (!sp->defined && !sp->referenced) |
605 | undefined_global_sym_count++; | |
606 | sp->referenced = 1; | |
607 | add_cmdline_ref(sp); | |
608 | } | |
609 | return; | |
610 | ||
611 | #if 1 | |
612 | case 'V': | |
613 | soversion = parse(arg, "%d", "invalid argument to -V"); | |
614 | return; | |
fb459a62 NW |
615 | #endif |
616 | ||
1136f72d PR |
617 | case 'X': |
618 | discard_locals = DISCARD_L; | |
619 | return; | |
fb459a62 | 620 | |
1136f72d PR |
621 | case 'x': |
622 | discard_locals = DISCARD_ALL; | |
623 | return; | |
c53138ba | 624 | |
1136f72d PR |
625 | case 'y': |
626 | { | |
627 | register symbol *sp = getsym(&swt[2]); | |
628 | sp->trace = 1; | |
629 | } | |
630 | return; | |
631 | ||
632 | case 'z': | |
d97e3ca8 | 633 | oldmagic = magic = ZMAGIC; |
1136f72d PR |
634 | return; |
635 | ||
636 | default: | |
637 | fatal("invalid command option `%s'", swt); | |
638 | } | |
fb459a62 NW |
639 | } |
640 | \f | |
1136f72d | 641 | /* Convenient functions for operating on one or all files being loaded. */ |
fb459a62 | 642 | |
1136f72d PR |
643 | /* |
644 | * Call FUNCTION on each input file entry. Do not call for entries for | |
645 | * libraries; instead, call once for each library member that is being | |
646 | * loaded. | |
647 | * | |
648 | * FUNCTION receives two arguments: the entry, and ARG. | |
649 | */ | |
fb459a62 NW |
650 | |
651 | void | |
1136f72d PR |
652 | each_file(function, arg) |
653 | register void (*function) (); | |
654 | register int arg; | |
655 | { | |
656 | register int i; | |
657 | ||
658 | for (i = 0; i < number_of_files; i++) { | |
659 | register struct file_entry *entry = &file_table[i]; | |
27b6ced7 JH |
660 | register struct file_entry *subentry; |
661 | ||
80f25b52 JH |
662 | if (entry->scrapped) |
663 | continue; | |
27b6ced7 JH |
664 | |
665 | if (!entry->library_flag) | |
666 | (*function) (entry, arg); | |
667 | ||
668 | subentry = entry->subfiles; | |
669 | for (; subentry; subentry = subentry->chain) { | |
670 | if (subentry->scrapped) | |
671 | continue; | |
672 | (*function) (subentry, arg); | |
673 | } | |
674 | ||
675 | #ifdef SUN_COMPAT | |
676 | if (entry->silly_archive) { | |
677 | ||
678 | if (!entry->is_dynamic) | |
679 | error("Silly"); | |
680 | ||
681 | if (!entry->silly_archive->library_flag) | |
682 | error("Sillier"); | |
683 | ||
684 | subentry = entry->silly_archive->subfiles; | |
80f25b52 JH |
685 | for (; subentry; subentry = subentry->chain) { |
686 | if (subentry->scrapped) | |
687 | continue; | |
1136f72d | 688 | (*function) (subentry, arg); |
80f25b52 | 689 | } |
27b6ced7 JH |
690 | } |
691 | #endif | |
fb459a62 | 692 | } |
fb459a62 NW |
693 | } |
694 | ||
1136f72d PR |
695 | /* |
696 | * Call FUNCTION on each input file entry until it returns a non-zero value. | |
697 | * Return this value. Do not call for entries for libraries; instead, call | |
698 | * once for each library member that is being loaded. | |
699 | * | |
700 | * FUNCTION receives two arguments: the entry, and ARG. It must be a function | |
701 | * returning unsigned long (though this can probably be fudged). | |
702 | */ | |
fb459a62 NW |
703 | |
704 | unsigned long | |
1136f72d PR |
705 | check_each_file(function, arg) |
706 | register unsigned long (*function) (); | |
707 | register int arg; | |
708 | { | |
709 | register int i; | |
710 | register unsigned long return_val; | |
711 | ||
712 | for (i = 0; i < number_of_files; i++) { | |
713 | register struct file_entry *entry = &file_table[i]; | |
80f25b52 JH |
714 | if (entry->scrapped) |
715 | continue; | |
1136f72d PR |
716 | if (entry->library_flag) { |
717 | register struct file_entry *subentry = entry->subfiles; | |
80f25b52 JH |
718 | for (; subentry; subentry = subentry->chain) { |
719 | if (subentry->scrapped) | |
720 | continue; | |
1136f72d PR |
721 | if (return_val = (*function) (subentry, arg)) |
722 | return return_val; | |
80f25b52 | 723 | } |
1136f72d PR |
724 | } else if (return_val = (*function) (entry, arg)) |
725 | return return_val; | |
fb459a62 | 726 | } |
1136f72d | 727 | return 0; |
fb459a62 NW |
728 | } |
729 | ||
730 | /* Like `each_file' but ignore files that were just for symbol definitions. */ | |
731 | ||
732 | void | |
1136f72d PR |
733 | each_full_file(function, arg) |
734 | register void (*function) (); | |
735 | register int arg; | |
736 | { | |
737 | register int i; | |
738 | ||
739 | for (i = 0; i < number_of_files; i++) { | |
740 | register struct file_entry *entry = &file_table[i]; | |
27b6ced7 JH |
741 | register struct file_entry *subentry; |
742 | ||
743 | if (entry->scrapped || entry->just_syms_flag) | |
1136f72d | 744 | continue; |
27b6ced7 JH |
745 | |
746 | #ifdef SUN_COMPAT | |
747 | if (entry->silly_archive) { | |
748 | ||
749 | if (!entry->is_dynamic) | |
750 | error("Silly"); | |
751 | ||
752 | if (!entry->silly_archive->library_flag) | |
753 | error("Sillier"); | |
754 | ||
755 | subentry = entry->silly_archive->subfiles; | |
756 | for (; subentry; subentry = subentry->chain) { | |
757 | if (subentry->scrapped) | |
758 | continue; | |
1136f72d | 759 | (*function) (subentry, arg); |
27b6ced7 JH |
760 | } |
761 | } | |
762 | #endif | |
763 | if (entry->is_dynamic) | |
764 | continue; | |
765 | ||
766 | if (!entry->library_flag) | |
1136f72d | 767 | (*function) (entry, arg); |
27b6ced7 JH |
768 | |
769 | subentry = entry->subfiles; | |
770 | for (; subentry; subentry = subentry->chain) { | |
771 | if (subentry->scrapped) | |
772 | continue; | |
773 | (*function) (subentry, arg); | |
774 | } | |
775 | ||
fb459a62 | 776 | } |
fb459a62 NW |
777 | } |
778 | ||
779 | /* Close the input file that is now open. */ | |
780 | ||
781 | void | |
1136f72d | 782 | file_close() |
fb459a62 | 783 | { |
1136f72d PR |
784 | close(input_desc); |
785 | input_desc = 0; | |
786 | input_file = 0; | |
fb459a62 NW |
787 | } |
788 | ||
1136f72d PR |
789 | /* |
790 | * Open the input file specified by 'entry', and return a descriptor. The | |
791 | * open file is remembered; if the same file is opened twice in a row, a new | |
792 | * open is not actually done. | |
793 | */ | |
fb459a62 NW |
794 | int |
795 | file_open (entry) | |
796 | register struct file_entry *entry; | |
797 | { | |
1136f72d | 798 | register int desc; |
fb459a62 | 799 | |
27b6ced7 | 800 | if (entry->superfile && entry->superfile->library_flag) |
1136f72d | 801 | return file_open (entry->superfile); |
fb459a62 | 802 | |
1136f72d PR |
803 | if (entry == input_file) |
804 | return input_desc; | |
fb459a62 | 805 | |
1136f72d | 806 | if (input_file) file_close (); |
fb459a62 | 807 | |
1136f72d PR |
808 | if (entry->search_dirs_flag) { |
809 | desc = findlib(entry); | |
810 | } else | |
811 | desc = open (entry->filename, O_RDONLY, 0); | |
fb459a62 | 812 | |
1136f72d PR |
813 | if (desc > 0) { |
814 | input_file = entry; | |
815 | input_desc = desc; | |
816 | return desc; | |
fb459a62 | 817 | } |
fb459a62 | 818 | |
1136f72d PR |
819 | perror_file (entry); |
820 | /* NOTREACHED */ | |
fb459a62 NW |
821 | } |
822 | ||
1136f72d PR |
823 | int |
824 | text_offset (entry) | |
fb459a62 NW |
825 | struct file_entry *entry; |
826 | { | |
1136f72d | 827 | return entry->starting_offset + N_TXTOFF (entry->header); |
fb459a62 NW |
828 | } |
829 | \f | |
830 | /* Medium-level input routines for rel files. */ | |
831 | ||
1136f72d PR |
832 | /* |
833 | * Read a file's header into the proper place in the file_entry. DESC is the | |
834 | * descriptor on which the file is open. ENTRY is the file's entry. | |
835 | */ | |
fb459a62 NW |
836 | void |
837 | read_header (desc, entry) | |
838 | int desc; | |
839 | register struct file_entry *entry; | |
840 | { | |
1136f72d PR |
841 | register int len; |
842 | struct exec *loc = (struct exec *) &entry->header; | |
fb459a62 | 843 | |
1136f72d PR |
844 | if (lseek (desc, entry->starting_offset, L_SET) != |
845 | entry->starting_offset) | |
846 | fatal_with_file("read_header: lseek failure ", entry); | |
fb459a62 | 847 | |
1136f72d PR |
848 | len = read (desc, &entry->header, sizeof (struct exec)); |
849 | if (len != sizeof (struct exec)) | |
850 | fatal_with_file ("failure reading header of ", entry); | |
851 | ||
852 | md_swapin_exec_hdr(&entry->header); | |
fb459a62 | 853 | |
1136f72d PR |
854 | if (N_BADMAG (*loc)) |
855 | fatal_with_file ("bad magic number in ", entry); | |
856 | ||
857 | entry->header_read_flag = 1; | |
858 | } | |
fb459a62 | 859 | |
1136f72d PR |
860 | /* |
861 | * Read the symbols of file ENTRY into core. Assume it is already open, on | |
862 | * descriptor DESC. Also read the length of the string table, which follows | |
863 | * the symbol table, but don't read the contents of the string table. | |
864 | */ | |
fb459a62 NW |
865 | void |
866 | read_entry_symbols (desc, entry) | |
867 | struct file_entry *entry; | |
868 | int desc; | |
869 | { | |
1136f72d PR |
870 | int str_size; |
871 | struct nlist *np; | |
872 | int i; | |
fb459a62 | 873 | |
1136f72d PR |
874 | if (!entry->header_read_flag) |
875 | read_header (desc, entry); | |
fb459a62 | 876 | |
1136f72d PR |
877 | np = (struct nlist *) alloca (entry->header.a_syms); |
878 | entry->nsymbols = entry->header.a_syms / sizeof(struct nlist); | |
879 | entry->symbols = (struct localsymbol *) | |
880 | xmalloc(entry->nsymbols * sizeof(struct localsymbol)); | |
fb459a62 | 881 | |
1136f72d PR |
882 | if (lseek(desc, N_SYMOFF(entry->header) + entry->starting_offset, L_SET) |
883 | != N_SYMOFF(entry->header) + entry->starting_offset) | |
884 | fatal_with_file ("read_symbols(h): lseek failure ", entry); | |
fb459a62 | 885 | |
1136f72d PR |
886 | if (entry->header.a_syms != read (desc, np, entry->header.a_syms)) |
887 | fatal_with_file ("premature end of file in symbols of ", entry); | |
fb459a62 | 888 | |
1136f72d PR |
889 | md_swapin_symbols(np, entry->header.a_syms / sizeof(struct nlist)); |
890 | ||
891 | for (i = 0; i < entry->nsymbols; i++) { | |
892 | entry->symbols[i].nzlist.nlist = *np++; | |
893 | entry->symbols[i].nzlist.nz_size = 0; | |
894 | entry->symbols[i].symbol = NULL; | |
895 | entry->symbols[i].next = NULL; | |
896 | entry->symbols[i].gotslot_offset = -1; | |
897 | entry->symbols[i].gotslot_claimed = 0; | |
27b6ced7 JH |
898 | entry->symbols[i].write = 0; |
899 | entry->symbols[i].is_L_symbol = 0; | |
80f25b52 | 900 | entry->symbols[i].rename = 0; |
1136f72d PR |
901 | } |
902 | ||
903 | entry->strings_offset = N_STROFF(entry->header) + | |
904 | entry->starting_offset; | |
905 | if (lseek(desc, entry->strings_offset, 0) == (off_t)-1) | |
906 | fatal_with_file ("read_symbols(s): lseek failure ", entry); | |
907 | if (sizeof str_size != read (desc, &str_size, sizeof str_size)) | |
908 | fatal_with_file ("bad string table size in ", entry); | |
fb459a62 | 909 | |
1136f72d PR |
910 | entry->string_size = md_swap_long(str_size); |
911 | } | |
fb459a62 | 912 | |
1136f72d PR |
913 | /* |
914 | * Read the string table of file ENTRY into core. Assume it is already open, | |
915 | * on descriptor DESC. | |
916 | */ | |
fb459a62 NW |
917 | void |
918 | read_entry_strings (desc, entry) | |
919 | struct file_entry *entry; | |
920 | int desc; | |
921 | { | |
1136f72d | 922 | int buffer; |
fb459a62 | 923 | |
1136f72d | 924 | if (!entry->header_read_flag || !entry->strings_offset) |
80f25b52 JH |
925 | fatal_with_file("internal error: cannot read string table for ", |
926 | entry); | |
fb459a62 | 927 | |
1136f72d PR |
928 | if (lseek (desc, entry->strings_offset, L_SET) != entry->strings_offset) |
929 | fatal_with_file ("read_strings: lseek failure ", entry); | |
930 | ||
931 | if (entry->string_size != | |
932 | read (desc, entry->strings, entry->string_size)) | |
933 | fatal_with_file ("premature end of file in strings of ", entry); | |
fb459a62 | 934 | |
fb459a62 | 935 | return; |
fb459a62 | 936 | } |
1136f72d PR |
937 | |
938 | /* DEAD - Read in all of the relocation information */ | |
939 | ||
940 | void | |
941 | read_relocation () | |
942 | { | |
943 | each_full_file (read_entry_relocation, 0); | |
944 | } | |
945 | ||
946 | /* Read in the relocation sections of ENTRY if necessary */ | |
947 | ||
948 | void | |
949 | read_entry_relocation (desc, entry) | |
950 | int desc; | |
951 | struct file_entry *entry; | |
952 | { | |
953 | register struct relocation_info *reloc; | |
954 | off_t pos; | |
955 | ||
956 | if (!entry->textrel) { | |
957 | ||
958 | reloc = (struct relocation_info *) | |
959 | xmalloc(entry->header.a_trsize); | |
960 | ||
961 | pos = text_offset(entry) + | |
962 | entry->header.a_text + entry->header.a_data; | |
963 | ||
964 | if (lseek(desc, pos, L_SET) != pos) | |
965 | fatal_with_file("read_reloc(t): lseek failure ", entry); | |
966 | ||
967 | if (entry->header.a_trsize != | |
968 | read(desc, reloc, entry->header.a_trsize)) { | |
969 | fatal_with_file ( | |
970 | "premature eof in text relocation of ", entry); | |
971 | } | |
972 | md_swapin_reloc(reloc, entry->header.a_trsize / sizeof(*reloc)); | |
973 | entry->textrel = reloc; | |
974 | entry->ntextrel = entry->header.a_trsize / sizeof(*reloc); | |
975 | ||
976 | } | |
977 | ||
978 | if (!entry->datarel) { | |
979 | ||
980 | reloc = (struct relocation_info *) | |
981 | xmalloc(entry->header.a_drsize); | |
982 | ||
983 | pos = text_offset(entry) + entry->header.a_text + | |
984 | entry->header.a_data + entry->header.a_trsize; | |
985 | ||
986 | if (lseek(desc, pos, L_SET) != pos) | |
987 | fatal_with_file("read_reloc(d): lseek failure ", entry); | |
988 | ||
989 | if (entry->header.a_drsize != | |
990 | read (desc, reloc, entry->header.a_drsize)) { | |
991 | fatal_with_file ( | |
992 | "premature eof in data relocation of ", entry); | |
993 | } | |
994 | md_swapin_reloc(reloc, entry->header.a_drsize / sizeof(*reloc)); | |
995 | entry->datarel = reloc; | |
996 | entry->ndatarel = entry->header.a_drsize / sizeof(*reloc); | |
997 | ||
998 | } | |
999 | } | |
1000 | ||
fb459a62 NW |
1001 | \f |
1002 | /* Read in the symbols of all input files. */ | |
1003 | ||
80f25b52 | 1004 | void read_file_symbols (), read_entry_symbols (); |
1136f72d | 1005 | void enter_file_symbols (), enter_global_ref (); |
fb459a62 NW |
1006 | |
1007 | void | |
1008 | load_symbols () | |
1009 | { | |
1136f72d | 1010 | register int i; |
fb459a62 | 1011 | |
1136f72d | 1012 | if (trace_files) fprintf (stderr, "Loading symbols:\n\n"); |
fb459a62 | 1013 | |
1136f72d PR |
1014 | for (i = 0; i < number_of_files; i++) { |
1015 | register struct file_entry *entry = &file_table[i]; | |
1016 | read_file_symbols (entry); | |
1017 | } | |
fb459a62 | 1018 | |
1136f72d | 1019 | if (trace_files) fprintf (stderr, "\n"); |
fb459a62 NW |
1020 | } |
1021 | ||
1136f72d PR |
1022 | /* |
1023 | * If ENTRY is a rel file, read its symbol and string sections into core. If | |
1024 | * it is a library, search it and load the appropriate members (which means | |
1025 | * calling this function recursively on those members). | |
1026 | */ | |
fb459a62 NW |
1027 | |
1028 | void | |
1029 | read_file_symbols (entry) | |
1030 | register struct file_entry *entry; | |
1031 | { | |
1136f72d PR |
1032 | register int desc; |
1033 | register int len; | |
1034 | struct exec hdr; | |
1035 | ||
1036 | desc = file_open (entry); | |
1037 | ||
1038 | len = read (desc, &hdr, sizeof hdr); | |
1039 | if (len != sizeof hdr) | |
1040 | fatal_with_file ("failure reading header of ", entry); | |
1041 | ||
1042 | md_swapin_exec_hdr(&hdr); | |
1043 | ||
1044 | if (!N_BADMAG (hdr)) { | |
1045 | if (N_IS_DYNAMIC(hdr)) { | |
1046 | if (relocatable_output) { | |
1047 | fatal_with_file( | |
1048 | "-r and shared objects currently not supported ", | |
1049 | entry); | |
1050 | return; | |
1051 | } | |
1052 | entry->is_dynamic = 1; | |
27b6ced7 | 1053 | if (entry->superfile || rrs_add_shobj(entry)) |
80f25b52 JH |
1054 | read_shared_object(desc, entry); |
1055 | else | |
1056 | entry->scrapped = 1; | |
1136f72d PR |
1057 | } else { |
1058 | read_entry_symbols (desc, entry); | |
1059 | entry->strings = (char *) alloca (entry->string_size); | |
1060 | read_entry_strings (desc, entry); | |
1061 | read_entry_relocation(desc, entry); | |
1062 | enter_file_symbols (entry); | |
1063 | entry->strings = 0; | |
1064 | } | |
1065 | } else { | |
1066 | char armag[SARMAG]; | |
1067 | ||
1068 | lseek (desc, 0, 0); | |
1069 | if (SARMAG != read (desc, armag, SARMAG) || | |
1070 | strncmp (armag, ARMAG, SARMAG)) | |
1071 | fatal_with_file( | |
1072 | "malformed input file (not rel or archive) ", entry); | |
1073 | entry->library_flag = 1; | |
1074 | search_library (desc, entry); | |
1075 | } | |
fb459a62 | 1076 | |
1136f72d | 1077 | file_close (); |
fb459a62 NW |
1078 | } |
1079 | \f | |
1080 | /* Enter the external symbol defs and refs of ENTRY in the hash table. */ | |
1081 | ||
1082 | void | |
1083 | enter_file_symbols (entry) | |
1084 | struct file_entry *entry; | |
1085 | { | |
1136f72d PR |
1086 | struct localsymbol *lsp, *lspend; |
1087 | ||
1088 | if (trace_files) prline_file_name (entry, stderr); | |
1089 | ||
1090 | lspend = entry->symbols + entry->nsymbols; | |
1091 | ||
1092 | for (lsp = entry->symbols; lsp < lspend; lsp++) { | |
1093 | register struct nlist *p = &lsp->nzlist.nlist; | |
1094 | ||
1095 | if (p->n_type == (N_SETV | N_EXT)) | |
1096 | continue; | |
1097 | ||
1098 | /* | |
1099 | * Turn magically prefixed symbols into set symbols of | |
1100 | * a corresponding type. | |
1101 | */ | |
1102 | if (set_element_prefixes && | |
1103 | set_element_prefixed_p(entry->strings+lsp->nzlist.nz_strx)) | |
1104 | lsp->nzlist.nz_type += (N_SETA - N_ABS); | |
1105 | ||
1106 | if (SET_ELEMENT_P(p->n_type)) { | |
1107 | set_symbol_count++; | |
1108 | if (!relocatable_output) | |
1109 | enter_global_ref(lsp, | |
1110 | p->n_un.n_strx + entry->strings, entry); | |
1111 | } else if (p->n_type == N_WARNING) { | |
1112 | char *name = p->n_un.n_strx + entry->strings; | |
1113 | ||
1114 | /* Grab the next entry. */ | |
1115 | p++; | |
1116 | if (p->n_type != (N_UNDF | N_EXT)) { | |
1117 | error("Warning symbol found in %s without external reference following.", | |
1118 | get_file_name(entry)); | |
1119 | make_executable = 0; | |
1120 | p--; /* Process normally. */ | |
1121 | } else { | |
1122 | symbol *sp; | |
1123 | char *sname = p->n_un.n_strx + entry->strings; | |
1124 | /* Deal with the warning symbol. */ | |
1125 | enter_global_ref(lsp, | |
1126 | p->n_un.n_strx + entry->strings, entry); | |
1127 | sp = getsym (sname); | |
1128 | sp->warning = (char *)xmalloc(strlen(name)+1); | |
1129 | strcpy (sp->warning, name); | |
1130 | warning_count++; | |
1131 | } | |
1132 | } else if (p->n_type & N_EXT) { | |
1133 | enter_global_ref(lsp, | |
1134 | p->n_un.n_strx + entry->strings, entry); | |
27b6ced7 JH |
1135 | } else if (p->n_un.n_strx && |
1136 | (p->n_un.n_strx + entry->strings)[0] == LPREFIX) | |
1137 | lsp->is_L_symbol = 1; | |
fb459a62 | 1138 | } |
fb459a62 | 1139 | |
fb459a62 NW |
1140 | } |
1141 | ||
1136f72d PR |
1142 | /* |
1143 | * Enter one global symbol in the hash table. LSP points to the `struct | |
1144 | * localsymbol' from the file that describes the global symbol. NAME is the | |
1145 | * symbol's name. ENTRY is the file entry for the file the symbol comes from. | |
1146 | * | |
1147 | * LSP is put on the chain of all such structs that refer to the same symbol. | |
1148 | * This chain starts in the `refs' for symbols from relocatable objects. A | |
1149 | * backpointer to the global symbol is kept in LSP. | |
1150 | * | |
27b6ced7 | 1151 | * Symbols from shared objects are linked through `soref'. For such symbols |
1136f72d PR |
1152 | * that's all we do at this stage, with the exception of the case where the |
1153 | * symbol is a common. The `referenced' bit is only set for references from | |
1154 | * relocatable objects. | |
1155 | * | |
1156 | */ | |
fb459a62 NW |
1157 | |
1158 | void | |
1136f72d PR |
1159 | enter_global_ref (lsp, name, entry) |
1160 | struct localsymbol *lsp; | |
fb459a62 NW |
1161 | char *name; |
1162 | struct file_entry *entry; | |
1163 | { | |
1136f72d PR |
1164 | register struct nzlist *nzp = &lsp->nzlist; |
1165 | register symbol *sp = getsym (name); | |
1166 | register int type = nzp->nz_type; | |
1167 | int oldref = sp->referenced; | |
1168 | int olddef = sp->defined; | |
1169 | int com = sp->defined && sp->max_common_size; | |
1170 | ||
1171 | if (type == (N_INDR | N_EXT)) { | |
1172 | sp->alias = getsym(entry->strings + (lsp + 1)->nzlist.nz_strx); | |
1173 | if (sp == sp->alias) { | |
1174 | error("%s: %s is alias for itself", | |
1175 | get_file_name(entry), name); | |
1176 | /* Rewrite symbol as global text symbol with value 0 */ | |
1177 | lsp->nzlist.nz_type = N_TEXT|N_EXT; | |
1178 | lsp->nzlist.nz_value = 0; | |
1179 | make_executable = 0; | |
1180 | } else | |
1181 | global_alias_count++; | |
1182 | } | |
fb459a62 | 1183 | |
1136f72d PR |
1184 | if (entry->is_dynamic) { |
1185 | lsp->next = sp->sorefs; | |
1186 | sp->sorefs = lsp; | |
1187 | ||
1188 | /* | |
1189 | * Handle commons from shared objects: | |
1190 | * 1) If symbol hitherto undefined, turn it into a common. | |
1191 | * 2) If symbol already common, update size if necessary. | |
1192 | */ | |
1193 | /*XXX - look at case where commons are only in shared objects */ | |
1194 | if (type == (N_UNDF | N_EXT) && nzp->nz_value) { | |
1195 | if (!olddef) { | |
1196 | if (oldref) | |
1197 | undefined_global_sym_count--; | |
1198 | common_defined_global_count++; | |
1199 | sp->max_common_size = nzp->nz_value; | |
1200 | sp->defined = N_UNDF | N_EXT; | |
1201 | } else if (com && sp->max_common_size < nzp->nz_value) { | |
1202 | sp->max_common_size = nzp->nz_value; | |
1203 | } | |
1204 | } | |
fb459a62 | 1205 | |
1136f72d PR |
1206 | /* |
1207 | * Handle size information in shared objects. | |
1208 | */ | |
1209 | if (nzp->nz_size > sp->size) | |
1210 | sp->size = nzp->nz_size; | |
fb459a62 | 1211 | |
1136f72d PR |
1212 | lsp->symbol = sp; |
1213 | return; | |
fb459a62 | 1214 | } |
fb459a62 | 1215 | |
1136f72d PR |
1216 | lsp->next = sp->refs; |
1217 | sp->refs = lsp; | |
1218 | lsp->symbol = sp; | |
fb459a62 | 1219 | |
1136f72d PR |
1220 | sp->referenced = 1; |
1221 | ||
1222 | if (sp == dynamic_symbol || sp == got_symbol) { | |
1223 | if (type != (N_UNDF | N_EXT) && !entry->just_syms_flag) | |
1224 | fatal("Linker reserved symbol %s defined as type %x ", | |
1225 | name, type); | |
1226 | return; | |
fb459a62 NW |
1227 | } |
1228 | ||
1136f72d PR |
1229 | #ifdef N_SIZE |
1230 | if (type == (N_SIZE | N_EXT)) { | |
27b6ced7 JH |
1231 | if (relocatable_output && nzp->nz_value != 0 && sp->size == 0) |
1232 | size_sym_count++; | |
1136f72d PR |
1233 | if (sp->size < nzp->nz_value) |
1234 | sp->size = nzp->nz_value; | |
1235 | } else | |
1236 | #endif | |
1237 | if (type != (N_UNDF | N_EXT) || nzp->nz_value) { | |
1238 | ||
1239 | /* | |
1240 | * Set `->defined' here, so commons and undefined globals | |
1241 | * can be counted correctly. | |
1242 | */ | |
1243 | if (!sp->defined || sp->defined == (N_UNDF | N_EXT)) | |
1244 | sp->defined = type; | |
1245 | ||
1246 | if (oldref && !olddef) | |
1247 | /* | |
1248 | * It used to be undefined and we're defining it. | |
1249 | */ | |
1250 | undefined_global_sym_count--; | |
1251 | ||
1252 | if (!olddef && type == (N_UNDF | N_EXT) && nzp->nz_value) { | |
1253 | /* | |
1254 | * First definition and it's common. | |
1255 | */ | |
1256 | common_defined_global_count++; | |
1257 | sp->max_common_size = nzp->nz_value; | |
1258 | } else if (com && type != (N_UNDF | N_EXT)) { | |
1259 | /* | |
1260 | * It used to be common and we're defining | |
1261 | * it as something else. | |
1262 | */ | |
1263 | common_defined_global_count--; | |
1264 | sp->max_common_size = 0; | |
1265 | } else if (com && type == (N_UNDF | N_EXT) | |
1266 | && sp->max_common_size < nzp->nz_value) | |
1267 | /* | |
1268 | * It used to be common and this is a new common entry | |
1269 | * to which we need to pay attention. | |
1270 | */ | |
1271 | sp->max_common_size = nzp->nz_value; | |
1272 | ||
1273 | if (SET_ELEMENT_P(type) && (!olddef || com)) | |
1274 | set_vector_count++; | |
1275 | ||
1276 | } else if (!oldref) | |
1277 | undefined_global_sym_count++; | |
1278 | ||
1279 | ||
1280 | if (sp == end_symbol && entry->just_syms_flag && !T_flag_specified) | |
1281 | text_start = nzp->nz_value; | |
1282 | ||
1283 | if (sp->trace) { | |
1284 | register char *reftype; | |
1285 | switch (type & N_TYPE) { | |
1286 | case N_UNDF: | |
1287 | reftype = nzp->nz_value? | |
1288 | "defined as common":"referenced"; | |
1289 | break; | |
1290 | ||
1291 | case N_ABS: | |
1292 | reftype = "defined as absolute"; | |
1293 | break; | |
1294 | ||
1295 | case N_TEXT: | |
1296 | reftype = "defined in text section"; | |
1297 | break; | |
1298 | ||
1299 | case N_DATA: | |
1300 | reftype = "defined in data section"; | |
1301 | break; | |
1302 | ||
1303 | case N_BSS: | |
1304 | reftype = "defined in BSS section"; | |
1305 | break; | |
1306 | ||
1307 | default: | |
1308 | reftype = "I don't know this type"; | |
1309 | break; | |
1310 | } | |
1311 | ||
1312 | fprintf (stderr, "symbol %s %s in ", sp->name, reftype); | |
1313 | print_file_name (entry, stderr); | |
1314 | fprintf (stderr, "\n"); | |
1315 | } | |
fb459a62 NW |
1316 | } |
1317 | ||
1136f72d PR |
1318 | /* |
1319 | * This return 0 if the given file entry's symbol table does *not* contain | |
1320 | * the nlist point entry, and it returns the files entry pointer (cast to | |
1321 | * unsigned long) if it does. | |
1322 | */ | |
fb459a62 NW |
1323 | |
1324 | unsigned long | |
1136f72d | 1325 | contains_symbol (entry, np) |
fb459a62 | 1326 | struct file_entry *entry; |
1136f72d | 1327 | register struct nlist *np; |
fb459a62 | 1328 | { |
1136f72d PR |
1329 | if (np >= &entry->symbols->nzlist.nlist && |
1330 | np < &(entry->symbols + entry->nsymbols)->nzlist.nlist) | |
1331 | return (unsigned long) entry; | |
1332 | return 0; | |
fb459a62 NW |
1333 | } |
1334 | ||
fb459a62 | 1335 | |
1136f72d PR |
1336 | void consider_file_section_lengths (), relocate_file_addresses (); |
1337 | void consider_relocation(); | |
fb459a62 | 1338 | |
1136f72d PR |
1339 | /* |
1340 | * Having entered all the global symbols and found the sizes of sections of | |
1341 | * all files to be linked, make all appropriate deductions from this data. | |
1342 | * | |
1343 | * We propagate global symbol values from definitions to references. We compute | |
1344 | * the layout of the output file and where each input file's contents fit | |
1345 | * into it. | |
1346 | * | |
1347 | * This is now done in several stages. | |
1348 | * | |
1349 | * 1) All global symbols are examined for definitions in relocatable (.o) | |
1350 | * files. The symbols' type is set according to the definition found, | |
1351 | * but its value can not yet be determined. In stead, we keep a pointer | |
1352 | * to the file entry's localsymbol that bequeathed the global symbol with | |
1353 | * its definition. Also, multiple (incompatible) definitions are checked | |
1354 | * for in this pass. If no definition comes forward, the set of local | |
1355 | * symbols originating from shared objects is searched for a definition. | |
1356 | * | |
1357 | * 2) Then the relocation information of each relocatable file is examined | |
27b6ced7 | 1358 | * for possible contributions to the RRS section. |
1136f72d PR |
1359 | * |
1360 | * 3) When this is done, the sizes and start addresses are set of all segments | |
1361 | * that will appear in the output file (including the RRS segment). | |
1362 | * | |
1363 | * 4) Finally, all symbols are relocated according according to the start | |
1364 | * of the entry they are part of. Then global symbols are assigned their | |
1365 | * final values. Also, space for commons and imported data are allocated | |
1366 | * during this pass, if the link mode in effect so demands. | |
1367 | * | |
1368 | */ | |
fb459a62 | 1369 | |
1136f72d | 1370 | void digest_pass1(), digest_pass2(); |
fb459a62 NW |
1371 | |
1372 | void | |
1136f72d | 1373 | digest_symbols () |
fb459a62 | 1374 | { |
fb459a62 | 1375 | |
1136f72d PR |
1376 | if (trace_files) |
1377 | fprintf(stderr, "Digesting symbol information:\n\n"); | |
1378 | ||
1379 | if (!relocatable_output) { | |
1380 | /* | |
1381 | * The set sector size is the number of set elements + a word | |
1382 | * for each symbol for the length word at the beginning of | |
1383 | * the vector, plus a word for each symbol for a zero at the | |
1384 | * end of the vector (for incremental linking). | |
1385 | */ | |
1386 | set_sect_size = (2 * set_symbol_count + set_vector_count) * | |
1387 | sizeof (unsigned long); | |
1388 | set_vectors = (unsigned long *) xmalloc (set_sect_size); | |
1389 | setv_fill_count = 0; | |
1390 | } | |
fb459a62 | 1391 | |
1136f72d PR |
1392 | /* Pass 1: check and define symbols */ |
1393 | defined_global_sym_count = 0; | |
1394 | digest_pass1(); | |
fb459a62 | 1395 | |
27b6ced7 JH |
1396 | each_full_file(consider_relocation, 0); /* Text */ |
1397 | each_full_file(consider_relocation, 1); /* Data */ | |
fb459a62 | 1398 | |
1136f72d PR |
1399 | /* |
1400 | * Compute total size of sections. | |
1401 | * RRS data is the first output data section, RRS text is the last | |
1402 | * text section. Thus, DATA_START is calculated from RRS_DATA_START | |
1403 | * and RRS_DATA_SIZE, while RRS_TEXT_START is derived from TEXT_START | |
1404 | * and TEXT_SIZE. | |
1405 | */ | |
1406 | consider_rrs_section_lengths(); | |
1407 | each_full_file(consider_file_section_lengths, 0); | |
1408 | rrs_text_start = text_start + text_size; | |
1409 | text_size += rrs_text_size; | |
1410 | data_size += rrs_data_size; | |
1411 | ||
1412 | /* | |
1413 | * If necessary, pad text section to full page in the file. Include | |
1414 | * the padding in the text segment size. | |
1415 | */ | |
1416 | ||
1417 | if (magic == ZMAGIC) { | |
1418 | int text_end = text_size + N_TXTOFF(outheader); | |
1419 | text_pad = PALIGN(text_end, page_size) - text_end; | |
1420 | text_size += text_pad; | |
fb459a62 | 1421 | } |
1136f72d | 1422 | outheader.a_text = text_size; |
fb459a62 | 1423 | |
1136f72d PR |
1424 | /* |
1425 | * Make the data segment address start in memory on a suitable | |
1426 | * boundary. | |
1427 | */ | |
fb459a62 | 1428 | |
1136f72d PR |
1429 | if (!Tdata_flag_specified) |
1430 | rrs_data_start = text_start + | |
1431 | DATA_START(outheader) - TEXT_START(outheader); | |
fb459a62 | 1432 | |
1136f72d PR |
1433 | data_start = rrs_data_start + rrs_data_size; |
1434 | if (!relocatable_output) { | |
1435 | set_sect_start = rrs_data_start + data_size; | |
1436 | data_size += set_sect_size; | |
1437 | } | |
1438 | bss_start = rrs_data_start + data_size; | |
1439 | ||
1440 | #ifdef DEBUG | |
1441 | printf("textstart = %#x, textsize = %#x, rrs_text_start = %#x, rrs_text_size %#x\n", | |
1442 | text_start, text_size, rrs_text_start, rrs_text_size); | |
1443 | printf("datastart = %#x, datasize = %#x, rrs_data_start %#x, rrs_data_size %#x\n", | |
1444 | data_start, data_size, rrs_data_start, rrs_data_size); | |
1445 | printf("bssstart = %#x, bsssize = %#x\n", | |
1446 | bss_start, bss_size); | |
fb459a62 NW |
1447 | #endif |
1448 | ||
1136f72d | 1449 | /* Compute start addresses of each file's sections and symbols. */ |
fb459a62 | 1450 | |
1136f72d PR |
1451 | each_full_file(relocate_file_addresses, 0); |
1452 | relocate_rrs_addresses(); | |
fb459a62 | 1453 | |
1136f72d PR |
1454 | /* Pass 2: assign values to symbols */ |
1455 | digest_pass2(); | |
fb459a62 | 1456 | |
1136f72d PR |
1457 | if (end_symbol) { /* These are null if -r. */ |
1458 | etext_symbol->value = text_start + text_size - text_pad; | |
1459 | edata_symbol->value = rrs_data_start + data_size; | |
1460 | end_symbol->value = rrs_data_start + data_size + bss_size; | |
fb459a62 | 1461 | } |
1136f72d PR |
1462 | /* |
1463 | * Figure the data_pad now, so that it overlaps with the bss | |
1464 | * addresses. | |
1465 | */ | |
fb459a62 | 1466 | |
1136f72d PR |
1467 | if (specified_data_size && specified_data_size > data_size) |
1468 | data_pad = specified_data_size - data_size; | |
fb459a62 | 1469 | |
1136f72d PR |
1470 | if (magic == ZMAGIC) |
1471 | data_pad = PALIGN(data_pad + data_size, page_size) - data_size; | |
fb459a62 | 1472 | |
1136f72d PR |
1473 | bss_size -= data_pad; |
1474 | if (bss_size < 0) | |
1475 | bss_size = 0; | |
fb459a62 | 1476 | |
1136f72d | 1477 | data_size += data_pad; |
27b6ced7 JH |
1478 | |
1479 | /* | |
1480 | * Calculate total number of symbols that will go into | |
1481 | * the output symbol table (barring DISCARD_* settings). | |
1482 | */ | |
1483 | global_sym_count = defined_global_sym_count + | |
1484 | undefined_global_sym_count; | |
1485 | ||
1486 | if (dynamic_symbol->referenced) | |
1487 | global_sym_count++; | |
1488 | ||
1489 | if (got_symbol->referenced) | |
1490 | global_sym_count++; | |
1491 | ||
1492 | if (relocatable_output) | |
1493 | /* For each alias we write out two struct nlists */ | |
1494 | global_sym_count += global_alias_count + size_sym_count; | |
1136f72d | 1495 | } |
fb459a62 | 1496 | |
1136f72d PR |
1497 | void |
1498 | digest_pass1() | |
1499 | { | |
1500 | ||
1501 | /* | |
1502 | * Now, for each symbol, verify that it is defined globally at most | |
1503 | * once within relocatable files (except when building a shared lib). | |
1504 | * and set the `defined' field if there is a definition. | |
1505 | * | |
1506 | * Then check the shared object symbol chain for any remaining | |
1507 | * undefined symbols. Set the `so_defined' field for any | |
1508 | * definition find this way. | |
1509 | */ | |
1510 | FOR_EACH_SYMBOL(i, sp) { | |
1511 | struct localsymbol *lsp; | |
1512 | int defs = 0; | |
1513 | ||
1514 | if (!sp->referenced) { | |
1515 | #if 0 | |
1516 | /* Check for undefined symbols in shared objects */ | |
1517 | int type; | |
1518 | for (lsp = sp->sorefs; lsp; lsp = lsp->next) { | |
1519 | type = lsp->nzlist.nlist.n_type; | |
1520 | if ((type & N_EXT) && type != (N_UNDF | N_EXT)) | |
1521 | break; | |
1522 | } | |
1523 | if ((type & N_EXT) && type == (N_UNDF | N_EXT)) | |
1524 | undefined_shobj_sym_count++; | |
fb459a62 NW |
1525 | #endif |
1526 | ||
1136f72d PR |
1527 | /* Superfluous symbol from shared object */ |
1528 | continue; | |
fb459a62 | 1529 | } |
fb459a62 | 1530 | |
1136f72d PR |
1531 | if (sp == got_symbol || sp == dynamic_symbol) |
1532 | continue; | |
1533 | ||
1534 | for (lsp = sp->refs; lsp; lsp = lsp->next) { | |
1535 | register struct nlist *p = &lsp->nzlist.nlist; | |
1536 | register int type = p->n_type; | |
1537 | ||
1538 | if (SET_ELEMENT_P(type)) { | |
1539 | if (relocatable_output) | |
1540 | fatal( | |
1541 | "internal error: global ref to set el %s with -r", | |
1542 | sp->name); | |
1543 | if (!defs++) { | |
1544 | sp->defined = N_SETV | N_EXT; | |
1545 | sp->value = | |
1546 | setv_fill_count++ * sizeof(long); | |
1547 | } else if ((sp->defined & N_TYPE) != N_SETV) { | |
1548 | sp->multiply_defined = 1; | |
1549 | multiple_def_count++; | |
1550 | } | |
1551 | /* Keep count and remember symbol */ | |
1552 | sp->setv_count++; | |
1553 | set_vectors[setv_fill_count++] = (long)p; | |
1554 | ||
1555 | } else if ((type & N_EXT) && type != (N_UNDF | N_EXT) | |
1556 | && (type & N_TYPE) != N_FN | |
1557 | && (type & N_TYPE) != N_SIZE) { | |
1558 | /* non-common definition */ | |
1559 | if (defs++ && sp->value != p->n_value | |
1560 | && entry_symbol) { | |
1561 | sp->multiply_defined = 1; | |
1562 | multiple_def_count++; | |
1563 | } | |
1564 | sp->def_nlist = p; | |
1565 | sp->defined = type; | |
1566 | } | |
fb459a62 NW |
1567 | } |
1568 | ||
1136f72d PR |
1569 | if (sp->defined) { |
1570 | if ((sp->defined & N_TYPE) == N_SETV) | |
1571 | /* Allocate zero entry in set vector */ | |
1572 | setv_fill_count++; | |
1573 | defined_global_sym_count++; | |
1574 | continue; | |
1575 | } | |
fb459a62 | 1576 | |
1136f72d PR |
1577 | if (relocatable_output) |
1578 | /* We're done */ | |
1579 | continue; | |
1580 | ||
1581 | /* | |
1582 | * Still undefined, search the shared object symbols for a | |
1583 | * definition. This symbol must go into the RRS. | |
1584 | */ | |
1585 | if (building_shared_object) { | |
1586 | /* Just punt for now */ | |
1587 | undefined_global_sym_count--; | |
1588 | continue; | |
1589 | } | |
fb459a62 | 1590 | |
1136f72d PR |
1591 | for (lsp = sp->sorefs; lsp; lsp = lsp->next) { |
1592 | register struct nlist *p = &lsp->nzlist.nlist; | |
1593 | register int type = p->n_type; | |
1594 | ||
1595 | if ((type & N_EXT) && type != (N_UNDF | N_EXT) | |
80f25b52 | 1596 | && (type & N_TYPE) != N_FN) { |
1136f72d PR |
1597 | /* non-common definition */ |
1598 | sp->def_nlist = p; | |
1599 | sp->so_defined = type; | |
1600 | undefined_global_sym_count--; | |
1601 | #ifdef DEBUG | |
1602 | printf("shr: %s gets defined to %x with value %x\n", sp->name, type, sp->value); | |
1603 | #endif | |
1604 | break; | |
1605 | } | |
1606 | } | |
1607 | } END_EACH_SYMBOL; | |
fb459a62 | 1608 | } |
fb459a62 NW |
1609 | |
1610 | void | |
1136f72d PR |
1611 | digest_pass2() |
1612 | { | |
1613 | /* | |
1614 | * Assign each symbol its final value. | |
1615 | * If not -r'ing, allocate common symbols in the BSS section. | |
1616 | */ | |
1617 | ||
1618 | FOR_EACH_SYMBOL(i, sp) { | |
1619 | int size; | |
1620 | int align = sizeof(int); | |
1621 | ||
1622 | if (!sp->referenced) | |
1623 | continue; | |
1624 | ||
1625 | if ((sp->defined & N_TYPE) == N_SETV) { | |
1626 | /* | |
1627 | * Set length word at front of vector and zero byte | |
1628 | * at end. Reverse the vector itself to put it in | |
1629 | * file order. | |
1630 | */ | |
1631 | unsigned long i, tmp; | |
1632 | unsigned long length_word_index = | |
1633 | sp->value / sizeof(long); | |
1634 | ||
1635 | /* Relocate symbol value */ | |
1636 | sp->value += set_sect_start; | |
1637 | ||
1638 | set_vectors[length_word_index] = sp->setv_count; | |
1639 | ||
1640 | /* | |
1641 | * Relocate vector to final address. | |
1642 | */ | |
1643 | for (i = 0; i < sp->setv_count; i++) { | |
1644 | struct nlist *p = (struct nlist *) | |
1645 | set_vectors[1+i+length_word_index]; | |
1646 | ||
1647 | set_vectors[1+i+length_word_index] = p->n_value; | |
1648 | } | |
1649 | ||
1650 | /* | |
1651 | * Reverse the vector. | |
1652 | */ | |
1653 | for (i = 1; i < (sp->setv_count - 1)/2 + 1; i++) { | |
1654 | ||
1655 | tmp = set_vectors[length_word_index + i]; | |
1656 | set_vectors[length_word_index + i] = | |
1657 | set_vectors[length_word_index + sp->setv_count + 1 - i]; | |
1658 | set_vectors[length_word_index + sp->setv_count + 1 - i] = tmp; | |
1659 | } | |
1660 | ||
1661 | /* Clear terminating entry */ | |
1662 | set_vectors[length_word_index + sp->setv_count + 1] = 0; | |
1663 | continue; | |
1664 | } | |
fb459a62 | 1665 | |
fb459a62 | 1666 | |
1136f72d PR |
1667 | if (sp->defined && sp->def_nlist && |
1668 | ((sp->defined & ~N_EXT) != N_SETV)) | |
1669 | sp->value = sp->def_nlist->n_value; | |
1670 | ||
1671 | if (building_shared_object && !(link_mode & SYMBOLIC)) | |
1672 | /* No common allocation in shared objects */ | |
1673 | continue; | |
1674 | ||
1675 | if ((size = sp->max_common_size) != 0) { | |
1676 | /* | |
1677 | * It's a common. | |
1678 | */ | |
1679 | if (sp->defined != (N_UNDF + N_EXT)) | |
1680 | fatal("%s: common isn't", sp->name); | |
1681 | ||
1682 | } else if ((size = sp->size) != 0 && sp->defined == N_SIZE) { | |
1683 | /* | |
1684 | * It's data from shared object with size info. | |
1685 | */ | |
7fc7155d | 1686 | if (!sp->so_defined) |
1136f72d PR |
1687 | fatal("%s: Bogus N_SIZE item", sp->name); |
1688 | ||
1689 | } else | |
1690 | /* | |
1691 | * It's neither | |
1692 | */ | |
1693 | continue; | |
1694 | ||
1695 | ||
1696 | if (relocatable_output && !force_common_definition) { | |
1697 | sp->defined = 0; | |
1698 | undefined_global_sym_count++; | |
1699 | defined_global_sym_count--; | |
1700 | continue; | |
1701 | } | |
fb459a62 | 1702 | |
1136f72d PR |
1703 | /* |
1704 | * Round up to nearest sizeof (int). I don't know whether | |
1705 | * this is necessary or not (given that alignment is taken | |
1706 | * care of later), but it's traditional, so I'll leave it in. | |
1707 | * Note that if this size alignment is ever removed, ALIGN | |
1708 | * above will have to be initialized to 1 instead of sizeof | |
1709 | * (int). | |
1710 | */ | |
fb459a62 | 1711 | |
1136f72d | 1712 | size = PALIGN(size, sizeof(int)); |
fb459a62 | 1713 | |
1136f72d PR |
1714 | while (!(size & align)) |
1715 | align <<= 1; | |
fb459a62 | 1716 | |
1136f72d PR |
1717 | align = align > MAX_ALIGNMENT ? |
1718 | MAX_ALIGNMENT : align; | |
fb459a62 | 1719 | |
1136f72d PR |
1720 | bss_size = PALIGN(bss_size + data_size + rrs_data_start, align) |
1721 | - (data_size + rrs_data_start); | |
fb459a62 | 1722 | |
1136f72d PR |
1723 | sp->value = rrs_data_start + data_size + bss_size; |
1724 | if (sp->defined == (N_UNDF | N_EXT)) | |
1725 | sp->defined = N_BSS | N_EXT; | |
1726 | else { | |
1727 | sp->so_defined = 0; | |
1728 | defined_global_sym_count++; | |
1729 | } | |
1730 | bss_size += size; | |
1731 | if (write_map) | |
1732 | printf("Allocating %s %s: %x at %x\n", | |
1733 | sp->defined==(N_BSS|N_EXT)?"common":"data", | |
1734 | sp->name, size, sp->value); | |
fb459a62 | 1735 | |
1136f72d | 1736 | } END_EACH_SYMBOL; |
fb459a62 NW |
1737 | } |
1738 | ||
fb459a62 | 1739 | /* |
1136f72d PR |
1740 | * Scan relocation info in ENTRY for contributions to the dynamic section of |
1741 | * the output file. | |
fb459a62 | 1742 | */ |
1136f72d PR |
1743 | void |
1744 | consider_relocation (entry, dataseg) | |
1745 | struct file_entry *entry; | |
1746 | int dataseg; | |
1747 | { | |
1748 | struct relocation_info *reloc, *end; | |
1749 | struct localsymbol *lsp; | |
1750 | symbol *sp; | |
1751 | ||
1752 | if (dataseg == 0) { | |
1753 | /* Text relocations */ | |
1754 | reloc = entry->textrel; | |
1755 | end = entry->textrel + entry->ntextrel; | |
1756 | } else { | |
1757 | /* Data relocations */ | |
1758 | reloc = entry->datarel; | |
1759 | end = entry->datarel + entry->ndatarel; | |
fb459a62 | 1760 | } |
fb459a62 | 1761 | |
1136f72d PR |
1762 | for (; reloc < end; reloc++) { |
1763 | ||
80f25b52 JH |
1764 | if (relocatable_output) { |
1765 | lsp = &entry->symbols[reloc->r_symbolnum]; | |
27b6ced7 JH |
1766 | if (RELOC_BASEREL_P(reloc)) { |
1767 | pic_code_seen = 1; | |
1768 | if (!RELOC_EXTERN_P(reloc)) | |
1769 | lsp->rename = 1; | |
80f25b52 JH |
1770 | } |
1771 | continue; | |
1772 | } | |
1773 | ||
1136f72d PR |
1774 | /* |
1775 | * First, do the PIC specific relocs. | |
1776 | * r_relative and r_copy should not occur at this point | |
1777 | * (we do output them). The others break down to these | |
1778 | * combinations: | |
1779 | * | |
1780 | * jmptab: extern: needs jmp slot | |
1781 | * !extern: "intersegment" jump/call, | |
1782 | * should get resolved in output | |
1783 | * | |
1784 | * baserel: extern: need GOT entry | |
1785 | * !extern: may need GOT entry, | |
1786 | * machine dependent | |
1787 | * | |
1788 | * baserel's always refer to symbol through `r_symbolnum' | |
1789 | * whether extern or not. Internal baserels refer to statics | |
1790 | * that must be accessed either *through* the GOT table like | |
1791 | * global data, or by means of an offset from the GOT table. | |
1792 | * The macro RELOC_STATICS_THROUGH_GOT_P() determines which | |
1793 | * applies, since this is a machine (compiler?) dependent | |
1794 | * addressing mode. | |
1795 | */ | |
1796 | ||
1797 | if (RELOC_JMPTAB_P(reloc)) { | |
1798 | ||
1799 | if (!RELOC_EXTERN_P(reloc)) | |
1800 | continue; | |
1801 | ||
1802 | lsp = &entry->symbols[reloc->r_symbolnum]; | |
1803 | sp = lsp->symbol; | |
1804 | if (sp->alias) | |
1805 | sp = sp->alias; | |
27b6ced7 | 1806 | alloc_rrs_jmpslot(entry, sp); |
1136f72d PR |
1807 | |
1808 | } else if (RELOC_BASEREL_P(reloc)) { | |
1809 | ||
1810 | lsp = &entry->symbols[reloc->r_symbolnum]; | |
27b6ced7 | 1811 | alloc_rrs_gotslot(entry, reloc, lsp); |
1136f72d PR |
1812 | |
1813 | } else if (RELOC_EXTERN_P(reloc)) { | |
1814 | ||
1815 | /* | |
1816 | * Non-PIC relocations. | |
1817 | * If the definition comes from a shared object | |
1818 | * we need a relocation entry in RRS. | |
1819 | * | |
1820 | * If the .so definition is N_TEXT a jmpslot is | |
1821 | * allocated. | |
1822 | * | |
1823 | * If it is N_DATA we allocate an address in BSS (?) | |
1824 | * and arrange for the data to be copied at run-time. | |
1825 | * The symbol is temporarily marked with N_SIZE in | |
1826 | * the `defined' field, so we know what to do in | |
1827 | * pass2() and during actual relocation. We convert | |
1828 | * the type back to something real again when writing | |
1829 | * out the symbols. | |
1830 | * | |
1831 | */ | |
1832 | lsp = &entry->symbols[reloc->r_symbolnum]; | |
1833 | sp = lsp->symbol; | |
1834 | if (sp == NULL) | |
1835 | fatal_with_file( | |
1836 | "internal error, sp==NULL", entry); | |
1837 | ||
1838 | if (sp->alias) | |
1839 | sp = sp->alias; | |
1840 | ||
1841 | /* | |
1842 | * Skip refs to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC | |
1843 | */ | |
1844 | if (sp == got_symbol) { | |
1845 | if (!CHECK_GOT_RELOC(reloc)) | |
1846 | fatal_with_file( | |
1847 | "Unexpected relocation type ", entry); | |
1848 | continue; | |
1849 | } | |
1850 | ||
1851 | /* | |
1852 | * This symbol gives rise to a RRS entry | |
1853 | */ | |
1854 | ||
1855 | if (building_shared_object) { | |
27b6ced7 | 1856 | alloc_rrs_reloc(entry, sp); |
1136f72d PR |
1857 | continue; |
1858 | } | |
1859 | ||
7fc7155d PR |
1860 | /* |
1861 | * Only allocate an alias for function calls. Use | |
1862 | * sp->size here as a heuristic to discriminate | |
1863 | * between function definitions and data residing | |
1864 | * in the text segment. | |
1865 | * NOTE THAT THE COMPILER MUST NOT GENERATE ".size" | |
1866 | * DIRECTIVES FOR FUNCTIONS. | |
1867 | * In the future we might go for ".type" directives. | |
1868 | */ | |
1869 | if (force_alias_definition && sp->size == 0 && | |
1136f72d PR |
1870 | sp->so_defined == N_TEXT + N_EXT) { |
1871 | ||
1872 | /* Call to shared library procedure */ | |
27b6ced7 JH |
1873 | alloc_rrs_jmpslot(entry, sp); |
1874 | #define EXPERIMENTAL | |
1875 | #ifdef EXPERIMENTAL | |
c62b29f8 | 1876 | if (!RELOC_PCREL_P(reloc)) { |
27b6ced7 JH |
1877 | #ifdef DEBUG |
1878 | printf("%s: FUNC flag set\n", sp->name); | |
1879 | #endif | |
c62b29f8 JH |
1880 | sp->aux = RRS_FUNC; |
1881 | } | |
27b6ced7 JH |
1882 | #endif |
1883 | ||
1136f72d | 1884 | } else if (sp->size && |
7fc7155d PR |
1885 | (sp->so_defined == N_DATA + N_EXT || |
1886 | sp->so_defined == N_TEXT + N_EXT)) { | |
1136f72d PR |
1887 | |
1888 | /* Reference to shared library data */ | |
27b6ced7 | 1889 | alloc_rrs_cpy_reloc(entry, sp); |
1136f72d PR |
1890 | sp->defined = N_SIZE; |
1891 | ||
1892 | } else if (!sp->defined && sp->max_common_size == 0) | |
27b6ced7 | 1893 | alloc_rrs_reloc(entry, sp); |
1136f72d PR |
1894 | |
1895 | } else { | |
1896 | /* | |
1897 | * Segment relocation. | |
1898 | * Prepare an RRS relocation as these are load | |
1899 | * address dependent. | |
1900 | */ | |
1901 | if (building_shared_object) { | |
27b6ced7 | 1902 | alloc_rrs_segment_reloc(entry, reloc); |
1136f72d PR |
1903 | } |
1904 | } | |
fb459a62 | 1905 | } |
fb459a62 NW |
1906 | } |
1907 | ||
1136f72d PR |
1908 | /* |
1909 | * Accumulate the section sizes of input file ENTRY into the section sizes of | |
1910 | * the output file. | |
1911 | */ | |
1912 | void | |
1913 | consider_file_section_lengths (entry) | |
1914 | register struct file_entry *entry; | |
fb459a62 | 1915 | { |
1136f72d PR |
1916 | if (entry->just_syms_flag) |
1917 | return; | |
fb459a62 | 1918 | |
1136f72d PR |
1919 | entry->text_start_address = text_size; |
1920 | /* If there were any vectors, we need to chop them off */ | |
1921 | text_size += entry->header.a_text; | |
1922 | entry->data_start_address = data_size; | |
1923 | data_size += entry->header.a_data; | |
1924 | entry->bss_start_address = bss_size; | |
1925 | bss_size += entry->header.a_bss; | |
fb459a62 | 1926 | |
1136f72d PR |
1927 | text_reloc_size += entry->header.a_trsize; |
1928 | data_reloc_size += entry->header.a_drsize; | |
fb459a62 NW |
1929 | } |
1930 | ||
1136f72d PR |
1931 | /* |
1932 | * Determine where the sections of ENTRY go into the output file, | |
1933 | * whose total section sizes are already known. | |
27b6ced7 JH |
1934 | * Also relocate the addresses of the file's local and debugger symbols |
1935 | * and determine which of the local symbols will make it into the | |
1936 | * output symbol table. | |
1136f72d | 1937 | */ |
fb459a62 | 1938 | void |
1136f72d PR |
1939 | relocate_file_addresses (entry) |
1940 | register struct file_entry *entry; | |
fb459a62 | 1941 | { |
27b6ced7 | 1942 | register struct localsymbol *lsp, *lspend; |
1136f72d PR |
1943 | |
1944 | entry->text_start_address += text_start; | |
1945 | /* | |
1946 | * Note that `data_start' and `data_size' have not yet been | |
1947 | * adjusted for `data_pad'. If they had been, we would get the wrong | |
1948 | * results here. | |
1949 | */ | |
1950 | entry->data_start_address += data_start; | |
1951 | entry->bss_start_address += bss_start; | |
1952 | #ifdef DEBUG | |
1953 | printf("%s: datastart: %#x, bss %#x\n", get_file_name(entry), | |
1954 | entry->data_start_address, entry->bss_start_address); | |
1955 | #endif | |
fb459a62 | 1956 | |
1136f72d PR |
1957 | lspend = entry->symbols + entry->nsymbols; |
1958 | ||
1959 | for (lsp = entry->symbols; lsp < lspend; lsp++) { | |
1960 | register struct nlist *p = &lsp->nzlist.nlist; | |
27b6ced7 JH |
1961 | register int type = p->n_type; |
1962 | ||
1136f72d PR |
1963 | /* |
1964 | * If this belongs to a section, update it | |
1965 | * by the section's start address | |
1966 | */ | |
1136f72d | 1967 | |
27b6ced7 | 1968 | switch (type & N_TYPE) { |
1136f72d PR |
1969 | case N_TEXT: |
1970 | case N_SETT: | |
1971 | p->n_value += entry->text_start_address; | |
1972 | break; | |
1973 | case N_DATA: | |
1974 | case N_SETD: | |
1975 | case N_SETV: | |
1976 | /* | |
1977 | * A symbol whose value is in the data section is | |
1978 | * present in the input file as if the data section | |
1979 | * started at an address equal to the length of the | |
1980 | * file's text. | |
1981 | */ | |
1982 | p->n_value += entry->data_start_address - | |
1983 | entry->header.a_text; | |
1984 | break; | |
1985 | case N_BSS: | |
1986 | case N_SETB: | |
1987 | /* likewise for symbols with value in BSS. */ | |
1988 | p->n_value += entry->bss_start_address | |
1989 | - entry->header.a_text - entry->header.a_data; | |
1990 | break; | |
1991 | } | |
27b6ced7 JH |
1992 | |
1993 | /* | |
1994 | * See if this symbol should be in the output symbol table. | |
1995 | */ | |
1996 | ||
1997 | if (type == N_WARNING) | |
1998 | continue; | |
1999 | ||
2000 | if (SET_ELEMENT_P (type)) { | |
2001 | /* | |
2002 | * This occurs even if global. These types of | |
2003 | * symbols are never written globally, though | |
2004 | * they are stored globally. | |
2005 | */ | |
2006 | lsp->write = relocatable_output; | |
2007 | ||
2008 | } else if (!(type & (N_STAB | N_EXT))) { | |
2009 | ||
2010 | /* | |
2011 | * Ordinary local symbol | |
2012 | */ | |
2013 | lsp->write = (lsp->rename || ( | |
2014 | discard_locals != DISCARD_ALL && | |
2015 | !(discard_locals == DISCARD_L && | |
2016 | lsp->is_L_symbol))); | |
2017 | if (lsp->write) | |
2018 | local_sym_count++; | |
2019 | ||
2020 | } else if (!(type & N_EXT)) { | |
2021 | ||
2022 | /* | |
2023 | * Debugger symbol | |
2024 | */ | |
2025 | lsp->write = (strip_symbols == STRIP_NONE); | |
2026 | if (lsp->write) | |
2027 | debugger_sym_count++; | |
2028 | ||
2029 | } | |
fb459a62 | 2030 | } |
27b6ced7 JH |
2031 | |
2032 | /* | |
2033 | * Count one for the local symbol that we generate, | |
2034 | * whose name is the file's name (usually) and whose address | |
2035 | * is the start of the file's text. | |
2036 | */ | |
2037 | if (discard_locals != DISCARD_ALL) | |
2038 | local_sym_count++; | |
2039 | ||
fb459a62 NW |
2040 | } |
2041 | \f | |
2042 | /* Write the output file */ | |
2043 | ||
2044 | void | |
2045 | write_output () | |
2046 | { | |
1136f72d PR |
2047 | struct stat statbuf; |
2048 | int filemode; | |
2049 | ||
2050 | if (lstat(output_filename, &statbuf) != -1) { | |
2051 | if (!S_ISDIR(statbuf.st_mode)) | |
2052 | (void)unlink(output_filename); | |
2053 | } | |
fb459a62 | 2054 | |
1136f72d PR |
2055 | outdesc = open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); |
2056 | if (outdesc < 0) | |
2057 | perror_name (output_filename); | |
fb459a62 | 2058 | |
1136f72d PR |
2059 | if (fstat (outdesc, &statbuf) < 0) |
2060 | perror_name (output_filename); | |
fb459a62 | 2061 | |
1136f72d | 2062 | filemode = statbuf.st_mode; |
fb459a62 | 2063 | |
1136f72d | 2064 | chmod (output_filename, filemode & ~0111); |
fb459a62 | 2065 | |
1136f72d PR |
2066 | /* Output the a.out header. */ |
2067 | write_header (); | |
fb459a62 | 2068 | |
1136f72d PR |
2069 | /* Output the text and data segments, relocating as we go. */ |
2070 | write_text (); | |
2071 | write_data (); | |
fb459a62 | 2072 | |
1136f72d PR |
2073 | /* Output the merged relocation info, if requested with `-r'. */ |
2074 | if (relocatable_output) | |
2075 | write_rel (); | |
fb459a62 | 2076 | |
1136f72d PR |
2077 | /* Output the symbol table (both globals and locals). */ |
2078 | write_syms (); | |
fb459a62 | 2079 | |
1136f72d PR |
2080 | /* Output the RSS section */ |
2081 | write_rrs (); | |
fb459a62 | 2082 | |
1136f72d | 2083 | close (outdesc); |
fb459a62 | 2084 | |
1136f72d PR |
2085 | if (chmod (output_filename, filemode | 0111) == -1) |
2086 | perror_name (output_filename); | |
fb459a62 NW |
2087 | } |
2088 | \f | |
2089 | void modify_location (), perform_relocation (), copy_text (), copy_data (); | |
2090 | ||
1136f72d PR |
2091 | /* Total number of symbols to be written in the output file. */ |
2092 | int nsyms; | |
2093 | ||
fb459a62 NW |
2094 | void |
2095 | write_header () | |
2096 | { | |
1136f72d PR |
2097 | int flags = (rrs_section_type == RRS_FULL) ? EX_DYNAMIC : 0; |
2098 | ||
80f25b52 | 2099 | if (!oldmagic) N_SET_FLAG (outheader, flags); |
1136f72d PR |
2100 | outheader.a_text = text_size; |
2101 | outheader.a_data = data_size; | |
2102 | outheader.a_bss = bss_size; | |
2103 | outheader.a_entry = (entry_symbol ? entry_symbol->value | |
2104 | : text_start + entry_offset); | |
2105 | ||
2106 | if (strip_symbols == STRIP_ALL) | |
2107 | nsyms = 0; | |
27b6ced7 JH |
2108 | else |
2109 | nsyms = global_sym_count + local_sym_count + debugger_sym_count; | |
fb459a62 | 2110 | |
27b6ced7 JH |
2111 | if (relocatable_output) |
2112 | nsyms += set_symbol_count; | |
fb459a62 | 2113 | |
27b6ced7 JH |
2114 | printf("global symbols %d (defined %d, undefined %d), locals: %d, \ |
2115 | debug symbols: %d, set_symbols %d, aliases %d --> nsyms %d\n", | |
2116 | global_sym_count, | |
1136f72d | 2117 | defined_global_sym_count, undefined_global_sym_count, |
27b6ced7 JH |
2118 | local_sym_count, debugger_sym_count, |
2119 | set_symbol_count, global_alias_count, nsyms); | |
2120 | #ifdef DEBUG | |
fb459a62 | 2121 | #endif |
fb459a62 | 2122 | |
1136f72d PR |
2123 | outheader.a_syms = nsyms * sizeof (struct nlist); |
2124 | ||
2125 | if (relocatable_output) { | |
2126 | outheader.a_trsize = text_reloc_size; | |
2127 | outheader.a_drsize = data_reloc_size; | |
2128 | } else { | |
2129 | outheader.a_trsize = 0; | |
2130 | outheader.a_drsize = 0; | |
2131 | } | |
2132 | ||
2133 | md_swapout_exec_hdr(&outheader); | |
2134 | mywrite (&outheader, sizeof (struct exec), 1, outdesc); | |
2135 | md_swapin_exec_hdr(&outheader); | |
2136 | ||
2137 | /* | |
2138 | * Output whatever padding is required in the executable file | |
2139 | * between the header and the start of the text. | |
2140 | */ | |
fb459a62 NW |
2141 | |
2142 | #ifndef COFF_ENCAPSULATE | |
1136f72d | 2143 | padfile (N_TXTOFF(outheader) - sizeof outheader, outdesc); |
fb459a62 NW |
2144 | #endif |
2145 | } | |
2146 | \f | |
2147 | /* Relocate the text segment of each input file | |
2148 | and write to the output file. */ | |
2149 | ||
2150 | void | |
2151 | write_text () | |
2152 | { | |
fb459a62 | 2153 | |
1136f72d PR |
2154 | if (trace_files) |
2155 | fprintf (stderr, "Copying and relocating text:\n\n"); | |
fb459a62 | 2156 | |
1136f72d PR |
2157 | each_full_file (copy_text, 0); |
2158 | file_close (); | |
fb459a62 | 2159 | |
1136f72d PR |
2160 | if (trace_files) |
2161 | fprintf (stderr, "\n"); | |
fb459a62 | 2162 | |
1136f72d | 2163 | padfile (text_pad, outdesc); |
fb459a62 NW |
2164 | } |
2165 | ||
1136f72d PR |
2166 | /* |
2167 | * Read the text segment contents of ENTRY, relocate them, and write the | |
2168 | * result to the output file. If `-r', save the text relocation for later | |
2169 | * reuse. | |
2170 | */ | |
fb459a62 NW |
2171 | void |
2172 | copy_text (entry) | |
2173 | struct file_entry *entry; | |
2174 | { | |
1136f72d PR |
2175 | register char *bytes; |
2176 | register int desc; | |
fb459a62 | 2177 | |
1136f72d PR |
2178 | if (trace_files) |
2179 | prline_file_name (entry, stderr); | |
fb459a62 | 2180 | |
1136f72d | 2181 | desc = file_open (entry); |
fb459a62 | 2182 | |
1136f72d PR |
2183 | /* Allocate space for the file's text section */ |
2184 | bytes = (char *) alloca (entry->header.a_text); | |
fb459a62 | 2185 | |
1136f72d PR |
2186 | /* Deal with relocation information however is appropriate */ |
2187 | if (entry->textrel == NULL) | |
2188 | fatal_with_file("no text relocation of ", entry); | |
fb459a62 | 2189 | |
1136f72d PR |
2190 | /* Read the text section into core. */ |
2191 | lseek (desc, text_offset (entry), 0); | |
2192 | if (entry->header.a_text != read (desc, bytes, entry->header.a_text)) | |
2193 | fatal_with_file ("premature eof in text section of ", entry); | |
fb459a62 | 2194 | |
fb459a62 | 2195 | |
1136f72d PR |
2196 | /* Relocate the text according to the text relocation. */ |
2197 | perform_relocation (bytes, entry->header.a_text, | |
2198 | entry->textrel, entry->ntextrel, entry, 0); | |
fb459a62 | 2199 | |
1136f72d PR |
2200 | /* Write the relocated text to the output file. */ |
2201 | mywrite (bytes, 1, entry->header.a_text, outdesc); | |
fb459a62 NW |
2202 | } |
2203 | \f | |
2204 | /* Relocate the data segment of each input file | |
2205 | and write to the output file. */ | |
2206 | ||
2207 | void | |
2208 | write_data () | |
2209 | { | |
1136f72d | 2210 | long pos; |
fb459a62 | 2211 | |
1136f72d PR |
2212 | if (trace_files) |
2213 | fprintf (stderr, "Copying and relocating data:\n\n"); | |
fb459a62 | 2214 | |
1136f72d PR |
2215 | pos = N_DATOFF(outheader) + data_start - rrs_data_start; |
2216 | if (lseek(outdesc, pos, L_SET) != pos) | |
2217 | fatal("write_data: lseek: cant position data offset"); | |
fb459a62 | 2218 | |
1136f72d PR |
2219 | each_full_file (copy_data, 0); |
2220 | file_close (); | |
fb459a62 | 2221 | |
1136f72d PR |
2222 | /* |
2223 | * Write out the set element vectors. See digest symbols for | |
2224 | * description of length of the set vector section. | |
2225 | */ | |
fb459a62 | 2226 | |
1136f72d PR |
2227 | if (set_vector_count) { |
2228 | swap_longs(set_vectors, 2 * set_symbol_count + set_vector_count); | |
2229 | mywrite (set_vectors, 2 * set_symbol_count + set_vector_count, | |
2230 | sizeof (unsigned long), outdesc); | |
2231 | } | |
2232 | ||
2233 | if (trace_files) | |
2234 | fprintf (stderr, "\n"); | |
fb459a62 | 2235 | |
1136f72d PR |
2236 | padfile (data_pad, outdesc); |
2237 | } | |
fb459a62 | 2238 | |
1136f72d PR |
2239 | /* |
2240 | * Read the data segment contents of ENTRY, relocate them, and write the | |
2241 | * result to the output file. If `-r', save the data relocation for later | |
2242 | * reuse. See comments in `copy_text'. | |
2243 | */ | |
fb459a62 NW |
2244 | void |
2245 | copy_data (entry) | |
2246 | struct file_entry *entry; | |
2247 | { | |
1136f72d PR |
2248 | register char *bytes; |
2249 | register int desc; | |
fb459a62 | 2250 | |
1136f72d PR |
2251 | if (trace_files) |
2252 | prline_file_name (entry, stderr); | |
fb459a62 | 2253 | |
1136f72d | 2254 | desc = file_open (entry); |
fb459a62 | 2255 | |
1136f72d | 2256 | bytes = (char *)alloca(entry->header.a_data); |
fb459a62 | 2257 | |
1136f72d PR |
2258 | if (entry->datarel == NULL) |
2259 | fatal_with_file("no data relocation of ", entry); | |
fb459a62 | 2260 | |
1136f72d PR |
2261 | lseek (desc, text_offset (entry) + entry->header.a_text, 0); |
2262 | if (entry->header.a_data != read(desc, bytes, entry->header.a_data)) | |
2263 | fatal_with_file ("premature eof in data section of ", entry); | |
fb459a62 | 2264 | |
1136f72d PR |
2265 | perform_relocation (bytes, entry->header.a_data, |
2266 | entry->datarel, entry->ndatarel, entry, 1); | |
fb459a62 | 2267 | |
1136f72d PR |
2268 | mywrite (bytes, 1, entry->header.a_data, outdesc); |
2269 | } | |
2270 | \f | |
2271 | /* | |
2272 | * Relocate ENTRY's text or data section contents. DATA is the address of the | |
2273 | * contents, in core. DATA_SIZE is the length of the contents. PC_RELOCATION | |
2274 | * is the difference between the address of the contents in the output file | |
2275 | * and its address in the input file. RELOC is the address of the | |
2276 | * relocation info, in core. NRELOC says how many there are. | |
2277 | */ | |
2278 | void | |
2279 | perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) | |
2280 | char *data; | |
2281 | int data_size; | |
2282 | struct relocation_info *reloc; | |
2283 | int nreloc; | |
2284 | struct file_entry *entry; | |
2285 | int dataseg; | |
2286 | { | |
2287 | register struct relocation_info *r = reloc; | |
2288 | struct relocation_info *end = reloc + nreloc; | |
2289 | ||
2290 | text_relocation = entry->text_start_address; | |
2291 | data_relocation = entry->data_start_address - entry->header.a_text; | |
2292 | bss_relocation = entry->bss_start_address - | |
2293 | entry->header.a_text - entry->header.a_data; | |
2294 | pc_relocation = dataseg? | |
2295 | entry->data_start_address - entry->header.a_text: | |
2296 | entry->text_start_address; | |
2297 | ||
2298 | for (; r < end; r++) { | |
2299 | int addr = RELOC_ADDRESS(r); | |
2300 | long addend = md_get_addend(r, data+addr); | |
2301 | long relocation; | |
2302 | ||
2303 | /* | |
2304 | * Loop over the relocations again as we did in | |
2305 | * consider_relocation(), claiming the reserved RRS | |
2306 | * relocations. | |
2307 | */ | |
2308 | ||
2309 | if (addr >= data_size) | |
2310 | fatal_with_file( | |
2311 | "relocation address out of range in ", entry); | |
2312 | ||
2313 | if (RELOC_JMPTAB_P(r)) { | |
2314 | ||
2315 | int symindex = RELOC_SYMBOL(r); | |
2316 | struct localsymbol *lsp = &entry->symbols[symindex]; | |
2317 | symbol *sp; | |
2318 | ||
2319 | if (symindex >= entry->nsymbols) | |
2320 | fatal_with_file( | |
2321 | "relocation symbolnum out of range in ", entry); | |
2322 | ||
2323 | sp = lsp->symbol; | |
2324 | if (sp->alias) | |
2325 | sp = sp->alias; | |
2326 | ||
2327 | if (relocatable_output) | |
2328 | relocation = addend; | |
2329 | else if (!RELOC_EXTERN_P(r)) { | |
2330 | relocation = addend + | |
2331 | data_relocation - text_relocation; | |
2332 | } else | |
2333 | relocation = addend + | |
27b6ced7 | 2334 | claim_rrs_jmpslot(entry, r, sp, addend); |
1136f72d PR |
2335 | |
2336 | } else if (RELOC_BASEREL_P(r)) { | |
2337 | ||
2338 | int symindex = RELOC_SYMBOL(r); | |
2339 | struct localsymbol *lsp = &entry->symbols[symindex]; | |
2340 | ||
2341 | if (symindex >= entry->nsymbols) | |
2342 | fatal_with_file( | |
2343 | "relocation symbolnum out of range in ", entry); | |
2344 | ||
2345 | if (relocatable_output) | |
2346 | relocation = addend; | |
2347 | else if (!RELOC_EXTERN_P(r)) | |
2348 | relocation = claim_rrs_internal_gotslot(entry, | |
2349 | r, lsp, addend); | |
2350 | else | |
27b6ced7 JH |
2351 | relocation = claim_rrs_gotslot(entry, |
2352 | r, lsp, addend); | |
1136f72d PR |
2353 | |
2354 | } else if (RELOC_EXTERN_P(r)) { | |
2355 | ||
2356 | int symindex = RELOC_SYMBOL(r); | |
2357 | symbol *sp; | |
2358 | ||
2359 | if (symindex >= entry->nsymbols) | |
2360 | fatal_with_file( | |
2361 | "relocation symbolnum out of range in ", entry); | |
2362 | ||
2363 | sp = entry->symbols[symindex].symbol; | |
2364 | if (sp->alias) | |
2365 | sp = sp->alias; | |
2366 | ||
2367 | if (relocatable_output) { | |
27b6ced7 JH |
2368 | relocation = addend; |
2369 | /* | |
2370 | * In PIC code, we keep the reference to the | |
2371 | * external symbol, even if defined now. | |
2372 | */ | |
2373 | if (!pic_code_seen) | |
2374 | relocation += sp->value; | |
1136f72d PR |
2375 | } else if (sp->defined) { |
2376 | if (sp == got_symbol) { | |
2377 | /* Handle _GOT_ refs */ | |
2378 | relocation = addend + sp->value | |
2379 | + md_got_reloc(r); | |
2380 | } else if (building_shared_object) { | |
2381 | /* | |
2382 | * Normal (non-PIC) relocation needs | |
2383 | * to be converted into an RRS reloc | |
2384 | * when building a shared object. | |
2385 | */ | |
2386 | r->r_address += dataseg? | |
2387 | entry->data_start_address: | |
2388 | entry->text_start_address; | |
2389 | relocation = addend; | |
27b6ced7 JH |
2390 | if (claim_rrs_reloc(entry, r, |
2391 | sp, &relocation)) | |
1136f72d PR |
2392 | continue; |
2393 | } else if (sp->defined == N_SIZE) { | |
2394 | /* | |
2395 | * If size is known, arrange a | |
2396 | * run-time copy. | |
2397 | */ | |
2398 | if (!sp->size) | |
2399 | fatal("Copy item isn't: %s", | |
2400 | sp->name); | |
2401 | ||
2402 | relocation = addend + sp->value; | |
2403 | r->r_address = sp->value; | |
27b6ced7 | 2404 | claim_rrs_cpy_reloc(entry, r, sp); |
1136f72d PR |
2405 | } else |
2406 | /* Plain old relocation */ | |
2407 | relocation = addend + sp->value; | |
2408 | } else { | |
2409 | /* | |
2410 | * If the symbol is undefined, we relocate it | |
2411 | * in a way similar to -r case. We use an | |
2412 | * RRS relocation to resolve the symbol at | |
2413 | * run-time. The r_address field is updated | |
2414 | * to reflect the changed position in the | |
2415 | * output file. | |
2416 | * | |
2417 | * In case the symbol is defined in a shared | |
2418 | * object as N_TEXT or N_DATA, an appropriate | |
2419 | * jmpslot or copy relocation is generated. | |
2420 | */ | |
2421 | switch (sp->so_defined) { | |
2422 | ||
2423 | case N_TEXT+N_EXT: | |
2424 | /* | |
2425 | * Claim a jmpslot if one was | |
2426 | * allocated (dependent on | |
2427 | * `force_alias_flag'). | |
2428 | */ | |
2429 | ||
2430 | if (sp->jmpslot_offset == -1) | |
2431 | goto undefined; | |
2432 | ||
2433 | relocation = addend + | |
27b6ced7 JH |
2434 | claim_rrs_jmpslot(entry, r, |
2435 | sp, addend); | |
1136f72d PR |
2436 | break; |
2437 | ||
2438 | case N_DATA+N_EXT: | |
2439 | /*FALLTHROUGH*/ | |
2440 | case 0: | |
2441 | undefined: | |
2442 | r->r_address += dataseg? | |
2443 | entry->data_start_address: | |
2444 | entry->text_start_address; | |
2445 | relocation = addend; | |
27b6ced7 JH |
2446 | if (claim_rrs_reloc(entry, r, |
2447 | sp, &relocation)) | |
1136f72d PR |
2448 | continue; |
2449 | break; | |
2450 | ||
2451 | case N_BSS+N_EXT: | |
2452 | printf("%s: BSS found in so_defined\n", sp->name); | |
2453 | /*break;*/ | |
2454 | ||
2455 | default: | |
2456 | fatal("%s: shobj symbol with unknown type %#x", sp->name, sp->so_defined); | |
2457 | break; | |
2458 | } | |
2459 | } | |
2460 | ||
2461 | } else { | |
2462 | ||
2463 | switch (RELOC_TYPE(r)) { | |
2464 | case N_TEXT: | |
2465 | case N_TEXT | N_EXT: | |
2466 | relocation = addend + text_relocation; | |
2467 | break; | |
2468 | ||
2469 | case N_DATA: | |
2470 | case N_DATA | N_EXT: | |
2471 | /* | |
2472 | * A word that points to beginning of the the | |
2473 | * data section initially contains not 0 but | |
2474 | * rather the "address" of that section in | |
2475 | * the input file, which is the length of the | |
2476 | * file's text. | |
2477 | */ | |
2478 | relocation = addend + data_relocation; | |
2479 | break; | |
2480 | ||
2481 | case N_BSS: | |
2482 | case N_BSS | N_EXT: | |
2483 | /* | |
2484 | * Similarly, an input word pointing to the | |
2485 | * beginning of the bss initially contains | |
2486 | * the length of text plus data of the file. | |
2487 | */ | |
2488 | relocation = addend + bss_relocation; | |
2489 | break; | |
2490 | ||
2491 | case N_ABS: | |
2492 | case N_ABS | N_EXT: | |
2493 | /* | |
2494 | * Don't know why this code would occur, but | |
2495 | * apparently it does. | |
2496 | */ | |
2497 | break; | |
2498 | ||
2499 | default: | |
2500 | fatal_with_file( | |
2501 | "nonexternal relocation code invalid in ", entry); | |
2502 | } | |
2503 | ||
2504 | /* | |
2505 | * When building a shared object, these segment | |
2506 | * relocations need a "load address relative" | |
2507 | * RRS fixup. | |
2508 | */ | |
2509 | if (building_shared_object) { | |
2510 | r->r_address += dataseg? | |
2511 | entry->data_start_address: | |
2512 | entry->text_start_address; | |
27b6ced7 | 2513 | claim_rrs_segment_reloc(entry, r); |
1136f72d PR |
2514 | } |
2515 | } | |
fb459a62 | 2516 | |
1136f72d PR |
2517 | if (RELOC_PCREL_P(r)) |
2518 | relocation -= pc_relocation; | |
fb459a62 | 2519 | |
1136f72d | 2520 | md_relocate(r, relocation, data+addr, relocatable_output); |
fb459a62 | 2521 | |
fb459a62 | 2522 | } |
fb459a62 NW |
2523 | } |
2524 | \f | |
2525 | /* For relocatable_output only: write out the relocation, | |
2526 | relocating the addresses-to-be-relocated. */ | |
2527 | ||
80f25b52 | 2528 | void coptxtrel(), copdatrel(), assign_symbolnums(); |
fb459a62 NW |
2529 | |
2530 | void | |
2531 | write_rel () | |
2532 | { | |
80f25b52 | 2533 | int count = 0; |
1136f72d PR |
2534 | |
2535 | if (trace_files) | |
2536 | fprintf (stderr, "Writing text relocation:\n\n"); | |
2537 | ||
2538 | /* | |
2539 | * Assign each global symbol a sequence number, giving the order | |
2540 | * in which `write_syms' will write it. | |
2541 | * This is so we can store the proper symbolnum fields | |
2542 | * in relocation entries we write. | |
2543 | * | |
2544 | ||
2545 | /* BLECH - Assign number 0 to __DYNAMIC (!! Sun compatibility) */ | |
2546 | ||
2547 | if (dynamic_symbol->referenced) | |
2548 | dynamic_symbol->symbolnum = count++; | |
2549 | FOR_EACH_SYMBOL(i, sp) { | |
2550 | if (sp != dynamic_symbol && sp->referenced) { | |
2551 | sp->symbolnum = count++; | |
27b6ced7 JH |
2552 | if (sp->size) |
2553 | count++; | |
2554 | if (sp->alias) | |
2555 | count++; | |
1136f72d PR |
2556 | } |
2557 | } END_EACH_SYMBOL; | |
2558 | ||
27b6ced7 | 2559 | if (count != global_sym_count) |
1136f72d PR |
2560 | fatal ("internal error: write_rel: count = %d", count); |
2561 | ||
80f25b52 JH |
2562 | each_full_file (assign_symbolnums, &count); |
2563 | ||
1136f72d PR |
2564 | /* Write out the relocations of all files, remembered from copy_text. */ |
2565 | each_full_file (coptxtrel, 0); | |
2566 | ||
2567 | if (trace_files) | |
2568 | fprintf (stderr, "\nWriting data relocation:\n\n"); | |
2569 | ||
2570 | each_full_file (copdatrel, 0); | |
2571 | ||
2572 | if (trace_files) | |
2573 | fprintf (stderr, "\n"); | |
fb459a62 NW |
2574 | } |
2575 | ||
80f25b52 JH |
2576 | /* |
2577 | * Assign symbol ordinal numbers to local symbols in each entry. | |
2578 | */ | |
2579 | void | |
2580 | assign_symbolnums(entry, countp) | |
2581 | struct file_entry *entry; | |
2582 | int *countp; | |
2583 | { | |
2584 | struct localsymbol *lsp, *lspend; | |
2585 | int n = *countp; | |
2586 | ||
2587 | lspend = entry->symbols + entry->nsymbols; | |
2588 | ||
27b6ced7 JH |
2589 | if (discard_locals != DISCARD_ALL) |
2590 | /* Count the N_FN symbol for this entry */ | |
2591 | n++; | |
2592 | ||
80f25b52 | 2593 | for (lsp = entry->symbols; lsp < lspend; lsp++) { |
27b6ced7 JH |
2594 | if (lsp->write) |
2595 | lsp->symbolnum = n++; | |
80f25b52 JH |
2596 | } |
2597 | *countp = n; | |
2598 | } | |
2599 | ||
fb459a62 | 2600 | void |
1136f72d PR |
2601 | coptxtrel(entry) |
2602 | struct file_entry *entry; | |
fb459a62 | 2603 | { |
1136f72d PR |
2604 | register struct relocation_info *r, *end; |
2605 | register int reloc = entry->text_start_address; | |
fb459a62 | 2606 | |
1136f72d PR |
2607 | r = entry->textrel; |
2608 | end = r + entry->ntextrel; | |
2609 | ||
2610 | for (; r < end; r++) { | |
27b6ced7 JH |
2611 | register int symindex; |
2612 | struct localsymbol *lsp; | |
2613 | symbol *sp; | |
1136f72d PR |
2614 | |
2615 | RELOC_ADDRESS(r) += reloc; | |
2616 | ||
1136f72d | 2617 | symindex = RELOC_SYMBOL(r); |
27b6ced7 JH |
2618 | lsp = &entry->symbols[symindex]; |
2619 | ||
2620 | if (!RELOC_EXTERN_P(r)) { | |
2621 | if (!pic_code_seen) | |
2622 | continue; | |
2623 | if (RELOC_BASEREL_P(r)) | |
2624 | RELOC_SYMBOL(r) = lsp->symbolnum; | |
2625 | continue; | |
2626 | } | |
1136f72d PR |
2627 | |
2628 | if (symindex >= entry->nsymbols) | |
2629 | fatal_with_file( | |
2630 | "relocation symbolnum out of range in ", entry); | |
fb459a62 | 2631 | |
27b6ced7 JH |
2632 | sp = lsp->symbol; |
2633 | ||
fb459a62 | 2634 | #ifdef N_INDR |
1136f72d PR |
2635 | /* Resolve indirection. */ |
2636 | if ((sp->defined & ~N_EXT) == N_INDR) { | |
2637 | if (sp->alias == NULL) | |
2638 | fatal("internal error: alias in hyperspace"); | |
2639 | sp = sp->alias; | |
2640 | } | |
fb459a62 NW |
2641 | #endif |
2642 | ||
1136f72d PR |
2643 | /* |
2644 | * If the symbol is now defined, change the external | |
2645 | * relocation to an internal one. | |
2646 | */ | |
fb459a62 | 2647 | |
1136f72d | 2648 | if (sp->defined) { |
27b6ced7 JH |
2649 | if (!pic_code_seen) { |
2650 | RELOC_EXTERN_P(r) = 0; | |
2651 | RELOC_SYMBOL(r) = (sp->defined & N_TYPE); | |
2652 | } else | |
2653 | RELOC_SYMBOL(r) = sp->symbolnum; | |
fb459a62 | 2654 | #ifdef RELOC_ADD_EXTRA |
1136f72d PR |
2655 | /* |
2656 | * If we aren't going to be adding in the | |
2657 | * value in memory on the next pass of the | |
2658 | * loader, then we need to add it in from the | |
2659 | * relocation entry. Otherwise the work we | |
2660 | * did in this pass is lost. | |
2661 | */ | |
2662 | if (!RELOC_MEMORY_ADD_P(r)) | |
2663 | RELOC_ADD_EXTRA(r) += sp->value; | |
fb459a62 | 2664 | #endif |
1136f72d PR |
2665 | } else |
2666 | /* | |
2667 | * Global symbols come first. | |
2668 | */ | |
2669 | RELOC_SYMBOL(r) = sp->symbolnum; | |
fb459a62 | 2670 | } |
1136f72d PR |
2671 | md_swapout_reloc(entry->textrel, entry->ntextrel); |
2672 | mywrite(entry->textrel, entry->ntextrel, | |
2673 | sizeof(struct relocation_info), outdesc); | |
fb459a62 NW |
2674 | } |
2675 | ||
2676 | void | |
1136f72d PR |
2677 | copdatrel(entry) |
2678 | struct file_entry *entry; | |
fb459a62 | 2679 | { |
1136f72d PR |
2680 | register struct relocation_info *r, *end; |
2681 | /* | |
2682 | * Relocate the address of the relocation. Old address is relative to | |
2683 | * start of the input file's data section. New address is relative to | |
2684 | * start of the output file's data section. | |
2685 | */ | |
2686 | register int reloc = entry->data_start_address - text_size; | |
fb459a62 | 2687 | |
1136f72d PR |
2688 | r = entry->datarel; |
2689 | end = r + entry->ndatarel; | |
2690 | ||
2691 | for (; r < end; r++) { | |
2692 | register int symindex; | |
2693 | symbol *sp; | |
2694 | int symtype; | |
2695 | ||
2696 | RELOC_ADDRESS(r) += reloc; | |
2697 | ||
27b6ced7 JH |
2698 | if (!RELOC_EXTERN_P(r)) { |
2699 | if (RELOC_BASEREL_P(r)) | |
2700 | fatal_with_file( | |
2701 | "Unsupported relocation type in ", | |
2702 | entry); | |
1136f72d | 2703 | continue; |
27b6ced7 | 2704 | } |
1136f72d PR |
2705 | |
2706 | symindex = RELOC_SYMBOL(r); | |
2707 | sp = entry->symbols[symindex].symbol; | |
2708 | ||
2709 | if (symindex >= entry->header.a_syms) | |
2710 | fatal_with_file( | |
2711 | "relocation symbolnum out of range in ", entry); | |
fb459a62 NW |
2712 | |
2713 | #ifdef N_INDR | |
1136f72d PR |
2714 | /* Resolve indirection. */ |
2715 | if ((sp->defined & ~N_EXT) == N_INDR) { | |
2716 | if (sp->alias == NULL) | |
2717 | fatal("internal error: alias in hyperspace"); | |
2718 | sp = sp->alias; | |
2719 | } | |
fb459a62 NW |
2720 | #endif |
2721 | ||
1136f72d PR |
2722 | symtype = sp->defined & N_TYPE; |
2723 | ||
27b6ced7 | 2724 | if (!pic_code_seen && (force_common_definition || |
1136f72d PR |
2725 | symtype == N_DATA || |
2726 | symtype == N_TEXT || | |
27b6ced7 | 2727 | symtype == N_ABS)) { |
1136f72d PR |
2728 | RELOC_EXTERN_P(r) = 0; |
2729 | RELOC_SYMBOL(r) = symtype; | |
2730 | } else | |
2731 | /* | |
2732 | * Global symbols come first. | |
2733 | */ | |
2734 | RELOC_SYMBOL(r) = | |
2735 | entry->symbols[symindex].symbol->symbolnum; | |
fb459a62 | 2736 | } |
1136f72d PR |
2737 | md_swapout_reloc(entry->datarel, entry->ndatarel); |
2738 | mywrite(entry->datarel, entry->ndatarel, | |
2739 | sizeof(struct relocation_info), outdesc); | |
fb459a62 NW |
2740 | } |
2741 | \f | |
27b6ced7 JH |
2742 | void write_file_syms __P((struct file_entry *, int *)); |
2743 | void write_string_table __P((void)); | |
fb459a62 NW |
2744 | |
2745 | /* Offsets and current lengths of symbol and string tables in output file. */ | |
2746 | ||
2747 | int symbol_table_offset; | |
2748 | int symbol_table_len; | |
2749 | ||
2750 | /* Address in output file where string table starts. */ | |
2751 | int string_table_offset; | |
2752 | ||
2753 | /* Offset within string table | |
2754 | where the strings in `strtab_vector' should be written. */ | |
2755 | int string_table_len; | |
2756 | ||
2757 | /* Total size of string table strings allocated so far, | |
2758 | including strings in `strtab_vector'. */ | |
2759 | int strtab_size; | |
2760 | ||
2761 | /* Vector whose elements are strings to be added to the string table. */ | |
2762 | char **strtab_vector; | |
2763 | ||
2764 | /* Vector whose elements are the lengths of those strings. */ | |
2765 | int *strtab_lens; | |
2766 | ||
2767 | /* Index in `strtab_vector' at which the next string will be stored. */ | |
2768 | int strtab_index; | |
2769 | ||
1136f72d PR |
2770 | /* |
2771 | * Add the string NAME to the output file string table. Record it in | |
2772 | * `strtab_vector' to be output later. Return the index within the string | |
2773 | * table that this string will have. | |
2774 | */ | |
fb459a62 NW |
2775 | |
2776 | int | |
1136f72d PR |
2777 | assign_string_table_index(name) |
2778 | char *name; | |
fb459a62 | 2779 | { |
1136f72d PR |
2780 | register int index = strtab_size; |
2781 | register int len = strlen(name) + 1; | |
fb459a62 | 2782 | |
1136f72d PR |
2783 | strtab_size += len; |
2784 | strtab_vector[strtab_index] = name; | |
2785 | strtab_lens[strtab_index++] = len; | |
fb459a62 | 2786 | |
1136f72d | 2787 | return index; |
fb459a62 NW |
2788 | } |
2789 | ||
1136f72d | 2790 | FILE *outstream = (FILE *) 0; |
fb459a62 | 2791 | |
1136f72d PR |
2792 | /* |
2793 | * Write the contents of `strtab_vector' into the string table. This is done | |
2794 | * once for each file's local&debugger symbols and once for the global | |
2795 | * symbols. | |
2796 | */ | |
fb459a62 NW |
2797 | void |
2798 | write_string_table () | |
2799 | { | |
1136f72d | 2800 | register int i; |
fb459a62 | 2801 | |
1136f72d | 2802 | lseek (outdesc, string_table_offset + string_table_len, 0); |
fb459a62 | 2803 | |
1136f72d PR |
2804 | if (!outstream) |
2805 | outstream = fdopen (outdesc, "w"); | |
fb459a62 | 2806 | |
1136f72d PR |
2807 | for (i = 0; i < strtab_index; i++) { |
2808 | fwrite (strtab_vector[i], 1, strtab_lens[i], outstream); | |
2809 | string_table_len += strtab_lens[i]; | |
2810 | } | |
fb459a62 | 2811 | |
1136f72d | 2812 | fflush (outstream); |
fb459a62 | 2813 | |
1136f72d PR |
2814 | /* Report I/O error such as disk full. */ |
2815 | if (ferror (outstream)) | |
2816 | perror_name (output_filename); | |
fb459a62 NW |
2817 | } |
2818 | \f | |
2819 | /* Write the symbol table and string table of the output file. */ | |
2820 | ||
2821 | void | |
1136f72d PR |
2822 | write_syms() |
2823 | { | |
2824 | /* Number of symbols written so far. */ | |
1136f72d PR |
2825 | int syms_written = 0; |
2826 | struct nlist nl; | |
2827 | ||
2828 | /* | |
2829 | * Buffer big enough for all the global symbols. One extra struct | |
2830 | * for each indirect symbol to hold the extra reference following. | |
2831 | */ | |
27b6ced7 JH |
2832 | struct nlist *buf = (struct nlist *) |
2833 | alloca(global_sym_count * sizeof(struct nlist)); | |
1136f72d PR |
2834 | /* Pointer for storing into BUF. */ |
2835 | register struct nlist *bufp = buf; | |
2836 | ||
2837 | /* Size of string table includes the bytes that store the size. */ | |
2838 | strtab_size = sizeof strtab_size; | |
2839 | ||
2840 | symbol_table_offset = N_SYMOFF(outheader); | |
2841 | symbol_table_len = 0; | |
2842 | string_table_offset = N_STROFF(outheader); | |
2843 | string_table_len = strtab_size; | |
2844 | ||
2845 | if (strip_symbols == STRIP_ALL) | |
2846 | return; | |
2847 | ||
2848 | /* First, write out the global symbols. */ | |
2849 | ||
2850 | /* | |
2851 | * Allocate two vectors that record the data to generate the string | |
2852 | * table from the global symbols written so far. This must include | |
2853 | * extra space for the references following indirect outputs. | |
2854 | */ | |
2855 | ||
27b6ced7 JH |
2856 | strtab_vector = (char **) alloca((global_sym_count) * sizeof(char *)); |
2857 | strtab_lens = (int *) alloca((global_sym_count) * sizeof(int)); | |
1136f72d PR |
2858 | strtab_index = 0; |
2859 | ||
2860 | /* | |
2861 | * __DYNAMIC symbol *must* be first for Sun compatibility, as Sun's | |
2862 | * ld.so reads the shared object's first symbol. This means that | |
2863 | * (Sun's) shared libraries cannot be stripped! (We only assume | |
2864 | * that __DYNAMIC is the first item in the data segment) | |
2865 | * | |
2866 | * If defined (ie. not relocatable_output), make it look | |
2867 | * like an internal symbol. | |
2868 | */ | |
2869 | if (dynamic_symbol->referenced) { | |
2870 | nl.n_other = 0; | |
2871 | nl.n_desc = 0; | |
2872 | nl.n_type = dynamic_symbol->defined; | |
2873 | if (nl.n_type == N_UNDF) | |
2874 | nl.n_type |= N_EXT; | |
fb459a62 | 2875 | else |
1136f72d PR |
2876 | nl.n_type &= ~N_EXT; |
2877 | nl.n_value = dynamic_symbol->value; | |
2878 | nl.n_un.n_strx = assign_string_table_index(dynamic_symbol->name); | |
2879 | *bufp++ = nl; | |
fb459a62 | 2880 | syms_written++; |
fb459a62 | 2881 | } |
fb459a62 | 2882 | |
1136f72d PR |
2883 | /* Scan the symbol hash table, bucket by bucket. */ |
2884 | ||
2885 | FOR_EACH_SYMBOL(i, sp) { | |
2886 | if (sp == dynamic_symbol) | |
2887 | /* Already dealt with above */ | |
2888 | continue; | |
2889 | ||
2890 | if (!sp->referenced) | |
2891 | /* Came from shared object but was not used */ | |
2892 | continue; | |
2893 | ||
2894 | if (sp->so_defined) | |
2895 | /* | |
2896 | * Definition came from shared object, | |
2897 | * don't mention it here | |
2898 | */ | |
2899 | continue; | |
2900 | ||
2901 | if (!sp->defined && !relocatable_output) { | |
2902 | /* | |
2903 | * We're building a shared object and there | |
2904 | * are still undefined symbols. Don't output | |
2905 | * these, symbol was discounted in digest_pass1() | |
2906 | * (they are in the RRS symbol table). | |
2907 | */ | |
2908 | if (!building_shared_object) | |
2909 | error("symbol %s remains undefined", sp->name); | |
2910 | continue; | |
2911 | } | |
fb459a62 | 2912 | |
1136f72d PR |
2913 | /* Construct a `struct nlist' for the symbol. */ |
2914 | ||
2915 | nl.n_other = 0; | |
2916 | nl.n_desc = 0; | |
2917 | ||
2918 | /* | |
2919 | * common condition needs to be before undefined | |
2920 | * condition because unallocated commons are set | |
2921 | * undefined in digest_symbols | |
2922 | */ | |
2923 | if (sp->defined > 1) { | |
2924 | /* defined with known type */ | |
2925 | ||
2926 | if (!relocatable_output && sp->alias && | |
2927 | sp->alias->defined > 1) { | |
2928 | /* | |
2929 | * If the target of an indirect symbol has | |
2930 | * been defined and we are outputting an | |
2931 | * executable, resolve the indirection; it's | |
2932 | * no longer needed | |
2933 | */ | |
2934 | nl.n_type = sp->alias->defined; | |
2935 | nl.n_type = sp->alias->value; | |
2936 | } else if (sp->defined == N_SIZE) | |
2937 | nl.n_type = N_DATA | N_EXT; | |
2938 | else | |
2939 | nl.n_type = sp->defined; | |
2940 | nl.n_value = sp->value; | |
2941 | } else if (sp->max_common_size) { | |
2942 | /* | |
2943 | * defined as common but not allocated, | |
2944 | * happens only with -r and not -d, write out | |
2945 | * a common definition | |
2946 | */ | |
2947 | nl.n_type = N_UNDF | N_EXT; | |
2948 | nl.n_value = sp->max_common_size; | |
2949 | } else if (!sp->defined) { | |
2950 | /* undefined -- legit only if -r */ | |
2951 | nl.n_type = N_UNDF | N_EXT; | |
2952 | nl.n_value = 0; | |
2953 | } else | |
2954 | fatal( | |
2955 | "internal error: %s defined in mysterious way", | |
2956 | sp->name); | |
2957 | ||
2958 | /* | |
2959 | * Allocate string table space for the symbol name. | |
2960 | */ | |
2961 | ||
2962 | nl.n_un.n_strx = assign_string_table_index(sp->name); | |
2963 | ||
2964 | /* Output to the buffer and count it. */ | |
2965 | ||
27b6ced7 | 2966 | if (syms_written >= global_sym_count) |
1136f72d PR |
2967 | fatal( |
2968 | "internal error: number of symbols exceeds allocated %d", | |
27b6ced7 | 2969 | global_sym_count); |
1136f72d PR |
2970 | *bufp++ = nl; |
2971 | syms_written++; | |
fb459a62 | 2972 | |
1136f72d PR |
2973 | if (nl.n_type == N_INDR + N_EXT) { |
2974 | if (sp->alias == NULL) | |
2975 | fatal("internal error: alias in hyperspace"); | |
2976 | nl.n_type = N_UNDF + N_EXT; | |
2977 | nl.n_un.n_strx = | |
2978 | assign_string_table_index(sp->alias->name); | |
2979 | nl.n_value = 0; | |
27b6ced7 JH |
2980 | nl.n_other = 0; |
2981 | nl.n_desc = 0; | |
2982 | *bufp++ = nl; | |
2983 | syms_written++; | |
2984 | } | |
2985 | ||
2986 | if (relocatable_output && sp->size) { | |
2987 | nl.n_type = N_SIZE + N_EXT; | |
2988 | nl.n_un.n_strx = assign_string_table_index(sp->name); | |
2989 | nl.n_value = sp->size; | |
2990 | nl.n_other = 0; | |
2991 | nl.n_desc = 0; | |
1136f72d PR |
2992 | *bufp++ = nl; |
2993 | syms_written++; | |
2994 | } | |
fb459a62 | 2995 | |
1136f72d PR |
2996 | #ifdef DEBUG |
2997 | printf("writesym(#%d): %s, type %x\n", syms_written, sp->name, sp->defined); | |
fb459a62 | 2998 | #endif |
1136f72d | 2999 | } END_EACH_SYMBOL; |
fb459a62 | 3000 | |
27b6ced7 | 3001 | if (syms_written != strtab_index || strtab_index != global_sym_count) |
1136f72d PR |
3002 | fatal("internal error:\ |
3003 | wrong number (%d) of global symbols written into output file, should be %d", | |
27b6ced7 | 3004 | syms_written, global_sym_count); |
fb459a62 | 3005 | |
1136f72d | 3006 | /* Output the buffer full of `struct nlist's. */ |
fb459a62 | 3007 | |
1136f72d PR |
3008 | lseek(outdesc, symbol_table_offset + symbol_table_len, 0); |
3009 | md_swapout_symbols(buf, bufp - buf); | |
3010 | mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc); | |
3011 | symbol_table_len += sizeof(struct nlist) * (bufp - buf); | |
fb459a62 | 3012 | |
1136f72d PR |
3013 | /* Write the strings for the global symbols. */ |
3014 | write_string_table(); | |
fb459a62 | 3015 | |
1136f72d PR |
3016 | /* Write the local symbols defined by the various files. */ |
3017 | each_file(write_file_syms, &syms_written); | |
3018 | file_close(); | |
fb459a62 | 3019 | |
1136f72d PR |
3020 | if (syms_written != nsyms) |
3021 | fatal("internal error:\ | |
3022 | wrong number of symbols (%d) written into output file, should be %d", | |
3023 | syms_written, nsyms); | |
fb459a62 | 3024 | |
1136f72d PR |
3025 | if (symbol_table_offset + symbol_table_len != string_table_offset) |
3026 | fatal( | |
3027 | "internal error: inconsistent symbol table length: %d vs %s", | |
3028 | symbol_table_offset + symbol_table_len, string_table_offset); | |
fb459a62 | 3029 | |
1136f72d PR |
3030 | lseek(outdesc, string_table_offset, 0); |
3031 | strtab_size = md_swap_long(strtab_size); | |
3032 | mywrite(&strtab_size, sizeof(int), 1, outdesc); | |
fb459a62 NW |
3033 | } |
3034 | ||
fb459a62 | 3035 | |
1136f72d PR |
3036 | /* |
3037 | * Write the local and debugger symbols of file ENTRY. Increment | |
3038 | * *SYMS_WRITTEN_ADDR for each symbol that is written. | |
3039 | */ | |
fb459a62 | 3040 | |
1136f72d PR |
3041 | /* |
3042 | * Note that we do not combine identical names of local symbols. dbx or gdb | |
3043 | * would be confused if we did that. | |
3044 | */ | |
fb459a62 | 3045 | void |
1136f72d PR |
3046 | write_file_syms(entry, syms_written_addr) |
3047 | struct file_entry *entry; | |
3048 | int *syms_written_addr; | |
fb459a62 | 3049 | { |
1136f72d | 3050 | struct localsymbol *lsp, *lspend; |
fb459a62 | 3051 | |
1136f72d PR |
3052 | /* Upper bound on number of syms to be written here. */ |
3053 | int max_syms = entry->nsymbols + 1; | |
fb459a62 | 3054 | |
1136f72d PR |
3055 | /* |
3056 | * Buffer to accumulate all the syms before writing them. It has one | |
3057 | * extra slot for the local symbol we generate here. | |
3058 | */ | |
3059 | struct nlist *buf = (struct nlist *) | |
3060 | alloca(max_syms * sizeof(struct nlist)); | |
fb459a62 | 3061 | |
1136f72d | 3062 | register struct nlist *bufp = buf; |
fb459a62 | 3063 | |
1136f72d PR |
3064 | if (entry->is_dynamic) |
3065 | return; | |
fb459a62 | 3066 | |
1136f72d PR |
3067 | /* |
3068 | * Make tables that record, for each symbol, its name and its name's | |
3069 | * length. The elements are filled in by `assign_string_table_index'. | |
3070 | */ | |
fb459a62 | 3071 | |
1136f72d PR |
3072 | strtab_vector = (char **) alloca(max_syms * sizeof(char *)); |
3073 | strtab_lens = (int *) alloca(max_syms * sizeof(int)); | |
3074 | strtab_index = 0; | |
fb459a62 | 3075 | |
1136f72d | 3076 | /* Generate a local symbol for the start of this file's text. */ |
fb459a62 | 3077 | |
1136f72d PR |
3078 | if (discard_locals != DISCARD_ALL) { |
3079 | struct nlist nl; | |
fb459a62 | 3080 | |
1136f72d PR |
3081 | nl.n_type = N_FN | N_EXT; |
3082 | nl.n_un.n_strx = assign_string_table_index(entry->local_sym_name); | |
3083 | nl.n_value = entry->text_start_address; | |
3084 | nl.n_desc = 0; | |
3085 | nl.n_other = 0; | |
3086 | *bufp++ = nl; | |
3087 | (*syms_written_addr)++; | |
27b6ced7 | 3088 | #if 0 |
1136f72d | 3089 | entry->local_syms_offset = *syms_written_addr * sizeof(struct nlist); |
27b6ced7 | 3090 | #endif |
1136f72d PR |
3091 | } |
3092 | /* Read the file's string table. */ | |
3093 | ||
3094 | entry->strings = (char *) alloca(entry->string_size); | |
3095 | read_entry_strings(file_open(entry), entry); | |
3096 | ||
3097 | lspend = entry->symbols + entry->nsymbols; | |
3098 | ||
3099 | for (lsp = entry->symbols; lsp < lspend; lsp++) { | |
3100 | register struct nlist *p = &lsp->nzlist.nlist; | |
3101 | register int type = p->n_type; | |
3102 | register int write = 0; | |
80f25b52 JH |
3103 | char *name; |
3104 | ||
27b6ced7 JH |
3105 | if (! lsp->write) |
3106 | continue; | |
3107 | ||
80f25b52 JH |
3108 | if (p->n_un.n_strx == 0) |
3109 | name = NULL; | |
3110 | else if (lsp->rename == 0) | |
3111 | name = p->n_un.n_strx + entry->strings; | |
3112 | else { | |
3113 | char *cp = p->n_un.n_strx + entry->strings; | |
3114 | name = (char *)alloca( | |
3115 | strlen(entry->local_sym_name) + | |
3116 | strlen(cp) + 2 ); | |
3117 | (void)sprintf(name, "%s.%s", entry->local_sym_name, cp); | |
80f25b52 | 3118 | } |
1136f72d PR |
3119 | |
3120 | /* | |
27b6ced7 JH |
3121 | * If this symbol has a name, allocate space for it |
3122 | * in the output string table. | |
1136f72d | 3123 | */ |
1136f72d | 3124 | |
27b6ced7 JH |
3125 | if (name) |
3126 | p->n_un.n_strx = assign_string_table_index(name); | |
1136f72d | 3127 | |
27b6ced7 | 3128 | /* Output this symbol to the buffer and count it. */ |
1136f72d | 3129 | |
27b6ced7 JH |
3130 | *bufp++ = *p; |
3131 | (*syms_written_addr)++; | |
1136f72d | 3132 | } |
fb459a62 | 3133 | |
1136f72d | 3134 | /* All the symbols are now in BUF; write them. */ |
fb459a62 | 3135 | |
1136f72d PR |
3136 | lseek(outdesc, symbol_table_offset + symbol_table_len, 0); |
3137 | md_swapout_symbols(buf, bufp - buf); | |
3138 | mywrite(buf, bufp - buf, sizeof(struct nlist), outdesc); | |
3139 | symbol_table_len += sizeof(struct nlist) * (bufp - buf); | |
fb459a62 | 3140 | |
1136f72d PR |
3141 | /* |
3142 | * Write the string-table data for the symbols just written, using | |
3143 | * the data in vectors `strtab_vector' and `strtab_lens'. | |
3144 | */ | |
fb459a62 | 3145 | |
1136f72d PR |
3146 | write_string_table(); |
3147 | entry->strings = 0; /* Since it will disappear anyway. */ | |
fb459a62 | 3148 | } |