diff options
author | jkh <jkh@FreeBSD.org> | 1993-12-11 12:02:10 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1993-12-11 12:02:10 +0000 |
commit | fa2f9983992b8f76f4876d186e7f838007698a3a (patch) | |
tree | 9dc50398c34bcf4df5b21ad170bcfc2ec5d49cff /gnu/usr.bin/ld/ld.c | |
parent | fae8cc8948a605d587d12154817c04384efa8e15 (diff) | |
download | FreeBSD-src-fa2f9983992b8f76f4876d186e7f838007698a3a.zip FreeBSD-src-fa2f9983992b8f76f4876d186e7f838007698a3a.tar.gz |
Sync up with Paul K's latest ld from cesium.
Diffstat (limited to 'gnu/usr.bin/ld/ld.c')
-rw-r--r-- | gnu/usr.bin/ld/ld.c | 325 |
1 files changed, 228 insertions, 97 deletions
diff --git a/gnu/usr.bin/ld/ld.c b/gnu/usr.bin/ld/ld.c index 3b24f43..567b536 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.14 1993/12/02 05:09:52 nate Exp $ + * $Id: ld.c,v 1.15 1993/12/04 00:52:56 jkh Exp $ */ /* Define how to initialize system-dependent header fields. */ @@ -55,6 +55,10 @@ 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; /* 1 => write relocation into output file so can re-input it later. */ @@ -77,6 +81,9 @@ int force_alias_definition; if `relocatable_output'. */ int pic_code_seen; +/* 1 => data segment must be page aligned, even if `-n' or `-N' */ +int page_align_data; + /* * Which symbols should be stripped (omitted from the output): none, all, or * debugger symbols. @@ -127,6 +134,25 @@ int specified_data_size; long *set_vectors; int setv_fill_count; +static void decode_option __P((char *, char *)); +static void decode_command __P((int, char **)); +static int classify_arg __P((char *)); +static void enter_global_ref __P((struct localsymbol *, + char *, struct file_entry *)); +static void digest_symbols __P((void)); +static void digest_pass1 __P((void)), digest_pass2 __P((void)); +static void consider_file_section_lengths __P((struct file_entry *)); +static void relocate_file_addresses __P((struct file_entry *)); +static void consider_relocation __P((struct file_entry *, int)); +static void 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 assign_symbolnums __P((struct file_entry *, int *)); + int main(argc, argv) char **argv; @@ -163,6 +189,7 @@ main(argc, argv) data_pad = 0; text_pad = 0; + page_align_data = 0; /* Initialize the data about options. */ @@ -180,7 +207,10 @@ main(argc, argv) make_executable = 1; force_executable = 0; link_mode = DYNAMIC; - soversion = LD_VERSION_BSD; +#ifdef SUNOS4 + link_mode |= SILLYARCHIVE; +#endif + soversion = DEFAULT_SOVERSION; /* Initialize the cumulative counts of symbols. */ @@ -262,8 +292,6 @@ main(argc, argv) exit(!make_executable); } -void decode_option(); - /* * 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 @@ -273,7 +301,7 @@ void decode_option(); * options. */ -int +static int classify_arg(arg) register char *arg; { @@ -320,10 +348,10 @@ classify_arg(arg) * each input file, and setting variables according to the options. */ -void +static void decode_command(argc, argv) - char **argv; int argc; + char **argv; { register int i; register struct file_entry *p; @@ -390,6 +418,12 @@ decode_command(argc, argv) 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) @@ -467,7 +501,7 @@ set_element_prefixed_p(name) * files. */ -void +static void decode_option(swt, arg) register char *swt, *arg; { @@ -484,6 +518,10 @@ decode_option(swt, arg) return; if (!strcmp(swt + 1, "assert")) return; +#ifdef SUN_COMPAT + if (!strcmp(swt + 1, "Bsilly")) + return; +#endif if (!strcmp(swt + 1, "Ttext")) { text_start = parse(arg, "%x", "invalid argument to -Ttext"); T_flag_specified = 1; @@ -551,16 +589,19 @@ decode_option(swt, arg) case 'Q': magic = oldmagic = QMAGIC; return; -#endif case 'Z': - magic = ZMAGIC; - oldmagic = 0; + magic = oldmagic = ZMAGIC; return; +#endif case 'o': output_filename = arg; return; + case 'p': + page_align_data = 1; + return; + case 'r': relocatable_output = 1; magic = OMAGIC; @@ -644,17 +685,38 @@ each_file(function, arg) for (i = 0; i < number_of_files; i++) { register struct file_entry *entry = &file_table[i]; + register struct file_entry *subentry; + if (entry->scrapped) continue; - if (entry->library_flag) { - register struct file_entry *subentry = entry->subfiles; + + if (!entry->library_flag) + (*function) (entry, arg); + + subentry = entry->subfiles; + for (; subentry; subentry = subentry->chain) { + if (subentry->scrapped) + continue; + (*function) (subentry, arg); + } + +#ifdef SUN_COMPAT + if (entry->silly_archive) { + + if (!entry->is_dynamic) + error("Silly"); + + if (!entry->silly_archive->library_flag) + error("Sillier"); + + subentry = entry->silly_archive->subfiles; for (; subentry; subentry = subentry->chain) { if (subentry->scrapped) continue; (*function) (subentry, arg); } - } else - (*function) (entry, arg); + } +#endif } } @@ -704,15 +766,41 @@ each_full_file(function, arg) for (i = 0; i < number_of_files; i++) { register struct file_entry *entry = &file_table[i]; - if (entry->scrapped || - entry->just_syms_flag || entry->is_dynamic) + register struct file_entry *subentry; + + if (entry->scrapped || entry->just_syms_flag) continue; - if (entry->library_flag) { - register struct file_entry *subentry = entry->subfiles; - for (; subentry; subentry = subentry->chain) + +#ifdef SUN_COMPAT + if (entry->silly_archive) { + + if (!entry->is_dynamic) + error("Silly"); + + if (!entry->silly_archive->library_flag) + error("Sillier"); + + subentry = entry->silly_archive->subfiles; + for (; subentry; subentry = subentry->chain) { + if (subentry->scrapped) + continue; (*function) (subentry, arg); - } else + } + } +#endif + if (entry->is_dynamic) + continue; + + if (!entry->library_flag) (*function) (entry, arg); + + subentry = entry->subfiles; + for (; subentry; subentry = subentry->chain) { + if (subentry->scrapped) + continue; + (*function) (subentry, arg); + } + } } @@ -737,7 +825,7 @@ file_open (entry) { register int desc; - if (entry->superfile) + if (entry->superfile && entry->superfile->library_flag) return file_open (entry->superfile); if (entry == input_file) @@ -802,6 +890,7 @@ read_header (desc, entry) * descriptor DESC. Also read the length of the string table, which follows * the symbol table, but don't read the contents of the string table. */ + void read_entry_symbols (desc, entry) struct file_entry *entry; @@ -941,8 +1030,6 @@ read_entry_relocation (desc, entry) /* Read in the symbols of all input files. */ -void read_file_symbols (), read_entry_symbols (); -void enter_file_symbols (), enter_global_ref (); void load_symbols () @@ -990,7 +1077,7 @@ read_file_symbols (entry) return; } entry->is_dynamic = 1; - if (rrs_add_shobj(entry)) + if (entry->superfile || rrs_add_shobj(entry)) read_shared_object(desc, entry); else entry->scrapped = 1; @@ -1095,7 +1182,7 @@ enter_file_symbols (entry) * */ -void +static void enter_global_ref (lsp, name, entry) struct localsymbol *lsp; char *name; @@ -1117,8 +1204,9 @@ enter_global_ref (lsp, name, entry) lsp->nzlist.nz_type = N_TEXT|N_EXT; lsp->nzlist.nz_value = 0; make_executable = 0; - } else + } else { global_alias_count++; + } } if (entry->is_dynamic) { @@ -1273,9 +1361,6 @@ contains_symbol (entry, np) } -void consider_file_section_lengths (), relocate_file_addresses (); -void consider_relocation(); - /* * 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. @@ -1295,7 +1380,7 @@ void consider_relocation(); * symbols originating from shared objects is searched for a definition. * * 2) Then the relocation information of each relocatable file is examined - * for for possible contributions to the RRS section. + * 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). @@ -1307,9 +1392,8 @@ void consider_relocation(); * */ -void digest_pass1(), digest_pass2(); -void +static void digest_symbols () { @@ -1323,9 +1407,9 @@ digest_symbols () * the vector, plus a word for each symbol for a zero at the * end of the vector (for incremental linking). */ - set_sect_size = (2 * set_symbol_count + set_vector_count) * + set_sect_size = (set_symbol_count + 2 * set_vector_count) * sizeof (unsigned long); - set_vectors = (unsigned long *) xmalloc (set_sect_size); + set_vectors = (long *)xmalloc (set_sect_size); setv_fill_count = 0; } @@ -1354,7 +1438,7 @@ digest_symbols () * the padding in the text segment size. */ - if (magic == ZMAGIC) { + if (magic == ZMAGIC || page_align_data) { int text_end = text_size + N_TXTOFF(outheader); text_pad = PALIGN(text_end, page_size) - text_end; text_size += text_pad; @@ -1429,12 +1513,24 @@ printf("bssstart = %#x, bsssize = %#x\n", if (got_symbol->referenced) global_sym_count++; - if (relocatable_output) + if (relocatable_output || building_shared_object) /* For each alias we write out two struct nlists */ - global_sym_count += global_alias_count + size_sym_count; + global_sym_count += global_alias_count; + + if (relocatable_output) + /* We write out the original N_SET* symbols */ + global_sym_count += size_sym_count; + +#ifdef DEBUG +printf("global symbols %d (defined %d, undefined %d, aliases %d), locals: %d, \ +debug symbols: %d, set_symbols %d\n", + global_sym_count, + defined_global_sym_count, undefined_global_sym_count, global_alias_count, + local_sym_count, debugger_sym_count, set_symbol_count); +#endif } -void +static void digest_pass1() { @@ -1510,7 +1606,14 @@ digest_pass1() if ((sp->defined & N_TYPE) == N_SETV) /* Allocate zero entry in set vector */ setv_fill_count++; - defined_global_sym_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; } @@ -1528,6 +1631,7 @@ digest_pass1() continue; } + again: for (lsp = sp->sorefs; lsp; lsp = lsp->next) { register struct nlist *p = &lsp->nzlist.nlist; register int type = p->n_type; @@ -1537,17 +1641,29 @@ digest_pass1() /* non-common definition */ sp->def_nlist = p; sp->so_defined = type; - undefined_global_sym_count--; + if (sp->referenced) + undefined_global_sym_count--; + else + sp->referenced = 1; #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) { + sp = sp->alias; + goto again; + } break; } } } END_EACH_SYMBOL; + + if (setv_fill_count != set_sect_size/sizeof(long)) + fatal("internal error: allocated set symbol space (%d) \ +doesn't match actual (%d)", + set_sect_size/sizeof(long), setv_fill_count); } -void +static void digest_pass2() { /* @@ -1562,6 +1678,16 @@ digest_pass2() 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 @@ -1676,11 +1802,12 @@ digest_pass2() } END_EACH_SYMBOL; } + /* * Scan relocation info in ENTRY for contributions to the dynamic section of * the output file. */ -void +static void consider_relocation (entry, dataseg) struct file_entry *entry; int dataseg; @@ -1849,7 +1976,7 @@ printf("%s: FUNC flag set\n", sp->name); * Accumulate the section sizes of input file ENTRY into the section sizes of * the output file. */ -void +static void consider_file_section_lengths (entry) register struct file_entry *entry; { @@ -1875,7 +2002,7 @@ consider_file_section_lengths (entry) * and determine which of the local symbols will make it into the * output symbol table. */ -void +static void relocate_file_addresses (entry) register struct file_entry *entry; { @@ -2025,18 +2152,20 @@ write_output () if (chmod (output_filename, filemode | 0111) == -1) perror_name (output_filename); } - -void modify_location (), perform_relocation (), copy_text (), copy_data (); /* Total number of symbols to be written in the output file. */ -int nsyms; +static int nsyms; void write_header () { int flags = (rrs_section_type == RRS_FULL) ? EX_DYNAMIC : 0; - if (!oldmagic) N_SET_FLAG (outheader, flags); +#ifdef QMAGIC + if (!oldmagic) +#endif + N_SET_FLAG (outheader, flags); + outheader.a_text = text_size; outheader.a_data = data_size; outheader.a_bss = bss_size; @@ -2051,15 +2180,6 @@ write_header () if (relocatable_output) nsyms += set_symbol_count; -#ifdef DEBUG -printf("global symbols %d (defined %d, undefined %d), locals: %d, \ -debug symbols: %d, set_symbols %d, aliases %d --> nsyms %d\n", - global_sym_count, - defined_global_sym_count, undefined_global_sym_count, - local_sym_count, debugger_sym_count, - set_symbol_count, global_alias_count, nsyms); -#endif - outheader.a_syms = nsyms * sizeof (struct nlist); if (relocatable_output) { @@ -2462,10 +2582,10 @@ printf("%s: BSS found in so_defined\n", sp->name); } } -/* For relocatable_output only: write out the relocation, - relocating the addresses-to-be-relocated. */ - -void coptxtrel(), copdatrel(), assign_symbolnums(); +/* + * For relocatable_output only: write out the relocation, + * relocating the addresses-to-be-relocated. + */ void write_rel () @@ -2513,10 +2633,11 @@ write_rel () fprintf (stderr, "\n"); } + /* * Assign symbol ordinal numbers to local symbols in each entry. */ -void +static void assign_symbolnums(entry, countp) struct file_entry *entry; int *countp; @@ -2537,7 +2658,7 @@ assign_symbolnums(entry, countp) *countp = n; } -void +static void coptxtrel(entry) struct file_entry *entry; { @@ -2613,7 +2734,7 @@ coptxtrel(entry) sizeof(struct relocation_info), outdesc); } -void +static void copdatrel(entry) struct file_entry *entry; { @@ -2684,28 +2805,28 @@ void write_string_table __P((void)); /* Offsets and current lengths of symbol and string tables in output file. */ -int symbol_table_offset; -int symbol_table_len; +static int symbol_table_offset; +static int symbol_table_len; /* Address in output file where string table starts. */ -int string_table_offset; +static int string_table_offset; /* Offset within string table where the strings in `strtab_vector' should be written. */ -int string_table_len; +static int string_table_len; /* Total size of string table strings allocated so far, including strings in `strtab_vector'. */ -int strtab_size; +static int strtab_size; /* Vector whose elements are strings to be added to the string table. */ -char **strtab_vector; +static char **strtab_vector; /* Vector whose elements are the lengths of those strings. */ -int *strtab_lens; +static int *strtab_lens; /* Index in `strtab_vector' at which the next string will be stored. */ -int strtab_index; +static int strtab_index; /* * Add the string NAME to the output file string table. Record it in @@ -2713,7 +2834,7 @@ int strtab_index; * table that this string will have. */ -int +static int assign_string_table_index(name) char *name; { @@ -2823,6 +2944,7 @@ write_syms() /* Scan the symbol hash table, bucket by bucket. */ FOR_EACH_SYMBOL(i, sp) { + if (sp == dynamic_symbol) /* Already dealt with above */ continue; @@ -2831,7 +2953,7 @@ write_syms() /* Came from shared object but was not used */ continue; - if (sp->so_defined) + if (sp->so_defined || (sp->alias && sp->alias->so_defined)) /* * Definition came from shared object, * don't mention it here @@ -2850,39 +2972,52 @@ write_syms() continue; } - /* Construct a `struct nlist' for the symbol. */ + if (syms_written >= global_sym_count) + fatal( + "internal error: number of symbols exceeds alloc'd %d", + global_sym_count); + /* + * Construct a `struct nlist' for the symbol. + */ nl.n_other = 0; nl.n_desc = 0; - /* - * common condition needs to be before undefined - * condition because unallocated commons are set - * undefined in digest_symbols - */ if (sp->defined > 1) { - /* defined with known type */ - - if (!relocatable_output && sp->alias && - sp->alias->defined > 1) { + /* + * defined with known type + */ + if (!relocatable_output && !building_shared_object && + sp->alias && sp->alias->defined > 1) { /* * If the target of an indirect symbol has * been defined and we are outputting an * executable, resolve the indirection; it's - * no longer needed + * no longer needed. */ nl.n_type = sp->alias->defined; - nl.n_type = sp->alias->value; - } else if (sp->defined == N_SIZE) - nl.n_type = N_DATA | N_EXT; - else - nl.n_type = sp->defined; - nl.n_value = sp->value; + nl.n_value = sp->alias->value; + } else { + if (sp->defined == N_SIZE) + nl.n_type = N_DATA | N_EXT; + else + nl.n_type = sp->defined; + if (nl.n_type == (N_INDR|N_EXT) && + sp->value != 0) + fatal("%s: N_INDR has value %#x", + sp->name, sp->value); + nl.n_value = sp->value; + } + } else if (sp->max_common_size) { /* * defined as common but not allocated, * happens only with -r and not -d, write out - * a common definition + * a common definition. + * + * common condition needs to be before undefined + * condition because unallocated commons are set + * undefined in digest_symbols. */ nl.n_type = N_UNDF | N_EXT; nl.n_value = sp->max_common_size; @@ -2903,10 +3038,6 @@ write_syms() /* Output to the buffer and count it. */ - if (syms_written >= global_sym_count) - fatal( - "internal error: number of symbols exceeds allocated %d", - global_sym_count); *bufp++ = nl; syms_written++; |