diff options
Diffstat (limited to 'gnu/usr.bin/ld/ld.c')
-rw-r--r-- | gnu/usr.bin/ld/ld.c | 903 |
1 files changed, 547 insertions, 356 deletions
diff --git a/gnu/usr.bin/ld/ld.c b/gnu/usr.bin/ld/ld.c index ad6f9a6..1d63c82 100644 --- a/gnu/usr.bin/ld/ld.c +++ b/gnu/usr.bin/ld/ld.c @@ -32,7 +32,7 @@ static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91"; Set, indirect, and warning symbol features added by Randy Smith. */ /* - * $Id: ld.c,v 1.18 1994/01/03 18:35:14 davidg Exp $ + * $Id: ld.c,v 1.19 1994/01/19 15:00:27 davidg Exp $ */ /* Define how to initialize system-dependent header fields. */ @@ -55,17 +55,18 @@ static char sccsid[] = "@(#)ld.c 6.10 (Berkeley) 5/22/91"; #include "ld.h" -#ifndef DEFAULT_SOVERSION -#define DEFAULT_SOVERSION LD_VERSION_BSD -#endif - -int building_shared_object; +/* 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. */ +/* 1 => write relocation into output file so can re-input it later. */ int relocatable_output; -/* Non zero means to create the output executable. */ -/* Cleared by nonfatal errors. */ +/* 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 */ @@ -81,9 +82,72 @@ int force_alias_definition; 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; +/* 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 */ + +/* + * 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. */ +int outdesc; /* 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; +int entry_offset; + +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. */ +struct glosym **cmdline_references; +int cl_refs_allocated; + /* * Which symbols should be stripped (omitted from the output): none, all, or * debugger symbols. @@ -100,11 +164,33 @@ enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals; -/* Nonzero means print names of input files as processed. */ -int trace_files; +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 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. + */ +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 warning_count; /* # of warning symbols encountered. */ -/* Magic number to use for the output file, set by switch. */ -int magic; +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. @@ -137,6 +223,7 @@ 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)); @@ -144,6 +231,7 @@ 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)); @@ -151,7 +239,15 @@ 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 myfatal __P((void)); + int main(argc, argv) @@ -189,6 +285,7 @@ main(argc, argv) data_pad = 0; text_pad = 0; + page_align_segments = 0; page_align_data = 0; /* Initialize the data about options. */ @@ -251,6 +348,9 @@ main(argc, argv) * 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); @@ -430,15 +530,15 @@ decode_command(argc, argv) fatal("-A specified before an input file other than the first"); p->filename = string; p->local_sym_name = string; - p->just_syms_flag = 1; + p->flags |= E_JUST_SYMS; p++; } if (argv[i][1] == 'l') { p->filename = string; p->local_sym_name = concat("-l", string, ""); - p->search_dirs_flag = 1; + p->flags |= E_SEARCH_DIRS; if (link_mode & DYNAMIC && !relocatable_output) - p->search_dynamic_flag = 1; + p->flags |= E_SEARCH_DYNAMIC; p++; } i += code - 1; @@ -446,8 +546,8 @@ decode_command(argc, argv) /* Now check some option settings for consistency. */ - if ((magic != OMAGIC) - && (text_start - text_start_alignment) & (page_size - 1)) + if (page_align_segments + && (text_start - text_start_alignment) & (page_size - 1)) fatal("-T argument not multiple of page size, with sharable output"); /* Append the standard search directories to the user-specified ones. */ @@ -456,9 +556,9 @@ decode_command(argc, argv) void add_cmdline_ref(sp) - struct glosym *sp; + symbol *sp; { - struct glosym **ptr; + symbol **ptr; for (ptr = cmdline_references; ptr < cmdline_references + cl_refs_allocated && *ptr; @@ -474,7 +574,7 @@ add_cmdline_ref(sp) ptr = cmdline_references + diff; } *ptr++ = sp; - *ptr = (struct glosym *) 0; + *ptr = (symbol *) 0; } int @@ -505,7 +605,6 @@ static void decode_option(swt, arg) register char *swt, *arg; { - /* We get Bstatic from gcc on suns. */ if (!strcmp(swt + 1, "Bstatic")) return; if (!strcmp(swt + 1, "Bdynamic")) @@ -558,9 +657,10 @@ decode_option(swt, arg) case 'e': entry_symbol = getsym(arg); - if (!entry_symbol->defined && !entry_symbol->referenced) + if (!entry_symbol->defined && + !(entry_symbol->flags & GS_REFERENCED)) undefined_global_sym_count++; - entry_symbol->referenced = 1; + entry_symbol->flags |= GS_REFERENCED; add_cmdline_ref(entry_symbol); return; @@ -579,19 +679,9 @@ decode_option(swt, arg) magic = OMAGIC; return; -#ifdef NMAGIC case 'n': magic = NMAGIC; return; -#endif - - case 'Q': - magic = QMAGIC; - return; - case 'Z': - magic = ZMAGIC; - netzmagic = 1; - return; case 'o': output_filename = arg; @@ -601,6 +691,12 @@ decode_option(swt, arg) page_align_data = 1; return; +#ifdef QMAGIC + case 'Q': + magic = QMAGIC; + return; +#endif + case 'r': relocatable_output = 1; magic = OMAGIC; @@ -628,9 +724,9 @@ decode_option(swt, arg) { register symbol *sp = getsym(arg); - if (!sp->defined && !sp->referenced) + if (!sp->defined && !(sp->flags & GS_REFERENCED)) undefined_global_sym_count++; - sp->referenced = 1; + sp->flags |= GS_REFERENCED; add_cmdline_ref(sp); } return; @@ -652,12 +748,17 @@ decode_option(swt, arg) case 'y': { register symbol *sp = getsym(&swt[2]); - sp->trace = 1; + sp->flags |= GS_TRACE; } return; case 'z': magic = ZMAGIC; + oldmagic = 0; + return; + + case 'Z': + magic = oldmagic = ZMAGIC; return; default: @@ -686,15 +787,15 @@ each_file(function, arg) register struct file_entry *entry = &file_table[i]; register struct file_entry *subentry; - if (entry->scrapped) + if (entry->flags & E_SCRAPPED) continue; - if (!entry->library_flag) + if (!(entry->flags & E_IS_LIBRARY)) (*function) (entry, arg); subentry = entry->subfiles; for (; subentry; subentry = subentry->chain) { - if (subentry->scrapped) + if (subentry->flags & E_SCRAPPED) continue; (*function) (subentry, arg); } @@ -702,15 +803,15 @@ each_file(function, arg) #ifdef SUN_COMPAT if (entry->silly_archive) { - if (!entry->is_dynamic) + if (!(entry->flags & E_DYNAMIC)) error("Silly"); - if (!entry->silly_archive->library_flag) + if (!(entry->silly_archive->flags & E_IS_LIBRARY)) error("Sillier"); subentry = entry->silly_archive->subfiles; for (; subentry; subentry = subentry->chain) { - if (subentry->scrapped) + if (subentry->flags & E_SCRAPPED) continue; (*function) (subentry, arg); } @@ -738,12 +839,12 @@ check_each_file(function, arg) for (i = 0; i < number_of_files; i++) { register struct file_entry *entry = &file_table[i]; - if (entry->scrapped) + if (entry->flags & E_SCRAPPED) continue; - if (entry->library_flag) { + if (entry->flags & E_IS_LIBRARY) { register struct file_entry *subentry = entry->subfiles; for (; subentry; subentry = subentry->chain) { - if (subentry->scrapped) + if (subentry->flags & E_SCRAPPED) continue; if (return_val = (*function) (subentry, arg)) return return_val; @@ -767,35 +868,35 @@ each_full_file(function, arg) register struct file_entry *entry = &file_table[i]; register struct file_entry *subentry; - if (entry->scrapped || entry->just_syms_flag) + if (entry->flags & (E_SCRAPPED | E_JUST_SYMS)) continue; #ifdef SUN_COMPAT if (entry->silly_archive) { - if (!entry->is_dynamic) + if (!(entry->flags & E_DYNAMIC)) error("Silly"); - if (!entry->silly_archive->library_flag) + if (!(entry->silly_archive->flags & E_IS_LIBRARY)) error("Sillier"); subentry = entry->silly_archive->subfiles; for (; subentry; subentry = subentry->chain) { - if (subentry->scrapped) + if (subentry->flags & E_SCRAPPED) continue; (*function) (subentry, arg); } } #endif - if (entry->is_dynamic) + if (entry->flags & E_DYNAMIC) continue; - if (!entry->library_flag) + if (!(entry->flags & E_IS_LIBRARY)) (*function) (entry, arg); subentry = entry->subfiles; for (; subentry; subentry = subentry->chain) { - if (subentry->scrapped) + if (subentry->flags & E_SCRAPPED) continue; (*function) (subentry, arg); } @@ -824,7 +925,7 @@ file_open (entry) { register int desc; - if (entry->superfile && entry->superfile->library_flag) + if (entry->superfile && (entry->superfile->flags & E_IS_LIBRARY)) return file_open (entry->superfile); if (entry == input_file) @@ -832,7 +933,7 @@ file_open (entry) if (input_file) file_close (); - if (entry->search_dirs_flag) { + if (entry->flags & E_SEARCH_DIRS) { desc = findlib(entry); } else desc = open (entry->filename, O_RDONLY, 0); @@ -853,8 +954,8 @@ text_offset (entry) { return entry->starting_offset + N_TXTOFF (entry->header); } - -/* Medium-level input routines for rel files. */ + +/*---------------------------------------------------------------------------*/ /* * Read a file's header into the proper place in the file_entry. DESC is the @@ -865,8 +966,7 @@ read_header (desc, entry) int desc; register struct file_entry *entry; { - register int len; - struct exec *loc = (struct exec *) &entry->header; + register int len, mid; if (lseek (desc, entry->starting_offset, L_SET) != entry->starting_offset) @@ -878,10 +978,13 @@ read_header (desc, entry) md_swapin_exec_hdr(&entry->header); - if (N_BADMAG (*loc)) + if (N_BADMAG (entry->header)) fatal_with_file ("bad magic number in ", entry); - entry->header_read_flag = 1; + if (N_BADMID(entry->header)) + fatal_with_file ("non-native input file ", entry); + + entry->flags |= E_HEADER_VALID; } /* @@ -899,7 +1002,7 @@ read_entry_symbols (desc, entry) struct nlist *np; int i; - if (!entry->header_read_flag) + if (!(entry->flags & E_HEADER_VALID)) read_header (desc, entry); np = (struct nlist *) alloca (entry->header.a_syms); @@ -921,11 +1024,9 @@ read_entry_symbols (desc, entry) 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].gotslot_claimed = 0; - entry->symbols[i].write = 0; - entry->symbols[i].is_L_symbol = 0; - entry->symbols[i].rename = 0; + entry->symbols[i].flags = 0; } entry->strings_offset = N_STROFF(entry->header) + @@ -949,7 +1050,7 @@ read_entry_strings (desc, entry) { int buffer; - if (!entry->header_read_flag || !entry->strings_offset) + if (!(entry->flags & E_HEADER_VALID) || !entry->strings_offset) fatal_with_file("internal error: cannot read string table for ", entry); @@ -963,14 +1064,6 @@ read_entry_strings (desc, entry) return; } -/* DEAD - Read in all of the relocation information */ - -void -read_relocation () -{ - each_full_file (read_entry_relocation, 0); -} - /* Read in the relocation sections of ENTRY if necessary */ void @@ -1026,23 +1119,24 @@ read_entry_relocation (desc, entry) } } - -/* Read in the symbols of all input files. */ - +/*---------------------------------------------------------------------------*/ -void +/* + * Read in the symbols of all input files. + */ +static void load_symbols () { register int i; - if (trace_files) fprintf (stderr, "Loading symbols:\n\n"); + if (trace_files) + fprintf(stderr, "Loading symbols:\n\n"); - for (i = 0; i < number_of_files; i++) { - register struct file_entry *entry = &file_table[i]; - read_file_symbols (entry); - } + for (i = 0; i < number_of_files; i++) + read_file_symbols(&file_table[i]); - if (trace_files) fprintf (stderr, "\n"); + if (trace_files) + fprintf (stderr, "\n"); } /* @@ -1068,18 +1162,18 @@ read_file_symbols (entry) md_swapin_exec_hdr(&hdr); if (!N_BADMAG (hdr)) { - if (N_IS_DYNAMIC(hdr)) { + if (N_IS_DYNAMIC(hdr) && !(entry->flags & E_JUST_SYMS)) { if (relocatable_output) { fatal_with_file( "-r and shared objects currently not supported ", entry); return; } - entry->is_dynamic = 1; + entry->flags |= E_DYNAMIC; if (entry->superfile || rrs_add_shobj(entry)) read_shared_object(desc, entry); else - entry->scrapped = 1; + entry->flags |= E_SCRAPPED; } else { read_entry_symbols (desc, entry); entry->strings = (char *) alloca (entry->string_size); @@ -1096,14 +1190,17 @@ read_file_symbols (entry) strncmp (armag, ARMAG, SARMAG)) fatal_with_file( "malformed input file (not rel or archive) ", entry); - entry->library_flag = 1; + entry->flags |= E_IS_LIBRARY; search_library (desc, entry); } file_close (); } - -/* Enter the external symbol defs and refs of ENTRY in the hash table. */ + + +/* + * Enter the external symbol defs and refs of ENTRY in the hash table. + */ void enter_file_symbols (entry) @@ -1160,7 +1257,7 @@ enter_file_symbols (entry) 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->is_L_symbol = 1; + lsp->flags |= LS_L_SYMBOL; } } @@ -1190,9 +1287,9 @@ enter_global_ref (lsp, name, entry) register struct nzlist *nzp = &lsp->nzlist; register symbol *sp = getsym (name); register int type = nzp->nz_type; - int oldref = sp->referenced; + int oldref = (sp->flags & GS_REFERENCED); int olddef = sp->defined; - int com = sp->defined && sp->max_common_size; + int com = sp->defined && sp->common_size; if (type == (N_INDR | N_EXT)) { sp->alias = getsym(entry->strings + (lsp + 1)->nzlist.nz_strx); @@ -1208,7 +1305,7 @@ enter_global_ref (lsp, name, entry) } } - if (entry->is_dynamic) { + if (entry->flags & E_DYNAMIC) { lsp->next = sp->sorefs; sp->sorefs = lsp; @@ -1223,11 +1320,17 @@ enter_global_ref (lsp, name, entry) if (oldref) undefined_global_sym_count--; common_defined_global_count++; - sp->max_common_size = nzp->nz_value; + sp->common_size = nzp->nz_value; sp->defined = N_UNDF | N_EXT; - } else if (com && sp->max_common_size < nzp->nz_value) { - sp->max_common_size = nzp->nz_value; + } 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... + */ + sp->common_size = 0; + sp->defined = 0; } /* @@ -1244,10 +1347,10 @@ enter_global_ref (lsp, name, entry) sp->refs = lsp; lsp->symbol = sp; - sp->referenced = 1; + sp->flags |= GS_REFERENCED; if (sp == dynamic_symbol || sp == got_symbol) { - if (type != (N_UNDF | N_EXT) && !entry->just_syms_flag) + if (type != (N_UNDF | N_EXT) && !(entry->flags & E_JUST_SYMS)) fatal("Linker reserved symbol %s defined as type %x ", name, type); return; @@ -1281,33 +1384,38 @@ enter_global_ref (lsp, name, entry) * First definition and it's common. */ common_defined_global_count++; - sp->max_common_size = nzp->nz_value; + 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->max_common_size = 0; + sp->common_size = 0; } else if (com && type == (N_UNDF | N_EXT) - && sp->max_common_size < nzp->nz_value) + && 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->max_common_size = nzp->nz_value; + sp->common_size = nzp->nz_value; if (SET_ELEMENT_P(type) && (!olddef || com)) set_vector_count++; - } else if (!oldref) + } else if (!oldref && !com) + /* + * An unreferenced symbol can already be defined + * as common by shared objects. + */ undefined_global_sym_count++; - if (sp == end_symbol && entry->just_syms_flag && !T_flag_specified) + if (sp == end_symbol && (entry->flags & E_JUST_SYMS) && + !T_flag_specified) text_start = nzp->nz_value; - if (sp->trace) { + if (sp->flags & GS_TRACE) { register char *reftype; switch (type & N_TYPE) { case N_UNDF: @@ -1343,7 +1451,7 @@ enter_global_ref (lsp, name, entry) } /* - * This return 0 if the given file entry's symbol table does *not* contain + * 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. */ @@ -1391,7 +1499,6 @@ contains_symbol (entry, np) * */ - static void digest_symbols () { @@ -1419,6 +1526,8 @@ digest_symbols () each_full_file(consider_relocation, 0); /* Text */ each_full_file(consider_relocation, 1); /* Data */ + each_file(consider_local_symbols, 0); + /* * Compute total size of sections. * RRS data is the first output data section, RRS text is the last @@ -1437,7 +1546,7 @@ digest_symbols () * the padding in the text segment size. */ - if (magic == ZMAGIC || magic == QMAGIC || page_align_data) { + 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; @@ -1490,7 +1599,7 @@ printf("bssstart = %#x, bsssize = %#x\n", if (specified_data_size && specified_data_size > data_size) data_pad = specified_data_size - data_size; - if (magic == ZMAGIC || magic == QMAGIC) + if (page_align_segments) data_pad = PALIGN(data_pad + data_size, page_size) - data_size; bss_size -= data_pad; @@ -1506,10 +1615,10 @@ printf("bssstart = %#x, bsssize = %#x\n", global_sym_count = defined_global_sym_count + undefined_global_sym_count; - if (dynamic_symbol->referenced) + if (dynamic_symbol->flags & GS_REFERENCED) global_sym_count++; - if (got_symbol->referenced) + if (got_symbol->flags & GS_REFERENCED) global_sym_count++; if (relocatable_output || building_shared_object) @@ -1529,12 +1638,15 @@ debug symbols: %d, set_symbols %d\n", #endif } +/* + * Determine the definition of each global symbol. + */ static void digest_pass1() { /* - * Now, for each symbol, verify that it is defined globally at most + * 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. * @@ -1546,7 +1658,7 @@ digest_pass1() struct localsymbol *lsp; int defs = 0; - if (!sp->referenced) { + if (!(sp->flags & GS_REFERENCED)) { #if 0 /* Check for undefined symbols in shared objects */ int type; @@ -1580,7 +1692,7 @@ digest_pass1() sp->value = setv_fill_count++ * sizeof(long); } else if ((sp->defined & N_TYPE) != N_SETV) { - sp->multiply_defined = 1; + sp->mult_defs = 1; multiple_def_count++; } /* Keep count and remember symbol */ @@ -1588,6 +1700,12 @@ digest_pass1() 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_ADDRESS(&reloc) = setv_fill_count * sizeof(long); alloc_rrs_segment_reloc(NULL, &reloc); @@ -1598,12 +1716,14 @@ digest_pass1() && (type & N_TYPE) != N_SIZE) { /* non-common definition */ if (defs++ && sp->value != p->n_value - && entry_symbol) { - sp->multiply_defined = 1; + && entry_symbol/*XXX*/) { + sp->mult_defs = 1; multiple_def_count++; } sp->def_nlist = p; + lsp->entry->flags |= E_SYMBOLS_USED; sp->defined = type; + sp->aux = N_AUX(p); } } @@ -1645,15 +1765,17 @@ digest_pass1() && (type & N_TYPE) != N_FN) { /* non-common definition */ sp->def_nlist = p; + lsp->entry->flags |= E_SYMBOLS_USED; sp->so_defined = type; - if (sp->referenced) + sp->aux = N_AUX(p); + if (sp->flags & GS_REFERENCED) undefined_global_sym_count--; else - sp->referenced = 1; + sp->flags |= GS_REFERENCED; #ifdef DEBUG printf("shr: %s gets defined to %x with value %x\n", sp->name, type, sp->value); #endif - if (sp->alias && !sp->alias->referenced) { + if (sp->alias && !(sp->alias->flags & GS_REFERENCED)) { sp = sp->alias; goto again; } @@ -1668,159 +1790,10 @@ doesn't match actual (%d)", set_sect_size/sizeof(long), setv_fill_count); } -static void -digest_pass2() -{ - /* - * Assign each symbol its final value. - * If not -r'ing, allocate common symbols in the BSS section. - */ - - FOR_EACH_SYMBOL(i, sp) { - int size; - int align = sizeof(int); - - if (!sp->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. - */ - 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, tmp; - 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; - RELOC_ADDRESS(&reloc) = - (1 + i + length_word_index) * - sizeof(long) - + set_sect_start; - RELOC_TYPE(&reloc) = - (sp->defined & N_TYPE); - claim_rrs_segment_reloc(NULL, &reloc); - } - } - - /* - * Reverse the vector. - */ - for (i = 1; i < (sp->setv_count - 1)/2 + 1; i++) { - - tmp = set_vectors[length_word_index + i]; - set_vectors[length_word_index + i] = - set_vectors[length_word_index + sp->setv_count + 1 - i]; - set_vectors[length_word_index + sp->setv_count + 1 - i] = tmp; - } - - /* Clear terminating entry */ - set_vectors[length_word_index + sp->setv_count + 1] = 0; - continue; - } - - - if (sp->defined && sp->def_nlist && - ((sp->defined & ~N_EXT) != N_SETV)) - sp->value = sp->def_nlist->n_value; - - if (building_shared_object && !(link_mode & SYMBOLIC)) - /* No common allocation in shared objects */ - continue; - - if ((size = sp->max_common_size) != 0) { - /* - * It's a common. - */ - if (sp->defined != (N_UNDF + N_EXT)) - fatal("%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) - fatal("%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 (!(size & align)) - align <<= 1; - - align = align > MAX_ALIGNMENT ? - MAX_ALIGNMENT : align; - - 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; -} - /* - * Scan relocation info in ENTRY for contributions to the dynamic section of - * the output file. + * Scan relocation info in ENTRY for contributions to the RRS section + * of the output file. */ static void consider_relocation (entry, dataseg) @@ -1848,7 +1821,7 @@ consider_relocation (entry, dataseg) if (RELOC_BASEREL_P(reloc)) { pic_code_seen = 1; if (!RELOC_EXTERN_P(reloc)) - lsp->rename = 1; + lsp->flags |= LS_RENAME; } continue; } @@ -1939,39 +1912,20 @@ consider_relocation (entry, dataseg) continue; } - /* - * Only allocate an alias for function calls. Use - * sp->size here as a heuristic to discriminate - * between function definitions and data residing - * in the text segment. - * NOTE THAT THE COMPILER MUST NOT GENERATE ".size" - * DIRECTIVES FOR FUNCTIONS. - * In the future we might go for ".type" directives. - */ - if (force_alias_definition && sp->size == 0 && - sp->so_defined == N_TEXT + N_EXT) { + if (force_alias_definition && sp->so_defined && + sp->aux == AUX_FUNC) { /* Call to shared library procedure */ alloc_rrs_jmpslot(entry, sp); -#define EXPERIMENTAL -#ifdef EXPERIMENTAL - if (!RELOC_PCREL_P(reloc)) { -#ifdef DEBUG -printf("%s: FUNC flag set\n", sp->name); -#endif - sp->aux = RRS_FUNC; - } -#endif - } else if (sp->size && - (sp->so_defined == N_DATA + N_EXT || - sp->so_defined == N_TEXT + N_EXT)) { + } 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->max_common_size == 0) + } else if (!sp->defined && sp->common_size == 0) alloc_rrs_reloc(entry, sp); } else { @@ -1988,6 +1942,76 @@ printf("%s: FUNC flag set\n", sp->name); } /* + * 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. */ @@ -1995,8 +2019,6 @@ static void consider_file_section_lengths (entry) register struct file_entry *entry; { - if (entry->just_syms_flag) - return; entry->text_start_address = text_size; /* If there were any vectors, we need to chop them off */ @@ -2013,9 +2035,7 @@ consider_file_section_lengths (entry) /* * 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 - * and determine which of the local symbols will make it into the - * output symbol table. + * Also relocate the addresses of the file's local and debugger symbols. */ static void relocate_file_addresses (entry) @@ -2072,57 +2092,165 @@ printf("%s: datastart: %#x, bss %#x\n", get_file_name(entry), break; } - /* - * See if this symbol should be in the output symbol table. - */ + } - if (type == N_WARNING) +} + +/* + * 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 (SET_ELEMENT_P (type)) { + if (sp->alias && + (relocatable_output || building_shared_object || + (sp->alias->defined && !sp->alias->so_defined))) /* - * This occurs even if global. These types of - * symbols are never written globally, though - * they are stored globally. + * 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. */ - lsp->write = relocatable_output; + defined_global_sym_count++; - } else if (!(type & (N_STAB | N_EXT))) { + 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; /* - * Ordinary local symbol + * Relocate vector to final address. */ - lsp->write = (lsp->rename || ( - discard_locals != DISCARD_ALL && - !(discard_locals == DISCARD_L && - lsp->is_L_symbol))); - if (lsp->write) - local_sym_count++; + for (i = 0; i < sp->setv_count; i++) { + struct nlist *p = (struct nlist *) + set_vectors[1+i+length_word_index]; - } else if (!(type & N_EXT)) { + set_vectors[1+i+length_word_index] = p->n_value; + if (building_shared_object) { + struct relocation_info reloc; + + bzero(&reloc, sizeof(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); + } + } /* - * Debugger symbol + * Reverse the vector. */ - lsp->write = (strip_symbols == STRIP_NONE); - if (lsp->write) - debugger_sym_count++; + 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; } - } - /* - * 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++; + if (sp->defined && sp->def_nlist && + ((sp->defined & ~N_EXT) != N_SETV)) + sp->value = sp->def_nlist->n_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)) + fatal("%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) + fatal("%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 (!(size & align)) + align <<= 1; + + align = align > MAX_ALIGNMENT ? MAX_ALIGNMENT : align; + + 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; } - -/* Write the output file */ + +/* -------------------------------------------------------------------*/ + +/* Write the output file */ void write_output () { @@ -2138,6 +2266,8 @@ write_output () if (outdesc < 0) perror_name (output_filename); + fatal_cleanup_hook = myfatal; + if (fstat (outdesc, &statbuf) < 0) perror_name (output_filename); @@ -2176,6 +2306,9 @@ write_header () { int flags = (rrs_section_type == RRS_FULL) ? EX_DYNAMIC : 0; + if (oldmagic && (flags & EX_DYNAMIC)) + error("Cannot set flag in old magic headers\n"); + N_SET_FLAG (outheader, flags); outheader.a_text = text_size; @@ -2339,7 +2472,7 @@ copy_data (entry) mywrite (bytes, 1, entry->header.a_data, outdesc); } - + /* * 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 @@ -2347,6 +2480,10 @@ copy_data (entry) * and its address in the input file. RELOC is the address of the * relocation info, in core. NRELOC says how many there are. */ + +/* HACK: md.c may need access to this */ +int pc_relocation; + void perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) char *data; @@ -2356,12 +2493,13 @@ perform_relocation(data, data_size, reloc, nreloc, entry, dataseg) struct file_entry *entry; int dataseg; { - register struct relocation_info *r = reloc; - struct relocation_info *end = reloc + nreloc; - text_relocation = entry->text_start_address; - data_relocation = entry->data_start_address - entry->header.a_text; - bss_relocation = entry->bss_start_address - + 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: @@ -2616,10 +2754,10 @@ write_rel () /* BLECH - Assign number 0 to __DYNAMIC (!! Sun compatibility) */ - if (dynamic_symbol->referenced) + if (dynamic_symbol->flags & GS_REFERENCED) dynamic_symbol->symbolnum = count++; FOR_EACH_SYMBOL(i, sp) { - if (sp != dynamic_symbol && sp->referenced) { + if (sp != dynamic_symbol && (sp->flags & GS_REFERENCED)) { sp->symbolnum = count++; if (sp->size) count++; @@ -2664,7 +2802,7 @@ assign_symbolnums(entry, countp) n++; for (lsp = entry->symbols; lsp < lspend; lsp++) { - if (lsp->write) + if (lsp->flags & LS_WRITE) lsp->symbolnum = n++; } *countp = n; @@ -2729,10 +2867,11 @@ coptxtrel(entry) * If we aren't going to be adding in the * value in memory on the next pass of the * loader, then we need to add it in from the - * relocation entry. Otherwise the work we + * relocation entry, unless the symbol remains + * external in our output. Otherwise the work we * did in this pass is lost. */ - if (!RELOC_MEMORY_ADD_P(r)) + if (!RELOC_MEMORY_ADD_P(r) && !RELOC_EXTERN_P(r)) RELOC_ADD_EXTRA(r) += sp->value; #endif } else @@ -2794,7 +2933,7 @@ copdatrel(entry) symtype = sp->defined & N_TYPE; - if (!pic_code_seen && (force_common_definition || + if (!pic_code_seen && ( symtype == N_BSS || symtype == N_DATA || symtype == N_TEXT || symtype == N_ABS)) { @@ -2939,7 +3078,7 @@ write_syms() * If defined (ie. not relocatable_output), make it look * like an internal symbol. */ - if (dynamic_symbol->referenced) { + if (dynamic_symbol->flags & GS_REFERENCED) { nl.n_other = 0; nl.n_desc = 0; nl.n_type = dynamic_symbol->defined; @@ -2961,7 +3100,7 @@ write_syms() /* Already dealt with above */ continue; - if (!sp->referenced) + if (!(sp->flags & GS_REFERENCED)) /* Came from shared object but was not used */ continue; @@ -3009,6 +3148,7 @@ write_syms() */ nl.n_type = sp->alias->defined; nl.n_value = sp->alias->value; + nl.n_other = N_OTHER(0, sp->alias->aux); } else { if (sp->defined == N_SIZE) nl.n_type = N_DATA | N_EXT; @@ -3019,9 +3159,10 @@ write_syms() fatal("%s: N_INDR has value %#x", sp->name, sp->value); nl.n_value = sp->value; + nl.n_other = N_OTHER(0, sp->aux); } - } else if (sp->max_common_size) { + } else if (sp->common_size) { /* * defined as common but not allocated, * happens only with -r and not -d, write out @@ -3032,7 +3173,7 @@ write_syms() * undefined in digest_symbols. */ nl.n_type = N_UNDF | N_EXT; - nl.n_value = sp->max_common_size; + nl.n_value = sp->common_size; } else if (!sp->defined) { /* undefined -- legit only if -r */ nl.n_type = N_UNDF | N_EXT; @@ -3053,6 +3194,9 @@ write_syms() *bufp++ = nl; syms_written++; + /* + * Write second symbol of an alias pair. + */ if (nl.n_type == N_INDR + N_EXT) { if (sp->alias == NULL) fatal("internal error: alias in hyperspace"); @@ -3066,6 +3210,9 @@ write_syms() 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); @@ -3144,7 +3291,7 @@ write_file_syms(entry, syms_written_addr) register struct nlist *bufp = buf; - if (entry->is_dynamic) + if (entry->flags & E_DYNAMIC) return; /* @@ -3168,9 +3315,6 @@ write_file_syms(entry, syms_written_addr) nl.n_other = 0; *bufp++ = nl; (*syms_written_addr)++; -#if 0 - entry->local_syms_offset = *syms_written_addr * sizeof(struct nlist); -#endif } /* Read the file's string table. */ @@ -3185,12 +3329,12 @@ write_file_syms(entry, syms_written_addr) register int write = 0; char *name; - if (! lsp->write) + if (!(lsp->flags & LS_WRITE)) continue; if (p->n_un.n_strx == 0) name = NULL; - else if (lsp->rename == 0) + else if (!(lsp->flags & LS_RENAME)) name = p->n_un.n_strx + entry->strings; else { char *cp = p->n_un.n_strx + entry->strings; @@ -3229,3 +3373,50 @@ write_file_syms(entry, syms_written_addr) write_string_table(); entry->strings = 0; /* Since it will disappear anyway. */ } + +/* + * Output COUNT*ELTSIZE bytes of data at BUF to the descriptor DESC. + */ +void +mywrite (buf, count, eltsize, desc) + void *buf; + int count; + int eltsize; + int desc; +{ + register int val; + register int bytes = count * eltsize; + + while (bytes > 0) { + val = write (desc, buf, bytes); + if (val <= 0) + perror(output_filename); + buf += val; + bytes -= val; + } +} + +static void +myfatal() +{ + if (outdesc > 0) + unlink(output_filename); +} + +/* + * Output PADDING zero-bytes to descriptor OUTDESC. + * PADDING may be negative; in that case, do nothing. + */ +void +padfile (padding, outdesc) + int padding; + int outdesc; +{ + register char *buf; + if (padding <= 0) + return; + + buf = (char *) alloca (padding); + bzero (buf, padding); + mywrite (buf, padding, 1, outdesc); +} |