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