} #if 0 if (sp->flags & GS_REFERENCED) sp->alias->flags |= GS_REFERENCED; #endif
if (sp->flags & GS_REFERENCED) { if (!(sp->alias->flags & GS_REFERENCED)) { sp->alias->flags |= GS_REFERENCED; if (!sp->alias->defined) undefined_global_sym_count++; } } }
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 *));intmain(argc, argv)	int	argc;	char	*argv[];{	if (atexit(cleanup))		err(1, "atexit");	/* 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);	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 intclassify_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 'R':	case 'l':	case 'o':	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;	case 'T':		if (arg[2] == 0)			return 2;		if (!strcmp(&arg[2], "text"))			return 2;		if (!strcmp(&arg[2], "data"))			return 2;		return 1;	/* GNU binutils 2.x  forward-compatible flags. */	case 'r':		/* Ignore "-rpath" and hope ld.so.conf will cover our sins. */		if (!strcmp(&arg[1], "rpath"))			return 2;		return 1;	case 's':		/* Treat "-shared" and "-soname' like binutils 2.x does. */		if (!strcmp(&arg[1], "shared"))			return 1;		if (!strcmp(&arg[1], "soname"))			return 2;		break;	}	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 voiddecode_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)		errx(1, "no input files");	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, -B 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, "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 (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 && getenv("LD_NOSTD_PATH") == NULL)		std_search_path();}voidadd_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;}intset_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 voiddecode_option(swt, arg)	register char  *swt, *arg;{	if (!strcmp(swt + 1, "Bstatic"))		return;	if (!strcmp(swt + 1, "Bdynamic"))		return;	if (!strcmp(swt + 1, "Bsymbolic"))		return;	if (!strcmp(swt + 1, "Bforcearchive"))		return;	if (!strcmp(swt + 1, "Bshareable")) {		if (warn_obsolete_syntax)			warnx("-Bshareable: obsolete syntax");		return;	}				if (!strcmp(swt + 1, "assert"))		return;#ifdef GNU_BINUTIL_COMPAT	if (strcmp(swt + 1, "-whole-archive") == 0) {		/* XXX incomplete emulation */		link_mode |= FORCEARCHIVE;		if (warn_forwards_compatible_inexact)			warnx("-no-whole-archive treated as -Bshareable");		return;	}	if (strcmp(swt + 1, "-no-whole-archive") == 0) {		/* XXX incomplete emulation */		if (warn_forwards_compatible_inexact)			warnx("-no-whole-archive ignored");		return;	}	if (strcmp(swt + 1, "shared") == 0) {		link_mode |= SHAREABLE;#ifdef DEBUG_COMPAT		warnx("-shared treated as -Bshareable");#endif		return;	}	if (strcmp(swt + 1, "soname") == 0) {		if (warn_forwards_compatible_inexact)			warnx("-soname %s ignored", arg);		return;	}	if (strcmp(swt + 1, "rpath") == 0) {		if (warn_forwards_compatible_inexact)			warnx("%s %s ignored", swt, arg);		goto do_rpath;	}#endif /* GNU_BINUTIL_COMPAT */#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 'l':		return;	case 'L':		add_search_dir(arg);		return;	case 'R':do_rpath:		rrs_search_paths = (rrs_search_paths == NULL)			? strdup(arg)			: concat(rrs_search_paths, ":", arg);		return;	case 'M':		write_map = 1;		return;	case 'N':		magic = OMAGIC;		return;	case 'n':		magic = NMAGIC;		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 '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. */voideach_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 longcheck_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.  */voideach_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.  */voidfile_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. */intfile_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;}inttext_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. */voidread_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. */voidread_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. */voidread_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 */voidread_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 voidload_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). */voidread_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. */voidenter_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), 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 voidenter_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;		} else {			if ((entry->flags & E_DYNAMIC) == 0)				global_alias_count++;		}#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;			if (sp != dynamic_symbol && sp != got_symbol)				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",			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 ", 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 longcontains_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 voiddigest_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) {		text_pad = PALIGN(text_size, page_size) - text_size;		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 DEBUGprintf("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 DEBUGprintf("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 voiddigest_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;		struct nlist	*q = NULL;		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",						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",					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++;				}		/* Let WEAK symbols take precedence over second class */				if (q != NULL && N_ISWEAK(q) && 					(lsp->entry->flags & E_SECONDCLASS))					continue;				q = p;				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 DEBUGprintf("pass1: SO definition for %s, type %x in %s at %#x\n",	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",					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",					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 voidconsider_relocation(entry, dataseg)	struct file_entry	*entry;	int			dataseg;{	struct relocation_info	*reloc, *end;	struct localsymbol	*lsp;	symbol			*sp;#ifdef ALLOW_SPARC_MIX	static int locked_pic_small = 0;#endif	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",						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);/* sparc assembler instructions sometimes hold RELOC_22/RELOC_11,   even when using the small -fpic model. This should not yield   an error though.  The linker is still thoroughly unsubtle about it   and constrains everything to +/-4096 of the GOT */#ifdef ALLOW_SPARC_MIX			if (!locked_pic_small) {				if (pic_type != PIC_TYPE_NONE &&					 RELOC_PIC_TYPE(reloc) != pic_type) {					warnx("%s: reloc type mix, enforcing pic model",						get_file_name(entry));					pic_type = PIC_TYPE_SMALL;					locked_pic_small = 1;				} 				else					pic_type = RELOC_PIC_TYPE(reloc);			} #else			pic_type = RELOC_PIC_TYPE(reloc);			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);#endif		} 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",					    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 voidconsider_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 voidconsider_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 voidrelocate_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 DEBUGprintf("%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 voiddigest_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) {				if (building_shared_object &&				    !sp->alias->defined)					/* Exclude aliases in shared objects */					continue;				/*				 * 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",						sp->name);				sp->defined = sp->so_defined;				sp->so_defined = 0;			}			defined_global_sym_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 %#x\n",					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", 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", 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 %x\n",				sp->defined==(N_BSS|N_EXT)?"common":"data",				sp->name, size, sp->value);	} END_EACH_SYMBOL;}