summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/ld/ld.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2002-09-17 01:54:56 +0000
committerobrien <obrien@FreeBSD.org>2002-09-17 01:54:56 +0000
commitb58b89fc83e89a880dc747f252347d46a4dd4953 (patch)
treeb6b6d8cb20d6e54de2ab2460a8990997c9ba68c2 /gnu/usr.bin/ld/ld.c
parenta51c9b66271f0551fb83b90a7db6c464eac2318b (diff)
downloadFreeBSD-src-b58b89fc83e89a880dc747f252347d46a4dd4953.zip
FreeBSD-src-b58b89fc83e89a880dc747f252347d46a4dd4953.tar.gz
BANG! BANG! BANG! Put these bits out of their misery.
Murdered by members of: a.out.die.die.die ELF is the 1 true path now. So make good on the src/Makefile threat that building a.out will not be supported post 4.x. These bits should either resurface as a port, or a new port using the latest Binutils bits. The later will not support our SunOS-style shared a.out libs; but we shouldn't need such support by this point in time.
Diffstat (limited to 'gnu/usr.bin/ld/ld.c')
-rw-r--r--gnu/usr.bin/ld/ld.c3825
1 files changed, 0 insertions, 3825 deletions
diff --git a/gnu/usr.bin/ld/ld.c b/gnu/usr.bin/ld/ld.c
deleted file mode 100644
index 316df28..0000000
--- a/gnu/usr.bin/ld/ld.c
+++ /dev/null
@@ -1,3825 +0,0 @@
-/*-
- * This code is derived from software copyrighted by the Free Software
- * Foundation.
- *
- * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
- *
- * Modified 1993 by Paul Kranenburg, Erasmus University
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91";
-#endif /* not lint */
-
-/* Linker `ld' for GNU
- Copyright (C) 1988 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Richard Stallman with some help from Eric Albert.
- Set, indirect, and warning symbol features added by Randy Smith. */
-
-/*
- * $FreeBSD$
- */
-
-/* Define how to initialize system-dependent header fields. */
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <err.h>
-#include <fcntl.h>
-#include <ar.h>
-#include <ranlib.h>
-#include <a.out.h>
-#include <stab.h>
-#include <string.h>
-
-#include "ld.h"
-#include "dynamic.h"
-
-/* Vector of entries for input files specified by arguments.
- These are all the input files except for members of specified libraries. */
-struct file_entry *file_table;
-int number_of_files;
-
-/* 1 => write relocation into output file so can re-input it later. */
-int relocatable_output;
-
-/* 1 => building a shared object, set by `-Bshareable'. */
-int building_shared_object;
-
-/* 1 => create the output executable. */
-int make_executable;
-
-/* Force the executable to be output, even if there are non-fatal errors */
-int force_executable;
-
-/* 1 => assign space to common symbols even if `relocatable_output'. */
-int force_common_definition;
-
-/* 1 => assign jmp slots to text symbols in shared objects even if non-PIC */
-int force_alias_definition;
-
-/* 1 => some files contain PIC code, affects relocation bits
- if `relocatable_output'. */
-int pic_code_seen;
-
-/* 1 => segments must be page aligned (ZMAGIC, QMAGIC) */
-int page_align_segments;
-
-/* 1 => data segment must be page aligned, even if `-n' or `-N' */
-int page_align_data;
-
-/* 1 => do not use standard library search path */
-int nostdlib;
-
-/* Version number to put in __DYNAMIC (set by -V) */
-int soversion;
-
-int text_size; /* total size of text. */
-int text_start; /* start of text */
-int text_pad; /* clear space between text and data */
-int data_size; /* total size of data. */
-int data_start; /* start of data */
-int data_pad; /* part of bss segment as part of data */
-
-int bss_size; /* total size of bss. */
-int bss_start; /* start of bss */
-
-int text_reloc_size; /* total size of text relocation. */
-int data_reloc_size; /* total size of data relocation. */
-
-int rrs_section_type; /* What's in the RRS section */
-int rrs_text_size; /* Size of RRS text additions */
-int rrs_text_start; /* Location of above */
-int rrs_data_size; /* Size of RRS data additions */
-int rrs_data_start; /* Location of above */
-
-/* Specifications of start and length of the area reserved at the end
- of the data segment for the set vectors. Computed in 'digest_symbols' */
-int set_sect_start; /* start of set element vectors */
-int set_sect_size; /* size of above */
-
-int link_mode; /* Current link mode */
-int pic_type; /* PIC type */
-
-/*
- * When loading the text and data, we can avoid doing a close
- * and another open between members of the same library.
- *
- * These two variables remember the file that is currently open.
- * Both are zero if no file is open.
- *
- * See `each_file' and `file_close'.
- */
-struct file_entry *input_file;
-int input_desc;
-
-/* The name of the file to write; "a.out" by default. */
-char *output_filename; /* Output file name. */
-char *real_output_filename; /* Output file name. */
-FILE *outstream; /* Output file descriptor. */
-struct exec outheader; /* Output file header. */
-int magic; /* Output file magic. */
-int oldmagic;
-int relocatable_output; /* `-r'-ed output */
-
-symbol *entry_symbol; /* specified by `-e' */
-int entry_offset; /* program entry if no `-e' given */
-
-int page_size; /* Size of a page (machine dependent) */
-
-/*
- * Keep a list of any symbols referenced from the command line (so
- * that error messages for these guys can be generated). This list is
- * zero terminated.
- */
-symbol **cmdline_references;
-int cl_refs_allocated;
-
-/*
- * Which symbols should be stripped (omitted from the output): none, all, or
- * debugger symbols.
- */
-enum {
- STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER
-} strip_symbols;
-
-/*
- * Which local symbols should be omitted: none, all, or those starting with L.
- * This is irrelevant if STRIP_NONE.
- */
-enum {
- DISCARD_NONE, DISCARD_ALL, DISCARD_L
-} discard_locals;
-
-int global_sym_count; /* # of nlist entries for global symbols */
-int size_sym_count; /* # of N_SIZE nlist entries for output
- (relocatable_output only) */
-int local_sym_count; /* # of nlist entries for local symbols. */
-int non_L_local_sym_count; /* # of nlist entries for non-L symbols */
-int debugger_sym_count; /* # of nlist entries for debugger info. */
-int undefined_global_sym_count; /* # of global symbols referenced and
- not defined. */
-int undefined_shobj_sym_count; /* # of undefined symbols referenced
- by shared objects */
-int multiple_def_count; /* # of multiply defined symbols. */
-int defined_global_sym_count; /* # of defined global symbols. */
-int common_defined_global_count; /* # of common symbols. */
-int undefined_weak_sym_count; /* # of weak symbols referenced and
- not defined. */
-
-#if notused
-int special_sym_count; /* # of linker defined symbols. */
- /* XXX - Currently, only __DYNAMIC and _G_O_T_ go here if required,
- * perhaps _etext, _edata and _end should go here too.
- */
-#endif
-int global_alias_count; /* # of aliased symbols */
-int set_symbol_count; /* # of N_SET* symbols. */
-int set_vector_count; /* # of set vectors in output. */
-int warn_sym_count; /* # of warning symbols encountered. */
-int flag_list_files; /* 1 => print pathnames of files, don't link */
-int list_warning_symbols; /* 1 => warning symbols referenced */
-
-struct string_list_element *set_element_prefixes;
-
-int trace_files; /* print names of input files as processed (`-t'). */
-int write_map; /* write a load map (`-M') */
-
-/*
- * `text-start' address is normally this much plus a page boundary.
- * This is not a user option; it is fixed for each system.
- */
-int text_start_alignment;
-
-/*
- * Nonzero if -T was specified in the command line.
- * This prevents text_start from being set later to default values.
- */
-int T_flag_specified;
-
-/*
- * Nonzero if -Tdata was specified in the command line.
- * This prevents data_start from being set later to default values.
- */
-int Tdata_flag_specified;
-
-/*
- * Size to pad data section up to.
- * We simply increase the size of the data section, padding with zeros,
- * and reduce the size of the bss section to match.
- */
-int specified_data_size;
-
-long *set_vectors;
-int setv_fill_count;
-
-static void decode_option __P((char *, char *));
-static void decode_command __P((int, char **));
-static int classify_arg __P((char *));
-static void load_symbols __P((void));
-static void enter_global_ref __P((struct localsymbol *,
- char *, struct file_entry *));
-static void digest_symbols __P((void));
-static void digest_pass1 __P((void)), digest_pass2 __P((void));
-static void consider_file_section_lengths __P((struct file_entry *));
-static void relocate_file_addresses __P((struct file_entry *));
-static void consider_relocation __P((struct file_entry *, int));
-static void consider_local_symbols __P((struct file_entry *));
-static void perform_relocation __P((char *, int,
- struct relocation_info *, int,
- struct file_entry *, int));
-static void copy_text __P((struct file_entry *));
-static void copy_data __P((struct file_entry *));
-static void coptxtrel __P((struct file_entry *));
-static void copdatrel __P((struct file_entry *));
-static void write_output __P((void));
-static void write_header __P((void));
-static void write_text __P((void));
-static void write_data __P((void));
-static void write_rel __P((void));
-static void write_syms __P((void));
-static void assign_symbolnums __P((struct file_entry *, int *));
-static void cleanup __P((void));
-static int parse __P((char *, char *, char *));
-static void list_files __P((void));
-
-
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
-
- /* Added this to stop ld core-dumping on very large .o files. */
-#ifdef RLIMIT_STACK
- /* Get rid of any avoidable limit on stack size. */
- {
- struct rlimit rlim;
-
- /* Set the stack limit huge so that alloca does not fail. */
- if (getrlimit(RLIMIT_STACK, &rlim) != 0)
- warn("getrlimit");
- else {
- rlim.rlim_cur = rlim.rlim_max;
- if (setrlimit(RLIMIT_STACK, &rlim) != 0)
- warn("setrlimit");
- }
- }
-#endif /* RLIMIT_STACK */
-
- page_size = PAGSIZ;
-
- /* Clear the cumulative info on the output file. */
-
- text_size = 0;
- data_size = 0;
- bss_size = 0;
- text_reloc_size = 0;
- data_reloc_size = 0;
-
- data_pad = 0;
- text_pad = 0;
- page_align_segments = 0;
- page_align_data = 0;
-
- /* Initialize the data about options. */
-
- specified_data_size = 0;
- strip_symbols = STRIP_NONE;
- trace_files = 0;
- discard_locals = DISCARD_NONE;
- entry_symbol = 0;
- write_map = 0;
- relocatable_output = 0;
- force_common_definition = 0;
- T_flag_specified = 0;
- Tdata_flag_specified = 0;
- magic = DEFAULT_MAGIC;
- make_executable = 1;
- force_executable = 0;
- link_mode = DYNAMIC;
-#ifdef SUNOS4
- link_mode |= SILLYARCHIVE;
-#endif
- soversion = DEFAULT_SOVERSION;
-
- /* Initialize the cumulative counts of symbols. */
-
- local_sym_count = 0;
- non_L_local_sym_count = 0;
- debugger_sym_count = 0;
- undefined_global_sym_count = 0;
- warn_sym_count = 0;
- list_warning_symbols = 0;
- multiple_def_count = 0;
- common_defined_global_count = 0;
-
- /* Keep a list of symbols referenced from the command line */
- cl_refs_allocated = 10;
- cmdline_references = (symbol **)
- xmalloc(cl_refs_allocated * sizeof(symbol *));
- *cmdline_references = 0;
-
- /* Completely decode ARGV. */
- decode_command(argc, argv);
-
- if (flag_list_files)
- list_files();
-
- building_shared_object =
- (!relocatable_output && (link_mode & SHAREABLE));
-
- if (building_shared_object && entry_symbol) {
- errx(1,"`-Bshareable' and `-e' options are mutually exclusive");
- }
-
- /* Create the symbols `etext', `edata' and `end'. */
- symtab_init(relocatable_output);
-
- /*
- * Determine whether to count the header as part of the text size,
- * and initialize the text size accordingly. This depends on the kind
- * of system and on the output format selected.
- */
-
- if (magic == ZMAGIC || magic == QMAGIC)
- page_align_segments = 1;
-
- md_init_header(&outheader, magic, 0);
-
- text_size = sizeof(struct exec);
- text_size -= N_TXTOFF(outheader);
-
- if (text_size < 0)
- text_size = 0;
- entry_offset = text_size;
-
- if (!T_flag_specified && !relocatable_output)
- text_start = TEXT_START(outheader);
-
- /* The text-start address is normally this far past a page boundary. */
- text_start_alignment = text_start % page_size;
-
- /*
- * Load symbols of all input files. Also search all libraries and
- * decide which library members to load.
- */
- load_symbols();
-
- /* Compute where each file's sections go, and relocate symbols. */
- digest_symbols();
-
- /*
- * Print error messages for any missing symbols, for any warning
- * symbols, and possibly multiple definitions
- */
- make_executable &= do_warnings(stderr);
-
- /* Print a map, if requested. */
- if (write_map)
- print_symbols(stdout);
-
- /* Write the output file. */
- if (make_executable || force_executable)
- write_output();
-
- exit(!make_executable);
-}
-
-/*
- * Analyze a command line argument. Return 0 if the argument is a filename.
- * Return 1 if the argument is a option complete in itself. Return 2 if the
- * argument is a option which uses an argument.
- *
- * Thus, the value is the number of consecutive arguments that are part of
- * options.
- */
-
-static int
-classify_arg(arg)
- register char *arg;
-{
- if (*arg != '-')
- return 0;
- switch (arg[1]) {
- case 'a':
- if (!strcmp(&arg[2], "ssert"))
- return 2;
- case 'A':
- case 'D':
- case 'e':
- case 'L':
- case 'l':
- case 'O':
- case 'o':
- case 'R':
- case 'u':
- case 'V':
- case 'y':
- if (arg[2])
- return 1;
- return 2;
-
- case 'B':
- if (!strcmp(&arg[2], "static"))
- return 1;
- if (!strcmp(&arg[2], "dynamic"))
- return 1;
- if (!strcmp(&arg[2], "forcedynamic"))
- return 1;
-
- case 'T':
- if (arg[2] == 0)
- return 2;
- if (!strcmp(&arg[2], "text"))
- return 2;
- if (!strcmp(&arg[2], "data"))
- return 2;
- return 1;
- }
-
- return 1;
-}
-
-/*
- * Process the command arguments, setting up file_table with an entry for
- * each input file, and setting variables according to the options.
- */
-
-static void
-decode_command(argc, argv)
- int argc;
- char **argv;
-{
- register int i;
- register struct file_entry *p;
-
- number_of_files = 0;
- output_filename = "a.out";
-
- /*
- * First compute number_of_files so we know how long to make
- * file_table.
- * Also process most options completely.
- */
-
- for (i = 1; i < argc; i++) {
- register int code = classify_arg(argv[i]);
- if (code) {
- if (i + code > argc)
- errx(1, "no argument following %s", argv[i]);
-
- decode_option(argv[i], argv[i + 1]);
-
- if (argv[i][1] == 'l' || argv[i][1] == 'A')
- number_of_files++;
-
- i += code - 1;
- } else
- number_of_files++;
- }
-
- if (!number_of_files) {
- if (flag_list_files)
- exit(0);
- errx(1, "No input files specified");
- }
-
- p = file_table = (struct file_entry *)
- xmalloc(number_of_files * sizeof(struct file_entry));
- bzero(p, number_of_files * sizeof(struct file_entry));
-
- /* Now scan again and fill in file_table. */
- /* All options except -A and -l are ignored here. */
-
- for (i = 1; i < argc; i++) {
- char *string;
- register int code = classify_arg(argv[i]);
-
- if (code == 0) {
- p->filename = argv[i];
- p->local_sym_name = argv[i];
- p++;
- continue;
- }
- if (code == 2)
- string = argv[i + 1];
- else
- string = &argv[i][2];
-
- if (argv[i][1] == 'B') {
- if (strcmp(string, "static") == 0)
- link_mode &= ~DYNAMIC;
- else if (strcmp(string, "dynamic") == 0)
- link_mode |= DYNAMIC;
- else if (strcmp(string, "forcedynamic") == 0)
- link_mode |= DYNAMIC|FORCEDYNAMIC;
- else if (strcmp(string, "symbolic") == 0)
- link_mode |= SYMBOLIC;
- else if (strcmp(string, "forcearchive") == 0)
- link_mode |= FORCEARCHIVE;
- else if (strcmp(string, "shareable") == 0)
- link_mode |= SHAREABLE;
-#ifdef SUN_COMPAT
- else if (strcmp(string, "silly") == 0)
- link_mode |= SILLYARCHIVE;
- else if (strcmp(string, "~silly") == 0)
- link_mode &= ~SILLYARCHIVE;
-#endif
- }
- if (!strcmp(argv[i] + 1, "assert")) {
- if (!strcmp(string, "pure-text"))
- link_mode |= WARNRRSTEXT;
- }
- if (argv[i][1] == 'A') {
- if (p != file_table)
- errx(1, "-A specified before an input file other than the first");
- p->filename = string;
- p->local_sym_name = string;
- p->flags |= E_JUST_SYMS;
- link_mode &= ~DYNAMIC;
- p++;
- }
- if (argv[i][1] == 'l') {
- p->filename = string;
- p->local_sym_name = concat("-l", string, "");
- p->flags |= E_SEARCH_DIRS;
- if (link_mode & DYNAMIC && !relocatable_output)
- p->flags |= E_SEARCH_DYNAMIC;
- p++;
- }
- i += code - 1;
- }
-
- /* Now check some option settings for consistency. */
-
- if (page_align_segments &&
- (text_start - text_start_alignment) & (page_size - 1))
- errx(1, "incorrect alignment of text start address");
-
- /* Append the standard search directories to the user-specified ones. */
- add_search_path(getenv("LD_LIBRARY_PATH"));
- if (!nostdlib)
- std_search_path();
-}
-
-void
-add_cmdline_ref(sp)
- symbol *sp;
-{
- symbol **ptr;
-
- for (ptr = cmdline_references;
- ptr < cmdline_references + cl_refs_allocated && *ptr;
- ptr++);
-
- if (ptr >= cmdline_references + cl_refs_allocated - 1) {
- int diff = ptr - cmdline_references;
-
- cl_refs_allocated *= 2;
- cmdline_references = (symbol **)
- xrealloc(cmdline_references,
- cl_refs_allocated * sizeof(symbol *));
- ptr = cmdline_references + diff;
- }
- *ptr++ = sp;
- *ptr = (symbol *)0;
-}
-
-int
-set_element_prefixed_p(name)
- char *name;
-{
- struct string_list_element *p;
- int i;
-
- for (p = set_element_prefixes; p; p = p->next) {
-
- for (i = 0; p->str[i] != '\0' && (p->str[i] == name[i]); i++);
- if (p->str[i] == '\0')
- return 1;
- }
- return 0;
-}
-
-/*
- * Record an option and arrange to act on it later. ARG should be the
- * following command argument, which may or may not be used by this option.
- *
- * The `l' and `A' options are ignored here since they actually specify input
- * files.
- */
-
-static void
-decode_option(swt, arg)
- register char *swt, *arg;
-{
- if (!strcmp(swt + 1, "Bstatic"))
- return;
- if (!strcmp(swt + 1, "Bdynamic"))
- return;
- if (!strcmp(swt + 1, "Bforcedynamic"))
- return;
- if (!strcmp(swt + 1, "Bsymbolic"))
- return;
- if (!strcmp(swt + 1, "Bforcearchive"))
- return;
- if (!strcmp(swt + 1, "Bshareable"))
- return;
- if (!strcmp(swt + 1, "assert"))
- return;
-#ifdef SUN_COMPAT
- if (!strcmp(swt + 1, "Bsilly"))
- return;
-#endif
- if (!strcmp(swt + 1, "Ttext")) {
- text_start = parse(arg, "%x", "invalid argument to -Ttext");
- T_flag_specified = 1;
- return;
- }
- if (!strcmp(swt + 1, "Tdata")) {
- rrs_data_start = parse(arg, "%x", "invalid argument to -Tdata");
- Tdata_flag_specified = 1;
- return;
- }
- if (!strcmp(swt + 1, "noinhibit-exec")) {
- force_executable = 1;
- return;
- }
- if (!strcmp(swt + 1, "nostdlib")) {
- nostdlib = 1;
- return;
- }
- if (swt[2] != 0)
- arg = &swt[2];
-
- switch (swt[1]) {
- case 'A':
- return;
-
- case 'D':
- specified_data_size = parse(arg, "%x", "invalid argument to -D");
- return;
-
- case 'd':
- if (swt[2] == 0 || *arg == 'c')
- force_common_definition = 1;
- else if (*arg == 'p')
- force_alias_definition = 1;
- else
- errx(1, "-d option takes 'c' or 'p' argument");
- return;
-
- case 'e':
- entry_symbol = getsym(arg);
- if (!entry_symbol->defined &&
- !(entry_symbol->flags & GS_REFERENCED))
- undefined_global_sym_count++;
- entry_symbol->flags |= GS_REFERENCED;
- add_cmdline_ref(entry_symbol);
- return;
-
- case 'f':
- flag_list_files = 1;
- return;
-
- case 'l':
- return;
-
- case 'L':
- add_search_dir(arg);
- return;
-
- case 'M':
- write_map = 1;
- return;
-
- case 'N':
- magic = OMAGIC;
- return;
-
- case 'n':
- magic = NMAGIC;
- return;
-
- case 'O':
- output_filename = xmalloc(strlen(arg)+5);
- strcpy(output_filename, arg);
- strcat(output_filename, ".tmp");
- real_output_filename = arg;
- return;
-
- case 'o':
- output_filename = arg;
- return;
-
- case 'p':
- page_align_data = 1;
- return;
-
-#ifdef QMAGIC
- case 'Q':
- magic = QMAGIC;
- return;
-#endif
-
- case 'r':
- relocatable_output = 1;
- magic = OMAGIC;
- text_start = 0;
- return;
-
- case 'R':
- rrs_search_paths = (rrs_search_paths == NULL)
- ? strdup(arg)
- : concat(rrs_search_paths, ":", arg);
- return;
-
- case 'S':
- strip_symbols = STRIP_DEBUGGER;
- return;
-
- case 's':
- strip_symbols = STRIP_ALL;
- return;
-
- case 'T':
- text_start = parse(arg, "%x", "invalid argument to -T");
- T_flag_specified = 1;
- return;
-
- case 't':
- trace_files = 1;
- return;
-
- case 'u':
- {
- register symbol *sp = getsym(arg);
-
- if (!sp->defined && !(sp->flags & GS_REFERENCED))
- undefined_global_sym_count++;
- sp->flags |= GS_REFERENCED;
- add_cmdline_ref(sp);
- }
- return;
-
-#if 1
- case 'V':
- soversion = parse(arg, "%d", "invalid argument to -V");
- return;
-#endif
-
- case 'X':
- discard_locals = DISCARD_L;
- return;
-
- case 'x':
- discard_locals = DISCARD_ALL;
- return;
-
- case 'y':
- {
- register symbol *sp = getsym(&swt[2]);
- sp->flags |= GS_TRACE;
- }
- return;
-
- case 'z':
- magic = ZMAGIC;
- oldmagic = 0;
-#ifdef __FreeBSD__
- netzmagic = 1;
-#endif
- return;
-
- case 'Z':
- magic = oldmagic = ZMAGIC;
-#ifdef __FreeBSD__
- netzmagic = 0;
-#endif
- return;
-
- default:
- errx(1, "invalid command option `%s'", swt);
- }
-}
-
-/* Convenient functions for operating on one or all files being loaded. */
-
-/*
- * Call FUNCTION on each input file entry. Do not call for entries for
- * libraries; instead, call once for each library member that is being
- * loaded.
- *
- * FUNCTION receives two arguments: the entry, and ARG.
- */
-
-void
-each_file(function, arg)
- register void (*function)();
- register void *arg;
-{
- register int i;
-
- for (i = 0; i < number_of_files; i++) {
- register struct file_entry *entry = &file_table[i];
- register struct file_entry *subentry;
-
- if (entry->flags & E_SCRAPPED)
- continue;
-
- if (!(entry->flags & E_IS_LIBRARY))
- (*function)(entry, arg);
-
- subentry = entry->subfiles;
- for (; subentry; subentry = subentry->chain) {
- if (subentry->flags & E_SCRAPPED)
- continue;
- (*function)(subentry, arg);
- }
-
-#ifdef SUN_COMPAT
- if (entry->silly_archive) {
-
- if (!(entry->flags & E_DYNAMIC))
- warnx("Silly");
-
- if (!(entry->silly_archive->flags & E_IS_LIBRARY))
- warnx("Sillier");
-
- subentry = entry->silly_archive->subfiles;
- for (; subentry; subentry = subentry->chain) {
- if (subentry->flags & E_SCRAPPED)
- continue;
- (*function)(subentry, arg);
- }
- }
-#endif
- }
-}
-
-/*
- * Call FUNCTION on each input file entry until it returns a non-zero value.
- * Return this value. Do not call for entries for libraries; instead, call
- * once for each library member that is being loaded.
- *
- * FUNCTION receives two arguments: the entry, and ARG. It must be a function
- * returning unsigned long (though this can probably be fudged).
- */
-
-unsigned long
-check_each_file(function, arg)
- register unsigned long (*function)();
- register void *arg;
-{
- register int i;
- register unsigned long return_val;
-
- for (i = 0; i < number_of_files; i++) {
- register struct file_entry *entry = &file_table[i];
- if (entry->flags & E_SCRAPPED)
- continue;
- if (entry->flags & E_IS_LIBRARY) {
- register struct file_entry *subentry = entry->subfiles;
- for (; subentry; subentry = subentry->chain) {
- if (subentry->flags & E_SCRAPPED)
- continue;
- if ( (return_val = (*function)(subentry, arg)) )
- return return_val;
- }
- } else if ( (return_val = (*function)(entry, arg)) )
- return return_val;
- }
- return 0;
-}
-
-/* Like `each_file' but ignore files that were just for symbol definitions. */
-
-void
-each_full_file(function, arg)
- register void (*function)();
- register void *arg;
-{
- register int i;
-
- for (i = 0; i < number_of_files; i++) {
- register struct file_entry *entry = &file_table[i];
- register struct file_entry *subentry;
-
- if (entry->flags & (E_SCRAPPED | E_JUST_SYMS))
- continue;
-
-#ifdef SUN_COMPAT
- if (entry->silly_archive) {
-
- if (!(entry->flags & E_DYNAMIC))
- warnx("Silly");
-
- if (!(entry->silly_archive->flags & E_IS_LIBRARY))
- warnx("Sillier");
-
- subentry = entry->silly_archive->subfiles;
- for (; subentry; subentry = subentry->chain) {
- if (subentry->flags & E_SCRAPPED)
- continue;
- (*function)(subentry, arg);
- }
- }
-#endif
- if (entry->flags & E_DYNAMIC)
- continue;
-
- if (!(entry->flags & E_IS_LIBRARY))
- (*function)(entry, arg);
-
- subentry = entry->subfiles;
- for (; subentry; subentry = subentry->chain) {
- if (subentry->flags & E_SCRAPPED)
- continue;
- (*function)(subentry, arg);
- }
-
- }
-}
-
-/* Close the input file that is now open. */
-
-void
-file_close()
-{
- close(input_desc);
- input_desc = 0;
- input_file = 0;
-}
-
-/*
- * Open the input file specified by 'entry', and return a descriptor. The
- * open file is remembered; if the same file is opened twice in a row, a new
- * open is not actually done.
- */
-int
-file_open(entry)
- register struct file_entry *entry;
-{
- register int fd;
-
- if (entry->superfile && (entry->superfile->flags & E_IS_LIBRARY))
- return file_open(entry->superfile);
-
- if (entry == input_file)
- return input_desc;
-
- if (input_file)
- file_close();
-
- if (entry->flags & E_SEARCH_DIRS) {
- fd = findlib(entry);
- } else
- fd = open(entry->filename, O_RDONLY, 0);
-
- if (fd >= 0) {
- input_file = entry;
- input_desc = fd;
- return fd;
- }
-
- if (entry->flags & E_SEARCH_DIRS)
- errx(1, "%s: no match", entry->local_sym_name);
- else
- err(1, "%s", entry->filename);
- return fd;
-}
-
-int
-text_offset(entry)
- struct file_entry *entry;
-{
- return entry->starting_offset + N_TXTOFF (entry->header);
-}
-
-/*---------------------------------------------------------------------------*/
-
-/*
- * Read a file's header into the proper place in the file_entry. FD is the
- * descriptor on which the file is open. ENTRY is the file's entry.
- */
-void
-read_header(fd, entry)
- int fd;
- struct file_entry *entry;
-{
- register int len;
-
- if (lseek(fd, entry->starting_offset, L_SET) !=
- entry->starting_offset)
- err(1, "%s: read_header: lseek", get_file_name(entry));
-
- len = read(fd, &entry->header, sizeof(struct exec));
- if (len != sizeof (struct exec))
- err(1, "%s: read_header: read", get_file_name(entry));
-
- md_swapin_exec_hdr(&entry->header);
-
- if (N_BADMAG (entry->header))
- errx(1, "%s: bad magic", get_file_name(entry));
-
- if (N_BADMID(entry->header))
- errx(1, "%s: non-native input file", get_file_name(entry));
-
- entry->flags |= E_HEADER_VALID;
-}
-
-/*
- * Read the symbols of file ENTRY into core. Assume it is already open, on
- * descriptor FD. Also read the length of the string table, which follows
- * the symbol table, but don't read the contents of the string table.
- */
-
-void
-read_entry_symbols(fd, entry)
- struct file_entry *entry;
- int fd;
-{
- int str_size;
- struct nlist *np;
- int i;
-
- if (!(entry->flags & E_HEADER_VALID))
- read_header(fd, entry);
-
- np = (struct nlist *)alloca(entry->header.a_syms);
- entry->nsymbols = entry->header.a_syms / sizeof(struct nlist);
- if (entry->nsymbols == 0)
- return;
-
- entry->symbols = (struct localsymbol *)
- xmalloc(entry->nsymbols * sizeof(struct localsymbol));
-
- if (lseek(fd, N_SYMOFF(entry->header) + entry->starting_offset, L_SET)
- != N_SYMOFF(entry->header) + entry->starting_offset)
- err(1, "%s: read_symbols: lseek(syms)", get_file_name(entry));
-
- if (entry->header.a_syms != read(fd, np, entry->header.a_syms))
- errx(1, "%s: read_symbols: premature end of file in symbols",
- get_file_name(entry));
-
- md_swapin_symbols(np, entry->header.a_syms / sizeof(struct nlist));
-
- for (i = 0; i < entry->nsymbols; i++) {
- entry->symbols[i].nzlist.nlist = *np++;
- entry->symbols[i].nzlist.nz_size = 0;
- entry->symbols[i].symbol = NULL;
- entry->symbols[i].next = NULL;
- entry->symbols[i].entry = entry;
- entry->symbols[i].gotslot_offset = -1;
- entry->symbols[i].flags = 0;
- }
-
- entry->strings_offset = N_STROFF(entry->header) +
- entry->starting_offset;
- if (lseek(fd, entry->strings_offset, 0) == (off_t)-1)
- err(1, "%s: read_symbols: lseek(strings)",
- get_file_name(entry));
- if (sizeof str_size != read(fd, &str_size, sizeof str_size))
- errx(1, "%s: read_symbols: cannot read string table size",
- get_file_name(entry));
-
- entry->string_size = md_swap_long(str_size);
-}
-
-/*
- * Read the string table of file ENTRY open on descriptor FD, into core.
- */
-void
-read_entry_strings(fd, entry)
- struct file_entry *entry;
- int fd;
-{
-
- if (entry->string_size == 0)
- return;
-
- if (!(entry->flags & E_HEADER_VALID) || !entry->strings_offset)
- errx(1, "%s: read_strings: string table unavailable",
- get_file_name(entry));
-
- if (lseek(fd, entry->strings_offset, L_SET) !=
- entry->strings_offset)
- err(1, "%s: read_strings: lseek",
- get_file_name(entry));
-
- if (read(fd, entry->strings, entry->string_size) !=
- entry->string_size)
- errx(1, "%s: read_strings: premature end of file in strings",
- get_file_name(entry));
-
- return;
-}
-
-/* Read in the relocation sections of ENTRY if necessary */
-
-void
-read_entry_relocation(fd, entry)
- int fd;
- struct file_entry *entry;
-{
- register struct relocation_info *reloc;
- off_t pos;
-
- if (!entry->textrel) {
-
- reloc = (struct relocation_info *)
- xmalloc(entry->header.a_trsize);
-
- pos = text_offset(entry) +
- entry->header.a_text + entry->header.a_data;
-
- if (lseek(fd, pos, L_SET) != pos)
- err(1, "%s: read_reloc(text): lseek",
- get_file_name(entry));
-
- if (read(fd, reloc, entry->header.a_trsize) !=
- entry->header.a_trsize)
- errx(1, "%s: read_reloc(text): premature EOF",
- get_file_name(entry));
-
- md_swapin_reloc(reloc, entry->header.a_trsize / sizeof(*reloc));
- entry->textrel = reloc;
- entry->ntextrel = entry->header.a_trsize / sizeof(*reloc);
-
- }
-
- if (!entry->datarel) {
-
- reloc = (struct relocation_info *)
- xmalloc(entry->header.a_drsize);
-
- pos = text_offset(entry) + entry->header.a_text +
- entry->header.a_data + entry->header.a_trsize;
-
- if (lseek(fd, pos, L_SET) != pos)
- err(1, "%s: read_reloc(data): lseek",
- get_file_name(entry));
-
- if (read(fd, reloc, entry->header.a_drsize) !=
- entry->header.a_drsize)
- errx(1, "%s: read_reloc(data): premature EOF",
- get_file_name(entry));
-
- md_swapin_reloc(reloc, entry->header.a_drsize / sizeof(*reloc));
- entry->datarel = reloc;
- entry->ndatarel = entry->header.a_drsize / sizeof(*reloc);
-
- }
-}
-
-/*---------------------------------------------------------------------------*/
-
-/*
- * Read in the symbols of all input files.
- */
-static void
-load_symbols()
-{
- register int i;
-
- if (trace_files)
- fprintf(stderr, "Loading symbols:\n\n");
-
- for (i = 0; i < number_of_files; i++)
- read_file_symbols(&file_table[i]);
-
- if (trace_files)
- fprintf(stderr, "\n");
-}
-
-/*
- * If ENTRY is a rel file, read its symbol and string sections into core. If
- * it is a library, search it and load the appropriate members (which means
- * calling this function recursively on those members).
- */
-
-void
-read_file_symbols(entry)
- register struct file_entry *entry;
-{
- register int fd;
- register int len;
- struct exec hdr;
-
- fd = file_open(entry);
-
- len = read(fd, &hdr, sizeof hdr);
- if (len != sizeof hdr)
- errx(1, "%s: read_file_symbols(header): premature EOF",
- get_file_name(entry));
-
- md_swapin_exec_hdr(&hdr);
-
- if (!N_BADMAG (hdr)) {
- if (N_IS_DYNAMIC(hdr) && !(entry->flags & E_JUST_SYMS)) {
- if (relocatable_output) {
- errx(1,
- "%s: -r and shared objects currently not supported",
- get_file_name(entry));
- return;
- }
-#if notyet /* Compatibility */
- if (!(N_GETFLAG(hdr) & EX_PIC))
- warnx("%s: EX_PIC not set",
- get_file_name(entry));
-#endif
- entry->flags |= E_DYNAMIC;
- if (entry->superfile || rrs_add_shobj(entry))
- read_shared_object(fd, entry);
- else
- entry->flags |= E_SCRAPPED;
- } else {
- if (N_GETFLAG(hdr) & EX_PIC)
- pic_code_seen = 1;
- read_entry_symbols(fd, entry);
- entry->strings = (char *)alloca(entry->string_size);
- read_entry_strings(fd, entry);
- read_entry_relocation(fd, entry);
- enter_file_symbols(entry);
- entry->strings = 0;
- }
- } else {
- char armag[SARMAG];
-
- lseek (fd, 0, 0);
- if (SARMAG != read(fd, armag, SARMAG) ||
- strncmp (armag, ARMAG, SARMAG))
- errx(1,
- "%s: malformed input file (not rel or archive)",
- get_file_name(entry));
- entry->flags |= E_IS_LIBRARY;
- search_library(fd, entry);
- }
-
- file_close();
-}
-
-
-/*
- * Enter the external symbol defs and refs of ENTRY in the hash table.
- */
-
-void
-enter_file_symbols(entry)
- struct file_entry *entry;
-{
- struct localsymbol *lsp, *lspend;
-
- if (trace_files)
- prline_file_name(entry, stderr);
-
- lspend = entry->symbols + entry->nsymbols;
-
- for (lsp = entry->symbols; lsp < lspend; lsp++) {
- register struct nlist *p = &lsp->nzlist.nlist;
-
- if (p->n_type == (N_SETV | N_EXT))
- continue;
-
- /*
- * Turn magically prefixed symbols into set symbols of
- * a corresponding type.
- */
- if (set_element_prefixes &&
- set_element_prefixed_p(entry->strings+lsp->nzlist.nz_strx))
- lsp->nzlist.nz_type += (N_SETA - N_ABS);
-
- if (SET_ELEMENT_P(p->n_type)) {
- set_symbol_count++;
- if (!relocatable_output)
- enter_global_ref(lsp,
- p->n_un.n_strx + entry->strings, entry);
- } else if (p->n_type == N_WARNING) {
- char *msg = p->n_un.n_strx + entry->strings;
-
- /* Grab the next entry. */
- lsp++;
- p = &lsp->nzlist.nlist;
- if (p->n_type != (N_UNDF | N_EXT)) {
- warnx(
- "%s: Warning symbol without external reference following.",
- get_file_name(entry));
- make_executable = 0;
- lsp--; /* Process normally. */
- } else {
- symbol *sp;
- char *name = p->n_un.n_strx + entry->strings;
- /* Deal with the warning symbol. */
- lsp->flags |= LS_WARNING;
- enter_global_ref(lsp, name, entry);
- sp = getsym(name);
- if (sp->warning == NULL) {
- sp->warning = (char *)
- xmalloc(strlen(msg)+1);
- strcpy(sp->warning, msg);
- warn_sym_count++;
- } else if (strcmp(sp->warning, msg))
- warnx(
- "%s: multiple definitions for warning symbol `%s'",
- get_file_name(entry), demangle(sp->name));
- }
- } else if (p->n_type & N_EXT) {
- enter_global_ref(lsp,
- p->n_un.n_strx + entry->strings, entry);
- } else if (p->n_un.n_strx &&
- (p->n_un.n_strx + entry->strings)[0] == LPREFIX)
- lsp->flags |= LS_L_SYMBOL;
- }
-
-}
-
-/*
- * Enter one global symbol in the hash table. LSP points to the `struct
- * localsymbol' from the file that describes the global symbol. NAME is the
- * symbol's name. ENTRY is the file entry for the file the symbol comes from.
- *
- * LSP is put on the chain of all such structs that refer to the same symbol.
- * This chain starts in the `refs' for symbols from relocatable objects. A
- * backpointer to the global symbol is kept in LSP.
- *
- * Symbols from shared objects are linked through `soref'. For such symbols
- * that's all we do at this stage, with the exception of the case where the
- * symbol is a common. The `referenced' bit is only set for references from
- * relocatable objects.
- *
- */
-
-static void
-enter_global_ref(lsp, name, entry)
- struct localsymbol *lsp;
- char *name;
- struct file_entry *entry;
-{
- register struct nzlist *nzp = &lsp->nzlist;
- register symbol *sp = getsym(name);
- register int type = nzp->nz_type;
- int oldref = (sp->flags & GS_REFERENCED);
- int olddef = sp->defined;
- int com = sp->defined && sp->common_size;
-
- if (type == (N_INDR | N_EXT) && !olddef) {
- sp->alias = getsym(entry->strings + (lsp + 1)->nzlist.nz_strx);
- if (sp == sp->alias) {
- warnx("%s: %s is alias for itself",
- get_file_name(entry), name);
- /* Rewrite symbol as global text symbol with value 0 */
- lsp->nzlist.nz_type = N_TEXT|N_EXT;
- lsp->nzlist.nz_value = 0;
- make_executable = 0;
- }
-#if 0
- if (sp->flags & GS_REFERENCED)
- sp->alias->flags |= GS_REFERENCED;
-#endif
- }
-
- if (entry->flags & E_DYNAMIC) {
- lsp->next = sp->sorefs;
- sp->sorefs = lsp;
- lsp->symbol = sp;
-
- /*
- * Handle commons from shared objects:
- * 1) If symbol hitherto undefined, turn it into a common.
- * 2) If symbol already common, update size if necessary.
- */
-/*XXX - look at case where commons are only in shared objects */
- if (type == (N_UNDF | N_EXT) && nzp->nz_value) {
- if (!olddef) {
- if (oldref)
- undefined_global_sym_count--;
- common_defined_global_count++;
- sp->common_size = nzp->nz_value;
- sp->defined = N_UNDF | N_EXT;
- } else if (com && sp->common_size < nzp->nz_value) {
- sp->common_size = nzp->nz_value;
- }
- } else if (type != (N_UNDF | N_EXT) && !oldref) {
- /*
- * This is an ex common...
- */
- if (com)
- common_defined_global_count--;
- sp->common_size = 0;
- sp->defined = 0;
- }
-
- /*
- * Handle size information in shared objects.
- */
- if (nzp->nz_size > sp->size)
- sp->size = nzp->nz_size;
-
- if ((lsp->flags & LS_WARNING) && (sp->flags & GS_REFERENCED))
- /*
- * Prevent warning symbols from getting
- * gratuitously referenced.
- */
- list_warning_symbols = 1;
- return;
- }
-
- lsp->next = sp->refs;
- sp->refs = lsp;
- lsp->symbol = sp;
-
- if (lsp->flags & LS_WARNING) {
- /*
- * Prevent warning symbols from getting
- * gratuitously referenced.
- */
- if (sp->flags & GS_REFERENCED)
- list_warning_symbols = 1;
- return;
- }
-
- if (sp->warning)
- list_warning_symbols = 1;
-
- sp->flags |= GS_REFERENCED;
-
- if (sp == dynamic_symbol || sp == got_symbol) {
- if (type != (N_UNDF | N_EXT) && !(entry->flags & E_JUST_SYMS))
- errx(1,"Linker reserved symbol %s defined as type %x ",
- name, type);
- return;
- }
-
- if (olddef && N_ISWEAK(&nzp->nlist) && !(sp->flags & GS_WEAK)) {
-#ifdef DEBUG
- printf("%s: not overridden by weak symbol from %s\n",
- demangle(sp->name), get_file_name(entry));
-#endif
- return;
- }
-
- if (type == (N_SIZE | N_EXT)) {
-
- if (relocatable_output && nzp->nz_value != 0 && sp->size == 0)
- size_sym_count++;
- if (sp->size < nzp->nz_value)
- sp->size = nzp->nz_value;
-
- } else if (type != (N_UNDF | N_EXT) || nzp->nz_value) {
-
- /*
- * Set `->defined' here, so commons and undefined globals
- * can be counted correctly.
- */
- if (!sp->defined || sp->defined == (N_UNDF | N_EXT)) {
- sp->defined = type;
- }
-
- if ((sp->flags & GS_WEAK) && !N_ISWEAK(&nzp->nlist)) {
- /*
- * Upgrade an existing weak definition.
- * We fake it by pretending the symbol is undefined;
- * must undo any common fiddling, however.
- */
- if (!oldref)
- errx(1, "internal error: enter_glob_ref: "
- "weak symbol not referenced");
- if (!olddef && !com)
- undefined_weak_sym_count--;
- undefined_global_sym_count++;
- sp->defined = type;
- sp->flags &= ~GS_WEAK;
- olddef = 0;
- if (com)
- common_defined_global_count--;
- com = 0;
- sp->common_size = 0;
- }
- if (oldref && !olddef) {
- /*
- * It used to be undefined and we're defining it.
- */
- undefined_global_sym_count--;
- if (sp->flags & GS_WEAK)
- /* Used to be a weak reference */
- undefined_weak_sym_count--;
- if (undefined_global_sym_count < 0 ||
- undefined_weak_sym_count < 0)
- errx(1, "internal error: enter_glob_ref: "
- "undefined_global_sym_count = %d, "
- "undefined_weak_sym_count = %d",
- undefined_global_sym_count,
- undefined_weak_sym_count);
-
- }
-
- if (N_ISWEAK(&nzp->nlist))
- /* The definition is weak */
- sp->flags |= GS_WEAK;
-
- if (!olddef && type == (N_UNDF | N_EXT) && nzp->nz_value) {
- /*
- * First definition and it's common.
- */
- common_defined_global_count++;
- sp->common_size = nzp->nz_value;
- } else if (com && type != (N_UNDF | N_EXT)) {
- /*
- * It used to be common and we're defining
- * it as something else.
- */
- common_defined_global_count--;
- sp->common_size = 0;
- } else if (com && type == (N_UNDF | N_EXT) &&
- sp->common_size < nzp->nz_value)
- /*
- * It used to be common and this is a new common entry
- * to which we need to pay attention.
- */
- sp->common_size = nzp->nz_value;
-
- if (SET_ELEMENT_P(type) && (!olddef || com))
- set_vector_count++;
-
- } else if (!oldref && !com) {
- /*
- * An unreferenced symbol can already be defined
- * as common by shared objects.
- */
- undefined_global_sym_count++;
- if (N_ISWEAK(&nzp->nlist)) {
- /* The reference is weak */
- sp->flags |= GS_WEAK;
- undefined_weak_sym_count++;
- }
- }
-
- if (sp == end_symbol && (entry->flags & E_JUST_SYMS) &&
- !T_flag_specified)
- text_start = nzp->nz_value;
-
- if (sp->flags & GS_TRACE) {
- register char *reftype;
- switch (type & N_TYPE) {
- case N_UNDF:
- reftype = nzp->nz_value
- ? "defined as common" : "referenced";
- break;
-
- case N_ABS:
- reftype = "defined as absolute";
- break;
-
- case N_TEXT:
- reftype = "defined in text section";
- break;
-
- case N_DATA:
- reftype = "defined in data section";
- break;
-
- case N_BSS:
- reftype = "defined in BSS section";
- break;
-
- case N_INDR:
- reftype = "alias";
- break;
-
- case N_SIZE:
- reftype = "size spec";
- break;
-
- default:
- reftype = "I don't know this type";
- break;
- }
-
- fprintf(stderr, "symbol %s %s%s in ", demangle(sp->name),
- (N_ISWEAK(&nzp->nlist))?"weakly ":"", reftype);
- print_file_name (entry, stderr);
- fprintf(stderr, "\n");
- }
-}
-
-/*
- * This returns 0 if the given file entry's symbol table does *not* contain
- * the nlist point entry, and it returns the files entry pointer (cast to
- * unsigned long) if it does.
- */
-
-unsigned long
-contains_symbol(entry, np)
- struct file_entry *entry;
- register struct nlist *np;
-{
- if (np >= &entry->symbols->nzlist.nlist &&
- np < &(entry->symbols + entry->nsymbols)->nzlist.nlist)
- return (unsigned long) entry;
- return 0;
-}
-
-
-/*
- * Having entered all the global symbols and found the sizes of sections of
- * all files to be linked, make all appropriate deductions from this data.
- *
- * We propagate global symbol values from definitions to references. We compute
- * the layout of the output file and where each input file's contents fit
- * into it.
- *
- * This is now done in several stages.
- *
- * 1) All global symbols are examined for definitions in relocatable (.o)
- * files. The symbols' type is set according to the definition found,
- * but its value can not yet be determined. In stead, we keep a pointer
- * to the file entry's localsymbol that bequeathed the global symbol with
- * its definition. Also, multiple (incompatible) definitions are checked
- * for in this pass. If no definition comes forward, the set of local
- * symbols originating from shared objects is searched for a definition.
- *
- * 2) Then the relocation information of each relocatable file is examined
- * for possible contributions to the RRS section.
- *
- * 3) When this is done, the sizes and start addresses are set of all segments
- * that will appear in the output file (including the RRS segment).
- *
- * 4) Finally, all symbols are relocated according according to the start
- * of the entry they are part of. Then global symbols are assigned their
- * final values. Also, space for commons and imported data are allocated
- * during this pass, if the link mode in effect so demands.
- *
- */
-
-static void
-digest_symbols()
-{
-
- if (trace_files)
- fprintf(stderr, "Digesting symbol information:\n\n");
-
- if (!relocatable_output) {
- /*
- * The set sector size is the number of set elements + a word
- * for each symbol for the length word at the beginning of
- * the vector, plus a word for each symbol for a zero at the
- * end of the vector (for incremental linking).
- */
- set_sect_size = (set_symbol_count + 2 * set_vector_count) *
- sizeof (unsigned long);
- set_vectors = (long *)xmalloc (set_sect_size);
- setv_fill_count = 0;
- }
-
- /* Pass 1: check and define symbols */
- defined_global_sym_count = 0;
- digest_pass1();
-
- each_full_file(consider_relocation, (void *)0); /* Text */
- each_full_file(consider_relocation, (void *)1); /* Data */
-
- each_file(consider_local_symbols, (void *)0);
-
- /*
- * Compute total size of sections.
- * RRS data is the first output data section, RRS text is the last
- * text section. Thus, DATA_START is calculated from RRS_DATA_START
- * and RRS_DATA_SIZE, while RRS_TEXT_START is derived from TEXT_START
- * and TEXT_SIZE.
- */
- consider_rrs_section_lengths();
- each_full_file(consider_file_section_lengths, 0);
- rrs_text_start = text_start + text_size;
- text_size += rrs_text_size;
- data_size += rrs_data_size;
-
- /*
- * If necessary, pad text section to full page in the file. Include
- * the padding in the text segment size.
- */
-
- if (page_align_segments || page_align_data) {
- int text_end = text_size + N_TXTOFF(outheader);
- text_pad = PALIGN(text_end, page_size) - text_end;
- text_size += text_pad;
- }
- outheader.a_text = text_size;
-
- /*
- * Make the data segment address start in memory on a suitable
- * boundary.
- */
-
- if (!Tdata_flag_specified)
- rrs_data_start = text_start +
- DATA_START(outheader) - TEXT_START(outheader);
-
- data_start = rrs_data_start + rrs_data_size;
- if (!relocatable_output) {
- set_sect_start = rrs_data_start + data_size;
- data_size += MALIGN(set_sect_size);
- }
- bss_start = rrs_data_start + data_size;
-
-#ifdef DEBUG
-printf("textstart = %#x, textsize = %#x, rrs_text_start = %#x, rrs_text_size %#x\n",
- text_start, text_size, rrs_text_start, rrs_text_size);
-printf("datastart = %#x, datasize = %#x, rrs_data_start %#x, rrs_data_size %#x\n",
- data_start, data_size, rrs_data_start, rrs_data_size);
-printf("bssstart = %#x, bsssize = %#x\n",
- bss_start, bss_size);
-printf("set_sect_start = %#x, set_sect_size = %#x\n",
- set_sect_start, set_sect_size);
-#endif
-
- /* Compute start addresses of each file's sections and symbols. */
-
- each_full_file(relocate_file_addresses, 0);
- relocate_rrs_addresses();
-
- /* Pass 2: assign values to symbols */
- digest_pass2();
-
- if (end_symbol) { /* These are null if -r. */
- etext_symbol->value = text_start + text_size - text_pad;
- edata_symbol->value = rrs_data_start + data_size;
- end_symbol->value = rrs_data_start + data_size + bss_size;
- }
- /*
- * Figure the data_pad now, so that it overlaps with the bss
- * addresses.
- */
-
- if (specified_data_size && specified_data_size > data_size)
- data_pad = specified_data_size - data_size;
-
- if (page_align_segments)
- data_pad = PALIGN(data_pad + data_size, page_size) - data_size;
-
- bss_size -= data_pad;
- if (bss_size < 0)
- bss_size = 0;
-
- data_size += data_pad;
-
- /*
- * Calculate total number of symbols that will go into
- * the output symbol table (barring DISCARD_* settings).
- */
- global_sym_count = defined_global_sym_count +
- undefined_global_sym_count;
-
- if (dynamic_symbol->flags & GS_REFERENCED)
- global_sym_count++;
-
- if (got_symbol->flags & GS_REFERENCED)
- global_sym_count++;
-
- if (relocatable_output || building_shared_object) {
- /* For each alias we write out two struct nlists */
- global_sym_count += global_alias_count;
- /* Propagate warning symbols; costs two extra struct nlists */
- global_sym_count += 2 * warn_sym_count;
- }
-
- if (relocatable_output)
- /* We write out the original N_SIZE symbols */
- global_sym_count += size_sym_count;
-
-#ifdef DEBUG
-printf(
-"global symbols %d "
-"(defined %d, undefined %d, weak %d, aliases %d, warnings 2 * %d, "
-"size symbols %d)\ncommons %d, locals: %d, debug symbols: %d, set_symbols %d\n",
- global_sym_count,
- defined_global_sym_count, undefined_global_sym_count,
- undefined_weak_sym_count,
- global_alias_count, warn_sym_count, size_sym_count,
- common_defined_global_count, local_sym_count,
- debugger_sym_count, set_symbol_count);
-#endif
-}
-
-/*
- * Determine the definition of each global symbol.
- */
-static void
-digest_pass1()
-{
-
- /*
- * For each symbol, verify that it is defined globally at most
- * once within relocatable files (except when building a shared lib).
- * and set the `defined' field if there is a definition.
- *
- * Then check the shared object symbol chain for any remaining
- * undefined symbols. Set the `so_defined' field for any
- * definition find this way.
- */
- FOR_EACH_SYMBOL(i, sp) {
- symbol *spsave;
- struct localsymbol *lsp;
- int defs = 0;
-
- if (!(sp->flags & GS_REFERENCED)) {
-#if 0
- /* Check for undefined symbols in shared objects */
- int type;
- for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
- type = lsp->nzlist.nlist.n_type;
- if ((type & N_EXT) && type != (N_UNDF | N_EXT))
- break;
- }
- if ((type & N_EXT) && type == (N_UNDF | N_EXT))
- undefined_shobj_sym_count++;
-#endif
-
- /* Superfluous symbol from shared object */
- continue;
- }
- if (sp->so_defined)
- /* Already examined; must have been an alias */
- continue;
-
- if (sp == got_symbol || sp == dynamic_symbol)
- continue;
-
- for (lsp = sp->refs; lsp; lsp = lsp->next) {
- register struct nlist *p = &lsp->nzlist.nlist;
- register int type = p->n_type;
-
- if (SET_ELEMENT_P(type)) {
- if (relocatable_output)
- errx(1,
- "internal error: global ref to set el %s with -r",
- demangle(sp->name));
- if (!defs++) {
- sp->defined = N_SETV | N_EXT;
- sp->value =
- setv_fill_count++ * sizeof(long);
- } else if ((sp->defined & N_TYPE) != N_SETV) {
- sp->mult_defs = 1;
- multiple_def_count++;
- }
- /* Keep count and remember symbol */
- sp->setv_count++;
- set_vectors[setv_fill_count++] = (long)p;
- if (building_shared_object) {
- struct relocation_info reloc;
-
- /*
- * Make sure to relocate the contents
- * of this set vector.
- */
- bzero(&reloc, sizeof(reloc));
- RELOC_INIT_SEGMENT_RELOC(&reloc);
- RELOC_ADDRESS(&reloc) =
- setv_fill_count * sizeof(long);
- alloc_rrs_segment_reloc(NULL, &reloc);
- }
-
- } else if ((type & N_EXT) && type != (N_UNDF | N_EXT)
- && (type & N_TYPE) != N_FN
- && (type & N_TYPE) != N_SIZE) {
- /* non-common definition */
- if (!N_ISWEAK(p))
- ++defs;
- if (defs > 1) {
- sp->mult_defs = 1;
- multiple_def_count++;
- } else if (!N_ISWEAK(p) ||
- (!sp->def_lsp && !sp->common_size)) {
- sp->def_lsp = lsp;
- lsp->entry->flags |= E_SYMBOLS_USED;
- sp->defined = type;
- sp->aux = N_AUX(p);
- }
- }
- }
-
- /*
- * If this symbol has acquired final definition, we're done.
- * Commons must be allowed to bind to shared object data
- * definitions.
- */
- if (sp->defined &&
- (sp->common_size == 0 ||
- relocatable_output || building_shared_object)) {
- if ((sp->defined & N_TYPE) == N_SETV)
- /* Allocate zero entry in set vector */
- setv_fill_count++;
- /*
- * At this stage, we do not know whether an alias
- * is going to be defined for real here, or whether
- * it refers to a shared object symbol. The decision
- * is deferred until digest_pass2().
- */
- if (!sp->alias)
- defined_global_sym_count++;
- continue;
- }
-
- if (relocatable_output)
- /* We're done */
- continue;
-
- /*
- * Still undefined, search the shared object symbols for a
- * definition. This symbol must go into the RRS.
- */
- if (building_shared_object) {
- /* Just punt for now */
- undefined_global_sym_count--;
- if (undefined_global_sym_count < 0)
- errx(1,
- "internal error: digest_pass1,1: %s: undefined_global_sym_count = %d",
- demangle(sp->name), undefined_global_sym_count);
- continue;
- }
-
- spsave=sp; /*XXX*/
- again:
- for (lsp = sp->sorefs; lsp; lsp = lsp->next) {
- register struct nlist *p = &lsp->nzlist.nlist;
- register int type = p->n_type;
-
- if ((type & N_EXT) && type != (N_UNDF | N_EXT) &&
- (type & N_TYPE) != N_FN) {
- /* non-common definition */
- if (sp->common_size) {
- /*
- * This common has an so defn; switch
- * to it iff defn is: data, first-class
- * and not weak.
- */
- if (N_AUX(p) != AUX_OBJECT ||
- N_ISWEAK(p) ||
- (lsp->entry->flags & E_SECONDCLASS))
- continue;
-
- /*
- * Change common to so ref. First,
- * downgrade common to undefined.
- */
- sp->common_size = 0;
- sp->defined = 0;
- common_defined_global_count--;
- undefined_global_sym_count++;
- }
- sp->def_lsp = lsp;
- sp->so_defined = type;
- sp->aux = N_AUX(p);
- if (lsp->entry->flags & E_SECONDCLASS)
- /* Keep looking for something better */
- continue;
- if (N_ISWEAK(p))
- /* Keep looking for something better */
- continue;
- break;
- }
- }
- if (sp->def_lsp) {
-#ifdef DEBUG
-printf("pass1: SO definition for %s, type %x in %s at %#x\n",
- demangle(sp->name), sp->so_defined, get_file_name(sp->def_lsp->entry),
- sp->def_lsp->nzlist.nz_value);
-#endif
- sp->def_lsp->entry->flags |= E_SYMBOLS_USED;
- if (sp->flags & GS_REFERENCED) {
- undefined_global_sym_count--;
- } else
- sp->flags |= GS_REFERENCED;
- if (undefined_global_sym_count < 0)
- errx(1, "internal error: digest_pass1,2: "
- "%s: undefined_global_sym_count = %d",
- demangle(sp->name), undefined_global_sym_count);
- if (sp->alias &&
- !(sp->alias->flags & GS_REFERENCED)) {
- sp = sp->alias;
- goto again;
- }
- } else if (sp->defined) {
- if (sp->common_size == 0)
- errx(1, "internal error: digest_pass1,3: "
- "%s: not a common: %x",
- demangle(sp->name), sp->defined);
- /*
- * Common not bound to shared object data; treat
- * it now like other defined symbols were above.
- */
- if (!sp->alias)
- defined_global_sym_count++;
- }
- sp=spsave; /*XXX*/
- } END_EACH_SYMBOL;
-
- if (setv_fill_count != set_sect_size/sizeof(long))
- errx(1, "internal error: allocated set symbol space (%d) "
- "doesn't match actual (%d)",
- set_sect_size/sizeof(long), setv_fill_count);
-}
-
-
-/*
- * Scan relocation info in ENTRY for contributions to the RRS section
- * of the output file.
- */
-static void
-consider_relocation(entry, dataseg)
- struct file_entry *entry;
- int dataseg;
-{
- struct relocation_info *reloc, *end;
- struct localsymbol *lsp;
- symbol *sp;
-
- if (dataseg == 0) {
- /* Text relocations */
- reloc = entry->textrel;
- end = entry->textrel + entry->ntextrel;
- } else {
- /* Data relocations */
- reloc = entry->datarel;
- end = entry->datarel + entry->ndatarel;
- }
-
- for (; reloc < end; reloc++) {
-
- if (relocatable_output) {
- lsp = &entry->symbols[reloc->r_symbolnum];
- if (RELOC_BASEREL_P(reloc)) {
- pic_code_seen = 1; /* Compatibility */
- if (!RELOC_EXTERN_P(reloc))
- lsp->flags |= LS_RENAME;
- }
- continue;
- }
-
- /*
- * First, do the PIC specific relocs.
- * r_relative and r_copy should not occur at this point
- * (we do output them). The others break down to these
- * combinations:
- *
- * jmptab: extern: needs jmp slot
- * !extern: "intersegment" jump/call,
- * should get resolved in output
- *
- * baserel: extern: need GOT entry
- * !extern: may need GOT entry,
- * machine dependent
- *
- * baserel's always refer to symbol through `r_symbolnum'
- * whether extern or not. Internal baserels refer to statics
- * that must be accessed either *through* the GOT table like
- * global data, or by means of an offset from the GOT table.
- * The macro RELOC_STATICS_THROUGH_GOT_P() determines which
- * applies, since this is a machine (compiler?) dependent
- * addressing mode.
- */
-
- if (RELOC_JMPTAB_P(reloc)) {
-
- if (!RELOC_EXTERN_P(reloc))
- continue;
-
- lsp = &entry->symbols[reloc->r_symbolnum];
- sp = lsp->symbol;
- if (sp->alias)
- sp = sp->alias;
- if (sp->flags & GS_TRACE) {
- fprintf(stderr, "symbol %s has jmpslot in %s\n",
- demangle(sp->name), get_file_name(entry));
- }
- alloc_rrs_jmpslot(entry, sp);
-
- } else if (RELOC_BASEREL_P(reloc)) {
-
- lsp = &entry->symbols[reloc->r_symbolnum];
- alloc_rrs_gotslot(entry, reloc, lsp);
- if (pic_type != PIC_TYPE_NONE &&
- RELOC_PIC_TYPE(reloc) != pic_type)
- errx(1, "%s: illegal reloc type mix",
- get_file_name(entry));
- pic_type = RELOC_PIC_TYPE(reloc);
-
- } else if (RELOC_EXTERN_P(reloc)) {
-
- /*
- * Non-PIC relocations.
- * If the definition comes from a shared object
- * we need a relocation entry in RRS.
- *
- * If the .so definition is N_TEXT a jmpslot is
- * allocated.
- *
- * If it is N_DATA we allocate an address in BSS (?)
- * and arrange for the data to be copied at run-time.
- * The symbol is temporarily marked with N_SIZE in
- * the `defined' field, so we know what to do in
- * pass2() and during actual relocation. We convert
- * the type back to something real again when writing
- * out the symbols.
- *
- */
- lsp = &entry->symbols[reloc->r_symbolnum];
- sp = lsp->symbol;
- if (sp == NULL)
- errx(1, "%s: bogus relocation record",
- get_file_name(entry));
-
- if (sp->alias)
- sp = sp->alias;
-
- /*
- * Skip refs to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC
- */
- if (sp == got_symbol) {
- if (!CHECK_GOT_RELOC(reloc))
- errx(1,
- "%s: Unexpected relocation type for GOT symbol",
- get_file_name(entry));
- continue;
- }
-
- /*
- * This symbol gives rise to a RRS entry
- */
-
- if (building_shared_object) {
- if (sp->flags & GS_TRACE) {
- fprintf(stderr,
- "symbol %s RRS entry in %s\n",
- demangle(sp->name), get_file_name(entry));
- }
- alloc_rrs_reloc(entry, sp);
- continue;
- }
-
- if (force_alias_definition && sp->so_defined &&
- sp->aux == AUX_FUNC) {
-
- /* Call to shared library procedure */
- alloc_rrs_jmpslot(entry, sp);
-
- } else if (sp->size && sp->so_defined &&
- sp->aux == AUX_OBJECT) {
-
- /* Reference to shared library data */
- alloc_rrs_cpy_reloc(entry, sp);
- sp->defined = N_SIZE;
-
- } else if (!sp->defined && sp->common_size == 0 &&
- sp->so_defined)
- alloc_rrs_reloc(entry, sp);
-
- } else {
- /*
- * Segment relocation.
- * Prepare an RRS relocation as these are load
- * address dependent.
- */
- if (building_shared_object && !RELOC_PCREL_P(reloc)) {
- alloc_rrs_segment_reloc(entry, reloc);
- }
- }
- }
-}
-
-/*
- * Determine the disposition of each local symbol.
- */
-static void
-consider_local_symbols(entry)
- register struct file_entry *entry;
-{
- register struct localsymbol *lsp, *lspend;
-
- if (entry->flags & E_DYNAMIC)
- return;
-
- lspend = entry->symbols + entry->nsymbols;
-
- /*
- * For each symbol determine whether it should go
- * in the output symbol table.
- */
-
- for (lsp = entry->symbols; lsp < lspend; lsp++) {
- register struct nlist *p = &lsp->nzlist.nlist;
- register int type = p->n_type;
-
- if (type == N_WARNING)
- continue;
-
- if (SET_ELEMENT_P (type)) {
- /*
- * This occurs even if global. These types of
- * symbols are never written globally, though
- * they are stored globally.
- */
- if (relocatable_output)
- lsp->flags |= LS_WRITE;
-
- } else if (!(type & (N_STAB | N_EXT))) {
-
- /*
- * Ordinary local symbol
- */
- if ((lsp->flags & LS_RENAME) || (
- discard_locals != DISCARD_ALL &&
- !(discard_locals == DISCARD_L &&
- (lsp->flags & LS_L_SYMBOL))) ) {
-
- lsp->flags |= LS_WRITE;
- local_sym_count++;
- }
-
- } else if (!(type & N_EXT)) {
-
- /*
- * Debugger symbol
- */
- if (strip_symbols == STRIP_NONE) {
- lsp->flags |= LS_WRITE;
- debugger_sym_count++;
- }
- }
- }
-
- /*
- * Count one for the local symbol that we generate,
- * whose name is the file's name (usually) and whose address
- * is the start of the file's text.
- */
- if (discard_locals != DISCARD_ALL)
- local_sym_count++;
-}
-
-/*
- * Accumulate the section sizes of input file ENTRY into the section sizes of
- * the output file.
- */
-static void
-consider_file_section_lengths(entry)
- register struct file_entry *entry;
-{
-
- entry->text_start_address = text_size;
- /* If there were any vectors, we need to chop them off */
- text_size += entry->header.a_text;
- entry->data_start_address = data_size;
- data_size += entry->header.a_data;
- entry->bss_start_address = bss_size;
- bss_size += MALIGN(entry->header.a_bss);
-
- text_reloc_size += entry->header.a_trsize;
- data_reloc_size += entry->header.a_drsize;
-}
-
-/*
- * Determine where the sections of ENTRY go into the output file,
- * whose total section sizes are already known.
- * Also relocate the addresses of the file's local and debugger symbols.
- */
-static void
-relocate_file_addresses(entry)
- register struct file_entry *entry;
-{
- register struct localsymbol *lsp, *lspend;
-
- entry->text_start_address += text_start;
- /*
- * Note that `data_start' and `data_size' have not yet been
- * adjusted for `data_pad'. If they had been, we would get the wrong
- * results here.
- */
- entry->data_start_address += data_start;
- entry->bss_start_address += bss_start;
-#ifdef DEBUG
-printf("%s: datastart: %#x, bss %#x\n", get_file_name(entry),
- entry->data_start_address, entry->bss_start_address);
-#endif
-
- lspend = entry->symbols + entry->nsymbols;
-
- for (lsp = entry->symbols; lsp < lspend; lsp++) {
- register struct nlist *p = &lsp->nzlist.nlist;
- register int type = p->n_type;
-
- /*
- * If this belongs to a section, update it
- * by the section's start address
- */
-
- switch (type & N_TYPE) {
- case N_TEXT:
- case N_SETT:
- p->n_value += entry->text_start_address;
- break;
- case N_DATA:
- case N_SETD:
- case N_SETV:
- /*
- * A symbol whose value is in the data section is
- * present in the input file as if the data section
- * started at an address equal to the length of the
- * file's text.
- */
- p->n_value += entry->data_start_address -
- entry->header.a_text;
- break;
- case N_BSS:
- case N_SETB:
- /* likewise for symbols with value in BSS. */
- p->n_value += entry->bss_start_address -
- (entry->header.a_text +
- entry->header.a_data);
- break;
- }
-
- }
-
-}
-
-/*
- * Assign a value to each global symbol.
- */
-static void
-digest_pass2()
-{
- FOR_EACH_SYMBOL(i, sp) {
- int size;
- int align = sizeof(int);
-
- if (!(sp->flags & GS_REFERENCED))
- continue;
-
- if (sp->alias &&
- (relocatable_output || building_shared_object ||
- (sp->alias->defined && !sp->alias->so_defined))) {
- /*
- * The alias points at a defined symbol, so it
- * must itself be counted as one too, in order to
- * compute the correct number of symbol table entries.
- */
- if (!sp->defined) {
- /*
- * Change aliased symbol's definition too.
- * These things happen if shared object commons
- * or data is going into our symbol table.
- */
- if (sp->so_defined != (N_INDR+N_EXT))
- warnx( "pass2: %s: alias isn't",
- demangle(sp->name));
- sp->defined = sp->so_defined;
- sp->so_defined = 0;
- }
- defined_global_sym_count++;
- }
-
- /*
- * Count the aliases that will appear in the output.
- */
- if (sp->alias && !sp->so_defined && !sp->alias->so_defined &&
- (sp->defined || relocatable_output ||
- !building_shared_object))
- global_alias_count++;
-
- if ((sp->defined & N_TYPE) == N_SETV) {
- /*
- * Set length word at front of vector and zero byte
- * at end. Reverse the vector itself to put it in
- * file order.
- */
- unsigned long i, *p, *q;
- unsigned long length_word_index =
- sp->value / sizeof(long);
-
- /* Relocate symbol value */
- sp->value += set_sect_start;
-
- set_vectors[length_word_index] = sp->setv_count;
-
- /*
- * Relocate vector to final address.
- */
- for (i = 0; i < sp->setv_count; i++) {
- struct nlist *p = (struct nlist *)
- set_vectors[1+i+length_word_index];
-
- set_vectors[1+i+length_word_index] = p->n_value;
- if (building_shared_object) {
- struct relocation_info reloc;
-
- bzero(&reloc, sizeof(reloc));
- RELOC_INIT_SEGMENT_RELOC(&reloc);
- RELOC_ADDRESS(&reloc) =
- (1 + i + length_word_index) *
- sizeof(long)
- + set_sect_start;
- RELOC_TYPE(&reloc) =
- (p->n_type - (N_SETA - N_ABS)) & N_TYPE;
- claim_rrs_segment_reloc(NULL, &reloc);
- }
- }
-
- /*
- * Reverse the vector.
- */
- p = &set_vectors[length_word_index + 1];
- q = &set_vectors[length_word_index + sp->setv_count];
- while (p < q) {
- unsigned long tmp = *p;
- *p++ = *q;
- *q-- = tmp;
- }
-
- /* Clear terminating entry */
- set_vectors[length_word_index + sp->setv_count + 1] = 0;
- continue;
- }
-
- if (sp->def_lsp) {
- if (sp->defined && (sp->defined & ~N_EXT) != N_SETV)
- sp->value = sp->def_lsp->nzlist.nz_value;
- if (sp->so_defined &&
- (sp->def_lsp->entry->flags & E_SECONDCLASS))
- /* Flag second-hand definitions */
- undefined_global_sym_count++;
- if (sp->flags & GS_TRACE)
- printf("symbol %s assigned to location %#lx\n",
- demangle(sp->name), sp->value);
- }
-
- /*
- * If not -r'ing, allocate common symbols in the BSS section.
- */
- if (building_shared_object && !(link_mode & SYMBOLIC))
- /* No common allocation in shared objects */
- continue;
-
- if ((size = sp->common_size) != 0) {
- /*
- * It's a common.
- */
- if (sp->defined != (N_UNDF + N_EXT))
- errx(1, "%s: common isn't", demangle(sp->name));
-
- } else if ((size = sp->size) != 0 && sp->defined == N_SIZE) {
- /*
- * It's data from shared object with size info.
- */
- if (!sp->so_defined)
- errx(1, "%s: Bogus N_SIZE item", demangle(sp->name));
-
- } else
- /*
- * It's neither
- */
- continue;
-
-
- if (relocatable_output && !force_common_definition) {
- sp->defined = 0;
- undefined_global_sym_count++;
- defined_global_sym_count--;
- continue;
- }
-
- /*
- * Round up to nearest sizeof (int). I don't know whether
- * this is necessary or not (given that alignment is taken
- * care of later), but it's traditional, so I'll leave it in.
- * Note that if this size alignment is ever removed, ALIGN
- * above will have to be initialized to 1 instead of sizeof
- * (int).
- */
-
- size = PALIGN(size, sizeof(int));
-
- while (align < MAX_ALIGNMENT && !(size & align))
- align <<= 1;
-
- bss_size = PALIGN(bss_size + data_size + rrs_data_start, align)
- - (data_size + rrs_data_start);
-
- sp->value = rrs_data_start + data_size + bss_size;
- if (sp->defined == (N_UNDF | N_EXT))
- sp->defined = N_BSS | N_EXT;
- else {
- sp->so_defined = 0;
- defined_global_sym_count++;
- }
- bss_size += size;
- if (write_map)
- printf("Allocating %s %s: %x at %lx\n",
- sp->defined==(N_BSS|N_EXT)?"common":"data",
- demangle(sp->name), size, sp->value);
-
- } END_EACH_SYMBOL;
-}
-
-
-/* -------------------------------------------------------------------*/
-
-/* Write the output file */
-void
-write_output()
-{
- struct stat statbuf;
- int filemode;
- mode_t u_mask;
-
- if (lstat(output_filename, &statbuf) == 0) {
- if (S_ISREG(statbuf.st_mode))
- (void)unlink(output_filename);
- }
-
- u_mask = umask(0);
- (void)umask(u_mask);
-
- outstream = fopen(output_filename, "w");
- if (outstream == NULL)
- err(1, "fopen: %s", output_filename);
-
- if (atexit(cleanup))
- err(1, "atexit");
-
- if (fstat(fileno(outstream), &statbuf) < 0)
- err(1, "fstat: %s", output_filename);
-
- filemode = statbuf.st_mode;
-
- if (S_ISREG(statbuf.st_mode) &&
- chmod(output_filename, filemode & ~0111) == -1)
- err(1, "chmod: %s", output_filename);
-
- /* Output the a.out header. */
- write_header();
-
- /* Output the text and data segments, relocating as we go. */
- write_text();
- write_data();
-
- /* Output the merged relocation info, if requested with `-r'. */
- if (relocatable_output)
- write_rel();
-
- /* Output the symbol table (both globals and locals). */
- write_syms();
-
- /* Output the RSS section */
- write_rrs();
-
- if (chmod (output_filename, filemode | (0111 & ~u_mask)) == -1)
- err(1, "chmod: %s", output_filename);
-
- fflush(outstream);
- /* Report I/O error such as disk full. */
- if (ferror(outstream) || fclose(outstream) != 0)
- err(1, "write_output: %s", output_filename);
- outstream = 0;
- if (real_output_filename)
- if (rename(output_filename, real_output_filename))
- err(1, "rename output: %s to %s",
- output_filename, real_output_filename);
-}
-
-/* Total number of symbols to be written in the output file. */
-static int nsyms;
-
-void
-write_header()
-{
- int flags;
-
- if (link_mode & SHAREABLE)
- /* Output is shared object */
- flags = EX_DYNAMIC | EX_PIC;
- else if (relocatable_output && pic_code_seen)
- /* Output is relocatable and contains PIC code */
- flags = EX_PIC;
- else if (rrs_section_type == RRS_FULL)
- /* Output is a dynamic executable */
- flags = EX_DYNAMIC;
- else
- /*
- * Output is a static executable
- * or a non-PIC relocatable object
- */
- flags = 0;
-
- if (oldmagic && (flags & EX_DPMASK) && !(link_mode & FORCEDYNAMIC))
- warnx("Cannot set flag in old magic headers\n");
-
- N_SET_FLAG (outheader, flags);
-
- outheader.a_text = text_size;
- outheader.a_data = data_size;
- outheader.a_bss = bss_size;
- outheader.a_entry = (entry_symbol ? entry_symbol->value
- : text_start + entry_offset);
-
- if (strip_symbols == STRIP_ALL)
- nsyms = 0;
- else
- nsyms = global_sym_count + local_sym_count + debugger_sym_count;
-
- if (relocatable_output)
- nsyms += set_symbol_count;
-
- outheader.a_syms = nsyms * sizeof (struct nlist);
-
- if (relocatable_output) {
- outheader.a_trsize = text_reloc_size;
- outheader.a_drsize = data_reloc_size;
- } else {
- outheader.a_trsize = 0;
- outheader.a_drsize = 0;
- }
-
- md_swapout_exec_hdr(&outheader);
- mywrite(&outheader, 1, sizeof (struct exec), outstream);
- md_swapin_exec_hdr(&outheader);
-
- /*
- * Output whatever padding is required in the executable file
- * between the header and the start of the text.
- */
-
-#ifndef COFF_ENCAPSULATE
- padfile(N_TXTOFF(outheader) - sizeof outheader, outstream);
-#endif
-}
-
-/*
- * Relocate the text segment of each input file
- * and write to the output file.
- */
-void
-write_text()
-{
-
- if (trace_files)
- fprintf(stderr, "Copying and relocating text:\n\n");
-
- each_full_file(copy_text, 0);
- file_close();
-
- if (trace_files)
- fprintf(stderr, "\n");
-
- padfile(text_pad, outstream);
-}
-
-/*
- * Read the text segment contents of ENTRY, relocate them, and write the
- * result to the output file. If `-r', save the text relocation for later
- * reuse.
- */
-void
-copy_text(entry)
- struct file_entry *entry;
-{
- register char *bytes;
- register int fd;
-
- if (trace_files)
- prline_file_name(entry, stderr);
-
- fd = file_open(entry);
-
- /* Allocate space for the file's text section */
- bytes = (char *)alloca(entry->header.a_text);
-
- /* Deal with relocation information however is appropriate */
- if (entry->textrel == NULL)
- errx(1, "%s: no text relocation", get_file_name(entry));
-
- /* Read the text section into core. */
- if (lseek(fd, text_offset(entry), L_SET) == (off_t)-1)
- err(1, "%s: copy_text: lseek", get_file_name(entry));
- if (entry->header.a_text != read(fd, bytes, entry->header.a_text))
- errx(1, "%s: copy_text: premature EOF", get_file_name(entry));
-
- /* Relocate the text according to the text relocation. */
- perform_relocation (bytes, entry->header.a_text,
- entry->textrel, entry->ntextrel, entry, 0);
-
- /* Write the relocated text to the output file. */
- mywrite(bytes, entry->header.a_text, 1, outstream);
-}
-
-/*
- * Relocate the data segment of each input file
- * and write to the output file.
- */
-
-void
-write_data()
-{
- off_t pos;
-
- if (trace_files)
- fprintf(stderr, "Copying and relocating data:\n\n");
-
- pos = N_DATOFF(outheader) + data_start - rrs_data_start;
- if (fseek(outstream, pos, SEEK_SET) != 0)
- errx(1, "write_data: fseek");
-
- each_full_file(copy_data, 0);
- file_close();
-
- /*
- * Write out the set element vectors. See digest symbols for
- * description of length of the set vector section.
- */
-
- if (set_vector_count) {
- swap_longs(set_vectors, set_symbol_count + 2*set_vector_count);
- mywrite(set_vectors, set_symbol_count + 2*set_vector_count,
- sizeof (unsigned long), outstream);
- }
-
- if (trace_files)
- fprintf(stderr, "\n");
-
- padfile(data_pad, outstream);
-}
-
-/*
- * Read the data segment contents of ENTRY, relocate them, and write the
- * result to the output file. If `-r', save the data relocation for later
- * reuse. See comments in `copy_text'.
- */
-void
-copy_data(entry)
- struct file_entry *entry;
-{
- register char *bytes;
- register int fd;
-
- if (trace_files)
- prline_file_name (entry, stderr);
-
- fd = file_open(entry);
-
- bytes = (char *)alloca(entry->header.a_data);
-
- if (entry->datarel == NULL)
- errx(1, "%s: no data relocation", get_file_name(entry));
-
- if (lseek(fd, text_offset(entry) + entry->header.a_text, L_SET) ==
- (off_t)-1)
- err(1, "%s: copy_data: lseek", get_file_name(entry));
- if (entry->header.a_data != read(fd, bytes, entry->header.a_data))
- errx(1, "%s: copy_data: premature EOF", get_file_name(entry));
-
- perform_relocation(bytes, entry->header.a_data,
- entry->datarel, entry->ndatarel, entry, 1);
-
- mywrite(bytes, entry->header.a_data, 1, outstream);
-}
-
-/*
- * Relocate ENTRY's text or data section contents. DATA is the address of the
- * contents, in core. DATA_SIZE is the length of the contents. PC_RELOCATION
- * is the difference between the address of the contents in the output file
- * and its address in the input file. RELOC is the address of the
- * relocation info, in core. NRELOC says how many there are.
- */
-
-int pc_relocation;
-
-void
-perform_relocation(data, data_size, reloc, nreloc, entry, dataseg)
- char *data;
- int data_size;
- struct relocation_info *reloc;
- int nreloc;
- struct file_entry *entry;
- int dataseg;
-{
-
- register struct relocation_info *r = reloc;
- struct relocation_info *end = reloc + nreloc;
-
- int text_relocation = entry->text_start_address;
- int data_relocation = entry->data_start_address - entry->header.a_text;
- int bss_relocation = entry->bss_start_address -
- entry->header.a_text - entry->header.a_data;
- pc_relocation = dataseg
- ? entry->data_start_address - entry->header.a_text
- : entry->text_start_address;
-
- for (; r < end; r++) {
- int addr = RELOC_ADDRESS(r);
- long addend = md_get_addend(r, data+addr);
- long relocation;
-
- /*
- * Loop over the relocations again as we did in
- * consider_relocation(), claiming the reserved RRS
- * relocations.
- */
-
- if (addr >= data_size)
- errx(1, "%s: relocation address out of range",
- get_file_name(entry));
-
- if (RELOC_JMPTAB_P(r)) {
-
- int symindex = RELOC_SYMBOL(r);
- struct localsymbol *lsp = &entry->symbols[symindex];
- symbol *sp;
-
- if (symindex >= entry->nsymbols)
- errx(1, "%s: relocation symbolnum out of range",
- get_file_name(entry));
-
- sp = lsp->symbol;
- if (sp == NULL)
- errx(1, "%s: bogus relocation record",
- get_file_name(entry));
- if (sp->alias)
- sp = sp->alias;
-
- if (relocatable_output)
- relocation = addend;
- else if (!RELOC_EXTERN_P(r)) {
- relocation = addend +
- data_relocation - text_relocation;
- } else
- relocation = addend +
- claim_rrs_jmpslot(entry, r, sp, addend);
-
- } else if (RELOC_BASEREL_P(r)) {
-
- int symindex = RELOC_SYMBOL(r);
- struct localsymbol *lsp = &entry->symbols[symindex];
-
- if (symindex >= entry->nsymbols)
- errx(1, "%s: relocation symbolnum out of range",
- get_file_name(entry));
-
- if (relocatable_output)
- relocation = addend;
- else if (!RELOC_EXTERN_P(r))
- relocation = claim_rrs_internal_gotslot(
- entry, r, lsp, addend);
- else
- relocation = claim_rrs_gotslot(
- entry, r, lsp, addend);
-
- } else if (RELOC_EXTERN_P(r)) {
-
- int symindex = RELOC_SYMBOL(r);
- symbol *sp;
-
- if (symindex >= entry->nsymbols)
- errx(1, "%s: relocation symbolnum out of range",
- get_file_name(entry));
-
- sp = entry->symbols[symindex].symbol;
- if (sp == NULL)
- errx(1, "%s: bogus relocation record",
- get_file_name(entry));
- if (sp->alias)
- sp = sp->alias;
-
- if (relocatable_output) {
- relocation = addend;
- /*
- * In PIC code, we keep the reference to the
- * external symbol, even if defined now.
- */
- if (!pic_code_seen)
- relocation += sp->value;
- } else if (sp->defined) {
- if (sp->flags & GS_TRACE) {
- fprintf(stderr,
- "symbol %s defined as %x in %s\n",
- demangle(sp->name), sp->defined,
- get_file_name(entry) );
- }
- if (sp == got_symbol) {
- /* Handle _GOT_ refs */
- relocation = addend + sp->value
- + md_got_reloc(r);
- } else if (building_shared_object) {
- /*
- * Normal (non-PIC) relocation needs
- * to be converted into an RRS reloc
- * when building a shared object.
- */
- r->r_address += dataseg?
- entry->data_start_address:
- entry->text_start_address;
- relocation = addend;
- if (claim_rrs_reloc(
- entry, r, sp, &relocation))
- continue;
- } else if (sp->defined == N_SIZE) {
- /*
- * If size is known, arrange a
- * run-time copy.
- */
- if (!sp->size)
- errx(1, "Copy item isn't: %s",
- demangle(sp->name));
-
- relocation = addend + sp->value;
- r->r_address = sp->value;
- claim_rrs_cpy_reloc(entry, r, sp);
- } else
- /* Plain old relocation */
- relocation = addend + sp->value;
- } else {
- /*
- * If the symbol is undefined, we relocate it
- * in a way similar to -r case. We use an
- * RRS relocation to resolve the symbol at
- * run-time. The r_address field is updated
- * to reflect the changed position in the
- * output file.
- */
- if (sp->flags & GS_TRACE) {
- fprintf(stderr,
- "symbol %s claims RRS in %s%s\n",
- demangle(sp->name), get_file_name(entry),
- (sp->so_defined == (N_TEXT+N_EXT) &&
- sp->flags & GS_HASJMPSLOT)?
- " (JMPSLOT)":"");
- }
- if (sp->so_defined == (N_TEXT+N_EXT) &&
- sp->flags & GS_HASJMPSLOT) {
- /*
- * Claim a jmpslot if one was allocated.
- *
- * At this point, a jmpslot can only
- * result from a shared object reference
- * while `force_alias' is in effect.
- */
- relocation = addend +
- claim_rrs_jmpslot(
- entry, r, sp, addend);
- } else {
- r->r_address += dataseg?
- entry->data_start_address:
- entry->text_start_address;
- relocation = addend;
- if ((building_shared_object ||
- sp->so_defined) &&
- claim_rrs_reloc(entry, r, sp,
- &relocation))
- continue;
- }
- }
-
- } else {
-
- switch (RELOC_TYPE(r)) {
- case N_TEXT:
- case N_TEXT | N_EXT:
- relocation = addend + text_relocation;
- break;
-
- case N_DATA:
- case N_DATA | N_EXT:
- /*
- * A word that points to beginning of the the
- * data section initially contains not 0 but
- * rather the "address" of that section in
- * the input file, which is the length of the
- * file's text.
- */
- relocation = addend + data_relocation;
- break;
-
- case N_BSS:
- case N_BSS | N_EXT:
- /*
- * Similarly, an input word pointing to the
- * beginning of the bss initially contains
- * the length of text plus data of the file.
- */
- relocation = addend + bss_relocation;
- break;
-
- case N_ABS:
- case N_ABS | N_EXT:
- /*
- * Don't know why this code would occur, but
- * apparently it does.
- */
- break;
-
- default:
- errx(1, "%s: nonexternal relocation invalid",
- get_file_name(entry));
- }
-
- /*
- * When building a shared object, these segment
- * relocations need a "load address relative"
- * RRS fixup.
- */
- if (building_shared_object && !RELOC_PCREL_P(r)) {
- r->r_address += dataseg?
- entry->data_start_address:
- entry->text_start_address;
- claim_rrs_segment_reloc(entry, r);
- }
- }
-
- if (RELOC_PCREL_P(r))
- relocation -= pc_relocation;
-
- md_relocate(r, relocation, data+addr, relocatable_output);
-
- }
-}
-
-
-/*
- * For relocatable_output only: write out the relocation,
- * relocating the addresses-to-be-relocated.
- */
-void
-write_rel()
-{
- int count = 0;
-
- if (trace_files)
- fprintf(stderr, "Writing text relocation:\n\n");
-
- /*
- * Assign each global symbol a sequence number, giving the order
- * in which `write_syms' will write it.
- * This is so we can store the proper symbolnum fields
- * in relocation entries we write.
- */
-
- /* BLECH - Assign number 0 to __DYNAMIC (!! Sun compatibility) */
-
- if (dynamic_symbol->flags & GS_REFERENCED)
- dynamic_symbol->symbolnum = count++;
- FOR_EACH_SYMBOL(i, sp) {
- if (sp == dynamic_symbol)
- continue;
- if (sp->warning)
- count += 2;
- if (!(sp->flags & GS_REFERENCED))
- continue;
- sp->symbolnum = count++;
- if (sp->size)
- count++;
- if (sp->alias)
- count++;
- } END_EACH_SYMBOL;
-
- if (count != global_sym_count)
- errx(1, "internal error: write_rel: count = %d", count);
-
- each_full_file(assign_symbolnums, &count);
-
- /* Write out the relocations of all files, remembered from copy_text. */
- each_full_file(coptxtrel, 0);
-
- if (trace_files)
- fprintf(stderr, "\nWriting data relocation:\n\n");
-
- each_full_file(copdatrel, 0);
-
- if (trace_files)
- fprintf(stderr, "\n");
-}
-
-
-/*
- * Assign symbol ordinal numbers to local symbols in each entry.
- */
-static void
-assign_symbolnums(entry, countp)
- struct file_entry *entry;
- int *countp;
-{
- struct localsymbol *lsp, *lspend;
- int n = *countp;
-
- lspend = entry->symbols + entry->nsymbols;
-
- if (discard_locals != DISCARD_ALL)
- /* Count the N_FN symbol for this entry */
- n++;
-
- for (lsp = entry->symbols; lsp < lspend; lsp++) {
- if (lsp->flags & LS_WRITE)
- lsp->symbolnum = n++;
- }
- *countp = n;
-}
-
-static void
-coptxtrel(entry)
- struct file_entry *entry;
-{
- register struct relocation_info *r, *end;
- register int reloc = entry->text_start_address;
-
- r = entry->textrel;
- end = r + entry->ntextrel;
-
- for (; r < end; r++) {
- register int symindex;
- struct localsymbol *lsp;
- symbol *sp;
-
- RELOC_ADDRESS(r) += reloc;
-
- symindex = RELOC_SYMBOL(r);
- lsp = &entry->symbols[symindex];
-
- if (!RELOC_EXTERN_P(r)) {
- if (!pic_code_seen)
- continue;
- if (RELOC_BASEREL_P(r))
- RELOC_SYMBOL(r) = lsp->symbolnum;
- continue;
- }
-
- if (symindex >= entry->nsymbols)
- errx(1, "%s: relocation symbolnum out of range",
- get_file_name(entry));
-
- sp = lsp->symbol;
-
-#ifdef N_INDR
- /* Resolve indirection. */
- if ((sp->defined & ~N_EXT) == N_INDR) {
- if (sp->alias == NULL)
- errx(1, "internal error: alias in hyperspace");
- sp = sp->alias;
- }
-#endif
-
- /*
- * If the symbol is now defined, change the external
- * relocation to an internal one.
- */
-
- if (sp->defined) {
- if (!pic_code_seen) {
- RELOC_EXTERN_P(r) = 0;
- RELOC_SYMBOL(r) = (sp->defined & N_TYPE);
- } else
- RELOC_SYMBOL(r) = sp->symbolnum;
- } else
- /*
- * Global symbols come first.
- */
- RELOC_SYMBOL(r) = sp->symbolnum;
- }
- md_swapout_reloc(entry->textrel, entry->ntextrel);
- mywrite(entry->textrel, entry->ntextrel,
- sizeof(struct relocation_info), outstream);
-}
-
-static void
-copdatrel(entry)
- struct file_entry *entry;
-{
- register struct relocation_info *r, *end;
- /*
- * Relocate the address of the relocation. Old address is relative to
- * start of the input file's data section. New address is relative to
- * start of the output file's data section.
- */
- register int reloc = entry->data_start_address - text_size;
-
- r = entry->datarel;
- end = r + entry->ndatarel;
-
- for (; r < end; r++) {
- register int symindex;
- symbol *sp;
- int symtype;
-
- RELOC_ADDRESS(r) += reloc;
-
- if (!RELOC_EXTERN_P(r)) {
- if (RELOC_BASEREL_P(r))
- errx(1, "%s: Unsupported relocation type",
- get_file_name(entry));
- continue;
- }
-
- symindex = RELOC_SYMBOL(r);
- sp = entry->symbols[symindex].symbol;
-
- if (symindex >= entry->header.a_syms)
- errx(1, "%s: relocation symbolnum out of range",
- get_file_name(entry));
-
-#ifdef N_INDR
- /* Resolve indirection. */
- if ((sp->defined & ~N_EXT) == N_INDR) {
- if (sp->alias == NULL)
- errx(1, "internal error: alias in hyperspace");
- sp = sp->alias;
- }
-#endif
-
- symtype = sp->defined & N_TYPE;
-
- if (!pic_code_seen && ( symtype == N_BSS ||
- symtype == N_DATA ||
- symtype == N_TEXT ||
- symtype == N_ABS)) {
- RELOC_EXTERN_P(r) = 0;
- RELOC_SYMBOL(r) = symtype;
- } else
- /*
- * Global symbols come first.
- */
- RELOC_SYMBOL(r) =
- entry->symbols[symindex].symbol->symbolnum;
- }
- md_swapout_reloc(entry->datarel, entry->ndatarel);
- mywrite(entry->datarel, entry->ndatarel,
- sizeof(struct relocation_info), outstream);
-}
-
-void write_file_syms __P((struct file_entry *, int *));
-void write_string_table __P((void));
-
-/* Offsets and current lengths of symbol and string tables in output file. */
-
-static int symtab_offset;
-static int symtab_len;
-
-/* Address in output file where string table starts. */
-static int strtab_offset;
-
-/* Offset within string table
- where the strings in `strtab_vector' should be written. */
-static int strtab_len;
-
-/* Total size of string table strings allocated so far,
- including strings in `strtab_vector'. */
-static int strtab_size;
-
-/* Vector whose elements are strings to be added to the string table. */
-static char **strtab_vector;
-
-/* Vector whose elements are the lengths of those strings. */
-static int *strtab_lens;
-
-/* Index in `strtab_vector' at which the next string will be stored. */
-static int strtab_index;
-
-/*
- * Add the string NAME to the output file string table. Record it in
- * `strtab_vector' to be output later. Return the index within the string
- * table that this string will have.
- */
-
-static int
-assign_string_table_index(name)
- char *name;
-{
- register int index = strtab_size;
- register int len = strlen(name) + 1;
-
- strtab_size += len;
- strtab_vector[strtab_index] = name;
- strtab_lens[strtab_index++] = len;
-
- return index;
-}
-
-/*
- * Write the contents of `strtab_vector' into the string table. This is done
- * once for each file's local&debugger symbols and once for the global
- * symbols.
- */
-void
-write_string_table()
-{
- register int i;
-
- if (fseek(outstream, strtab_offset + strtab_len, SEEK_SET) != 0)
- err(1, "write_string_table: %s: fseek", output_filename);
-
- for (i = 0; i < strtab_index; i++) {
- mywrite(strtab_vector[i], strtab_lens[i], 1, outstream);
- strtab_len += strtab_lens[i];
- }
-}
-
-/* Write the symbol table and string table of the output file. */
-
-void
-write_syms()
-{
- /* Number of symbols written so far. */
- int syms_written = 0;
- struct nlist nl;
-
- /*
- * Buffer big enough for all the global symbols. One extra struct
- * for each indirect symbol to hold the extra reference following.
- */
- struct nlist *buf = (struct nlist *)
- alloca(global_sym_count * sizeof(struct nlist));
- /* Pointer for storing into BUF. */
- register struct nlist *bufp = buf;
-
- /* Size of string table includes the bytes that store the size. */
- strtab_size = sizeof strtab_size;
-
- symtab_offset = N_SYMOFF(outheader);
- symtab_len = 0;
- strtab_offset = N_STROFF(outheader);
- strtab_len = strtab_size;
-
- if (strip_symbols == STRIP_ALL)
- return;
-
- /* First, write out the global symbols. */
-
- /*
- * Allocate two vectors that record the data to generate the string
- * table from the global symbols written so far. This must include
- * extra space for the references following indirect outputs.
- */
-
- strtab_vector = (char **)alloca((global_sym_count) * sizeof(char *));
- strtab_lens = (int *)alloca((global_sym_count) * sizeof(int));
- strtab_index = 0;
-
- /*
- * __DYNAMIC symbol *must* be first for Sun compatibility, as Sun's
- * ld.so reads the shared object's first symbol. This means that
- * (Sun's) shared libraries cannot be stripped! (We only assume
- * that __DYNAMIC is the first item in the data segment)
- *
- * If defined (ie. not relocatable_output), make it look
- * like an internal symbol.
- */
- if (dynamic_symbol->flags & GS_REFERENCED) {
- nl.n_other = 0;
- nl.n_desc = 0;
- nl.n_type = dynamic_symbol->defined;
- if (nl.n_type == N_UNDF)
- nl.n_type |= N_EXT;
- else
- nl.n_type &= ~N_EXT;
- nl.n_value = dynamic_symbol->value;
- nl.n_un.n_strx = assign_string_table_index(dynamic_symbol->name);
- *bufp++ = nl;
- syms_written++;
- }
-
- /* Scan the symbol hash table, bucket by bucket. */
-
- FOR_EACH_SYMBOL(i, sp) {
-
- if (sp == dynamic_symbol)
- /* Already dealt with above */
- continue;
-
- /*
- * Propagate N_WARNING symbols.
- */
- if ((relocatable_output || building_shared_object)
- && sp->warning) {
- nl.n_type = N_WARNING;
- nl.n_un.n_strx = assign_string_table_index(sp->warning);
- nl.n_value = 0;
- nl.n_other = 0;
- nl.n_desc = 0;
- *bufp++ = nl;
- syms_written++;
-
- nl.n_type = N_UNDF + N_EXT;
- nl.n_un.n_strx = assign_string_table_index(sp->name);
- nl.n_value = 0;
- nl.n_other = 0;
- nl.n_desc = 0;
- *bufp++ = nl;
- syms_written++;
- }
-
- if (!(sp->flags & GS_REFERENCED))
- /* Came from shared object but was not used */
- continue;
-
- if (sp->so_defined || (sp->alias && sp->alias->so_defined))
- /*
- * Definition came from shared object,
- * don't mention it here
- */
- continue;
-
- if (!sp->defined && !relocatable_output) {
- /*
- * We're building a shared object and there
- * are still undefined symbols. Don't output
- * these, symbol was discounted in digest_pass1()
- * (they are in the RRS symbol table).
- */
- if (building_shared_object)
- continue;
- if (!(sp->flags & GS_WEAK))
- warnx("symbol %s remains undefined", demangle(sp->name));
- }
-
- if (syms_written >= global_sym_count)
- errx(1,
- "internal error: number of symbols exceeds alloc'd %d",
- global_sym_count);
-
- /*
- * Construct a `struct nlist' for the symbol.
- */
- nl.n_other = 0;
- nl.n_desc = 0;
-
- if (sp->defined > 1) {
- /*
- * defined with known type
- */
- if (!relocatable_output && !building_shared_object &&
- sp->alias && sp->alias->defined > 1) {
- /*
- * If the target of an indirect symbol has
- * been defined and we are outputting an
- * executable, resolve the indirection; it's
- * no longer needed.
- */
- nl.n_type = sp->alias->defined;
- nl.n_value = sp->alias->value;
- nl.n_other = N_OTHER(0, sp->alias->aux);
- } else {
- int bind = 0;
-
- if (sp->defined == N_SIZE)
- nl.n_type = N_DATA | N_EXT;
- else
- nl.n_type = sp->defined;
- if (nl.n_type == (N_INDR|N_EXT) &&
- sp->value != 0)
- errx(1, "%s: N_INDR has value %#lx",
- demangle(sp->name), sp->value);
- nl.n_value = sp->value;
- if (sp->def_lsp)
- bind = N_BIND(&sp->def_lsp->nzlist.nlist);
- nl.n_other = N_OTHER(bind, sp->aux);
- }
-
- } else if (sp->common_size) {
- /*
- * defined as common but not allocated,
- * happens only with -r and not -d, write out
- * a common definition.
- *
- * common condition needs to be before undefined
- * condition because unallocated commons are set
- * undefined in digest_symbols.
- */
- nl.n_type = N_UNDF | N_EXT;
- nl.n_value = sp->common_size;
- } else if (!sp->defined) {
- /* undefined -- legit only if -r */
- nl.n_type = N_UNDF | N_EXT;
- nl.n_value = 0;
- } else
- errx(1,
- "internal error: %s defined in mysterious way",
- demangle(sp->name));
-
- /*
- * Allocate string table space for the symbol name.
- */
-
- nl.n_un.n_strx = assign_string_table_index(sp->name);
-
- /* Output to the buffer and count it. */
-
- *bufp++ = nl;
- syms_written++;
-
- /*
- * Write second symbol of an alias pair.
- */
- if (nl.n_type == N_INDR + N_EXT) {
- if (sp->alias == NULL)
- errx(1, "internal error: alias in hyperspace");
- nl.n_type = N_UNDF + N_EXT;
- nl.n_un.n_strx =
- assign_string_table_index(sp->alias->name);
- nl.n_value = 0;
- nl.n_other = 0;
- nl.n_desc = 0;
- *bufp++ = nl;
- syms_written++;
- }
-
- /*
- * Write N_SIZE symbol for a symbol with a known size.
- */
- if (relocatable_output && sp->size) {
- nl.n_type = N_SIZE + N_EXT;
- nl.n_un.n_strx = assign_string_table_index(sp->name);
- nl.n_value = sp->size;
- nl.n_other = 0;
- nl.n_desc = 0;
- *bufp++ = nl;
- syms_written++;
- }
-
-#ifdef DEBUG
-printf("writesym(#%d): %s, type %x\n", syms_written, demangle(sp->name), sp->defined);
-#endif
- } END_EACH_SYMBOL;
-
- if (syms_written != strtab_index || strtab_index != global_sym_count)
- errx(1, "internal error: wrong number (%d) of global symbols "
- "written into output file, should be %d",
- syms_written, global_sym_count);
-
- /* Output the buffer full of `struct nlist's. */
-
- if (fseek(outstream, symtab_offset + symtab_len, SEEK_SET) != 0)
- err(1, "write_syms: fseek");
- md_swapout_symbols(buf, bufp - buf);
- mywrite(buf, bufp - buf, sizeof(struct nlist), outstream);
- symtab_len += sizeof(struct nlist) * (bufp - buf);
-
- /* Write the strings for the global symbols. */
- write_string_table();
-
- /* Write the local symbols defined by the various files. */
- each_file(write_file_syms, (void *)&syms_written);
- file_close();
-
- if (syms_written != nsyms)
- errx(1, "internal error: wrong number of symbols (%d) "
- "written into output file, should be %d",
- syms_written, nsyms);
-
- if (symtab_offset + symtab_len != strtab_offset)
- errx(1,
- "internal error: inconsistent symbol table length: %d vs %d",
- symtab_offset + symtab_len, strtab_offset);
-
- if (fseek(outstream, strtab_offset, SEEK_SET) != 0)
- err(1, "write_syms: fseek");
- strtab_size = md_swap_long(strtab_size);
- mywrite(&strtab_size, sizeof(int), 1, outstream);
-}
-
-
-/*
- * Write the local and debugger symbols of file ENTRY. Increment
- * *SYMS_WRITTEN_ADDR for each symbol that is written.
- */
-
-/*
- * Note that we do not combine identical names of local symbols. dbx or gdb
- * would be confused if we did that.
- */
-void
-write_file_syms(entry, syms_written_addr)
- struct file_entry *entry;
- int *syms_written_addr;
-{
- struct localsymbol *lsp, *lspend;
-
- /* Upper bound on number of syms to be written here. */
- int max_syms = entry->nsymbols + 1;
-
- /*
- * Buffer to accumulate all the syms before writing them. It has one
- * extra slot for the local symbol we generate here.
- */
- struct nlist *buf = (struct nlist *)
- alloca(max_syms * sizeof(struct nlist));
-
- register struct nlist *bufp = buf;
-
- if (entry->flags & E_DYNAMIC)
- return;
-
- /*
- * Make tables that record, for each symbol, its name and its name's
- * length. The elements are filled in by `assign_string_table_index'.
- */
-
- strtab_vector = (char **)alloca(max_syms * sizeof(char *));
- strtab_lens = (int *)alloca(max_syms * sizeof(int));
- strtab_index = 0;
-
- /* Generate a local symbol for the start of this file's text. */
-
- if (discard_locals != DISCARD_ALL) {
- struct nlist nl;
-
- nl.n_type = N_FN | N_EXT;
- nl.n_un.n_strx =
- assign_string_table_index(entry->local_sym_name);
- nl.n_value = entry->text_start_address;
- nl.n_desc = 0;
- nl.n_other = 0;
- *bufp++ = nl;
- (*syms_written_addr)++;
- }
- /* Read the file's string table. */
-
- entry->strings = (char *)alloca(entry->string_size);
- read_entry_strings(file_open(entry), entry);
-
- lspend = entry->symbols + entry->nsymbols;
-
- for (lsp = entry->symbols; lsp < lspend; lsp++) {
- register struct nlist *p = &lsp->nzlist.nlist;
- char *name;
-
- if (!(lsp->flags & LS_WRITE))
- continue;
-
- if (discard_locals == DISCARD_ALL ||
- (discard_locals == DISCARD_L &&
- (lsp->flags & LS_L_SYMBOL))) {
- /*
- * The user wants to discard this symbol, but it
- * is referenced by a relocation. We can still
- * save some file space by suppressing the unique
- * renaming of the symbol.
- */
- lsp->flags &= ~LS_RENAME;
- }
-
- if (p->n_un.n_strx == 0)
- name = NULL;
- else if (!(lsp->flags & LS_RENAME))
- name = p->n_un.n_strx + entry->strings;
- else {
- char *cp = p->n_un.n_strx + entry->strings;
- name = (char *)alloca(
- strlen(entry->local_sym_name) +
- strlen(cp) + 2 );
- (void)sprintf(name, "%s.%s", entry->local_sym_name, cp);
- }
-
- /*
- * If this symbol has a name, allocate space for it
- * in the output string table.
- */
-
- if (name)
- p->n_un.n_strx = assign_string_table_index(name);
-
- /* Output this symbol to the buffer and count it. */
-
- *bufp++ = *p;
- (*syms_written_addr)++;
- }
-
- /* All the symbols are now in BUF; write them. */
-
- if (fseek(outstream, symtab_offset + symtab_len, SEEK_SET) != 0)
- err(1, "write local symbols: fseek");
- md_swapout_symbols(buf, bufp - buf);
- mywrite(buf, bufp - buf, sizeof(struct nlist), outstream);
- symtab_len += sizeof(struct nlist) * (bufp - buf);
-
- /*
- * Write the string-table data for the symbols just written, using
- * the data in vectors `strtab_vector' and `strtab_lens'.
- */
-
- write_string_table();
- entry->strings = 0; /* Since it will disappear anyway. */
-}
-
-/*
- * Parse the string ARG using scanf format FORMAT, and return the result.
- * If it does not parse, report fatal error
- * generating the error message using format string ERROR and ARG as arg.
- */
-
-static int
-parse(arg, format, error)
- char *arg, *format, *error;
-{
- int x;
-
- if (1 != sscanf(arg, format, &x))
- errx(1, error, arg);
- return x;
-}
-
-/*
- * Output COUNT*ELTSIZE bytes of data at BUF to the descriptor FD.
- */
-void
-mywrite(buf, count, eltsize, fd)
- void *buf;
- int count;
- int eltsize;
- FILE *fd;
-{
-
- if (fwrite(buf, eltsize, count, fd) != count)
- err(1, "write");
-}
-
-static void
-cleanup()
-{
- struct stat statbuf;
-
- if (outstream == 0)
- return;
-
- if (fstat(fileno(outstream), &statbuf) == 0) {
- if (S_ISREG(statbuf.st_mode))
- (void)unlink(output_filename);
- }
-}
-
-/*
- * Output PADDING zero-bytes to descriptor FD.
- * PADDING may be negative; in that case, do nothing.
- */
-void
-padfile(padding, fd)
- int padding;
- FILE *fd;
-{
- register char *buf;
- if (padding <= 0)
- return;
-
- buf = (char *)alloca(padding);
- bzero(buf, padding);
- mywrite(buf, padding, 1, fd);
-}
-
-static void
-list_files()
-{
- int error, i;
-
- error = 0;
- for (i = 0; i < number_of_files; i++) {
- register struct file_entry *entry = &file_table[i];
- int fd;
-
- if (entry->flags & E_SEARCH_DIRS)
- fd = findlib(entry);
- else
- fd = open(entry->filename, O_RDONLY, 0);
- if (fd < 0)
- error = 1;
- else
- close(fd);
-
- /*
- * Print the name even if the file doesn't exist except in
- * the -lfoo case. This allows `ld -f' to work as well as
- * possible when it is used to generate dependencies before
- * the libraries exist.
- */
- if (fd >= 0 || !(entry->flags & E_SEARCH_DIRS))
- printf("%s\n", entry->filename);
- }
- exit(error);
-}
OpenPOWER on IntegriCloud