X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fcofflink.c;h=c9d23f23d3cf251f83457534c1b2e825f975c472;hb=5dccc1ddaa1d8e543c1113a83df73c6d7e6973ec;hp=2de8f988b812f2096ee4de8ae85f93e93cb7b986;hpb=13d1a4dda9c2eeb850bae5110672e2adeb828fac;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/cofflink.c b/bfd/cofflink.c index 2de8f988b8..c9d23f23d3 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -1,5 +1,5 @@ /* COFF specific linker code. - Copyright 1994, 1995 Free Software Foundation, Inc. + Copyright 1994, 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -34,6 +34,11 @@ static boolean coff_link_check_archive_element static boolean coff_link_check_ar_symbols PARAMS ((bfd *, struct bfd_link_info *, boolean *)); static boolean coff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *)); +static char *dores_com PARAMS ((char *, bfd *, int)); +static char *get_name PARAMS ((char *, char **)); +static int process_embedded_commands + PARAMS ((bfd *, struct bfd_link_info *, bfd *)); +static void mark_relocs PARAMS ((struct coff_final_link_info *, bfd *)); /* Create an entry in a COFF linker hash table. */ @@ -81,6 +86,7 @@ _bfd_coff_link_hash_table_init (table, abfd, newfunc) struct bfd_hash_table *, const char *)); { + table->stab_info = NULL; return _bfd_link_hash_table_init (&table->root, abfd, newfunc); } @@ -108,7 +114,7 @@ _bfd_coff_link_hash_table_create (abfd) /* Create an entry in a COFF debug merge hash table. */ struct bfd_hash_entry * -coff_debug_merge_hash_newfunc (entry, table, string) +_bfd_coff_debug_merge_hash_newfunc (entry, table, string) struct bfd_hash_entry *entry; struct bfd_hash_table *table; const char *string; @@ -219,27 +225,25 @@ coff_link_check_ar_symbols (abfd, info, pneeded) struct bfd_link_info *info; boolean *pneeded; { - boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); bfd_size_type symesz; bfd_byte *esym; bfd_byte *esym_end; *pneeded = false; - sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global; - symesz = bfd_coff_symesz (abfd); esym = (bfd_byte *) obj_coff_external_syms (abfd); esym_end = esym + obj_raw_syment_count (abfd) * symesz; while (esym < esym_end) { struct internal_syment sym; + enum coff_symbol_classification classification; bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); - if ((sym.n_sclass == C_EXT - || (sym_is_global && (*sym_is_global) (abfd, &sym))) - && (sym.n_scnum != 0 || sym.n_value != 0)) + classification = bfd_coff_classify_symbol (abfd, &sym); + if (classification == COFF_SYMBOL_GLOBAL + || classification == COFF_SYMBOL_COMMON) { const char *name; char buf[SYMNMLEN + 1]; @@ -281,7 +285,7 @@ coff_link_add_symbols (abfd, info) bfd *abfd; struct bfd_link_info *info; { - boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); + boolean keep_syms; boolean default_copy; bfd_size_type symcount; struct coff_link_hash_entry **sym_hash; @@ -289,7 +293,10 @@ coff_link_add_symbols (abfd, info) bfd_byte *esym; bfd_byte *esym_end; - sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global; + /* Keep the symbols during this function, in case the linker needs + to read the generic symbols in order to report an error message. */ + keep_syms = obj_coff_keep_syms (abfd); + obj_coff_keep_syms (abfd) = true; if (info->keep_memory) default_copy = false; @@ -305,7 +312,7 @@ coff_link_add_symbols (abfd, info) ((size_t) symcount * sizeof (struct coff_link_hash_entry *)))); if (sym_hash == NULL && symcount != 0) - return false; + goto error_return; obj_coff_sym_hashes (abfd) = sym_hash; memset (sym_hash, 0, (size_t) symcount * sizeof (struct coff_link_hash_entry *)); @@ -317,24 +324,26 @@ coff_link_add_symbols (abfd, info) while (esym < esym_end) { struct internal_syment sym; + enum coff_symbol_classification classification; boolean copy; bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym); - if (sym.n_sclass == C_EXT - || (sym_is_global && (*sym_is_global) (abfd, &sym))) + classification = bfd_coff_classify_symbol (abfd, &sym); + if (classification != COFF_SYMBOL_LOCAL) { const char *name; char buf[SYMNMLEN + 1]; flagword flags; asection *section; bfd_vma value; + boolean addit; /* This symbol is externally visible. */ name = _bfd_coff_internal_syment_name (abfd, &sym, buf); if (name == NULL) - return false; + goto error_return; /* We must copy the name into memory if we got it from the syment itself, rather than the string table. */ @@ -345,31 +354,80 @@ coff_link_add_symbols (abfd, info) value = sym.n_value; - if (sym.n_scnum == 0) + switch (classification) { - if (value == 0) - { - flags = 0; - section = bfd_und_section_ptr; - } - else + default: + abort (); + + case COFF_SYMBOL_GLOBAL: + flags = BSF_EXPORT | BSF_GLOBAL; + section = coff_section_from_bfd_index (abfd, sym.n_scnum); + if (! obj_pe (abfd)) + value -= section->vma; + break; + + case COFF_SYMBOL_UNDEFINED: + flags = 0; + section = bfd_und_section_ptr; + break; + + case COFF_SYMBOL_COMMON: + flags = BSF_GLOBAL; + section = bfd_com_section_ptr; + break; + + case COFF_SYMBOL_PE_SECTION: + flags = BSF_SECTION_SYM | BSF_GLOBAL; + section = coff_section_from_bfd_index (abfd, sym.n_scnum); + break; + } + + if (sym.n_sclass == C_WEAKEXT + || (obj_pe (abfd) && sym.n_sclass == C_NT_WEAK)) + flags = BSF_WEAK; + + addit = true; + + /* In the PE format, section symbols actually refer to the + start of the output section. We handle them specially + here. */ + if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) + { + *sym_hash = coff_link_hash_lookup (coff_hash_table (info), + name, false, copy, false); + if (*sym_hash != NULL) { - flags = BSF_GLOBAL; - section = bfd_com_section_ptr; + if (((*sym_hash)->coff_link_hash_flags + & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0 + && (*sym_hash)->root.type != bfd_link_hash_undefined + && (*sym_hash)->root.type != bfd_link_hash_undefweak) + (*_bfd_error_handler) + ("Warning: symbol `%s' is both section and non-section", + name); + + addit = false; } } - else + + if (addit) { - flags = BSF_EXPORT | BSF_GLOBAL; - section = coff_section_from_bfd_index (abfd, sym.n_scnum); - value -= section->vma; + if (! (bfd_coff_link_add_one_symbol + (info, abfd, name, flags, section, value, + (const char *) NULL, copy, false, + (struct bfd_link_hash_entry **) sym_hash))) + goto error_return; } - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, name, flags, section, value, - (const char *) NULL, copy, false, - (struct bfd_link_hash_entry **) sym_hash))) - return false; + if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) + (*sym_hash)->coff_link_hash_flags |= + COFF_LINK_HASH_PE_SECTION_SYMBOL; + + if (section == bfd_com_section_ptr + && (*sym_hash)->root.type == bfd_link_hash_common + && ((*sym_hash)->root.u.c.p->alignment_power + > bfd_coff_default_section_alignment_power (abfd))) + (*sym_hash)->root.u.c.p->alignment_power + = bfd_coff_default_section_alignment_power (abfd); if (info->hash->creator->flavour == bfd_get_flavour (abfd)) { @@ -377,11 +435,20 @@ coff_link_add_symbols (abfd, info) && (*sym_hash)->type == T_NULL) || sym.n_scnum != 0 || (sym.n_value != 0 - && (*sym_hash)->root.type != bfd_link_hash_defined)) + && (*sym_hash)->root.type != bfd_link_hash_defined + && (*sym_hash)->root.type != bfd_link_hash_defweak)) { (*sym_hash)->class = sym.n_sclass; - (*sym_hash)->type = sym.n_type; - (*sym_hash)->numaux = sym.n_numaux; + if (sym.n_type != T_NULL) + { + if ((*sym_hash)->type != T_NULL + && (*sym_hash)->type != sym.n_type) + (*_bfd_error_handler) + (_("Warning: type of symbol `%s' changed from %d to %d in %s"), + name, (*sym_hash)->type, sym.n_type, + bfd_get_filename (abfd)); + (*sym_hash)->type = sym.n_type; + } (*sym_hash)->auxbfd = abfd; if (sym.n_numaux != 0) { @@ -390,12 +457,13 @@ coff_link_add_symbols (abfd, info) bfd_byte *eaux; union internal_auxent *iaux; + (*sym_hash)->numaux = sym.n_numaux; alloc = ((union internal_auxent *) bfd_hash_allocate (&info->hash->table, (sym.n_numaux * sizeof (*alloc)))); if (alloc == NULL) - return false; + goto error_return; for (i = 0, eaux = esym + symesz, iaux = alloc; i < sym.n_numaux; i++, eaux += symesz, iaux++) @@ -406,13 +474,79 @@ coff_link_add_symbols (abfd, info) } } } + + if (classification == COFF_SYMBOL_PE_SECTION + && (*sym_hash)->numaux != 0) + { + /* Some PE sections (such as .bss) have a zero size in + the section header, but a non-zero size in the AUX + record. Correct that here. + + FIXME: This is not at all the right place to do this. + For example, it won't help objdump. This needs to be + done when we swap in the section header. */ + + BFD_ASSERT ((*sym_hash)->numaux == 1); + if (section->_raw_size == 0) + section->_raw_size = (*sym_hash)->aux[0].x_scn.x_scnlen; + + /* FIXME: We could test whether the section sizes + matches the size in the aux entry, but apparently + that sometimes fails unexpectedly. */ + } } esym += (sym.n_numaux + 1) * symesz; sym_hash += sym.n_numaux + 1; } + /* If this is a non-traditional, non-relocateable link, try to + optimize the handling of any .stab/.stabstr sections. */ + if (! info->relocateable + && ! info->traditional_format + && info->hash->creator->flavour == bfd_get_flavour (abfd) + && (info->strip != strip_all && info->strip != strip_debugger)) + { + asection *stab, *stabstr; + + stab = bfd_get_section_by_name (abfd, ".stab"); + if (stab != NULL) + { + stabstr = bfd_get_section_by_name (abfd, ".stabstr"); + + if (stabstr != NULL) + { + struct coff_link_hash_table *table; + struct coff_section_tdata *secdata; + + secdata = coff_section_data (abfd, stab); + if (secdata == NULL) + { + stab->used_by_bfd = + (PTR) bfd_zalloc (abfd, + sizeof (struct coff_section_tdata)); + if (stab->used_by_bfd == NULL) + goto error_return; + secdata = coff_section_data (abfd, stab); + } + + table = coff_hash_table (info); + + if (! _bfd_link_section_stabs (abfd, &table->stab_info, + stab, stabstr, + &secdata->stab_info)) + goto error_return; + } + } + } + + obj_coff_keep_syms (abfd) = keep_syms; + return true; + + error_return: + obj_coff_keep_syms (abfd) = keep_syms; + return false; } /* Do the final link step. */ @@ -425,6 +559,7 @@ _bfd_coff_final_link (abfd, info) bfd_size_type symesz; struct coff_final_link_info finfo; boolean debug_merge_allocated; + boolean long_section_names; asection *o; struct bfd_link_order *p; size_t max_sym_count; @@ -447,6 +582,7 @@ _bfd_coff_final_link (abfd, info) finfo.strtab = NULL; finfo.section_info = NULL; finfo.last_file_index = -1; + finfo.last_bf_index = -1; finfo.internal_syms = NULL; finfo.sec_ptrs = NULL; finfo.sym_indices = NULL; @@ -455,6 +591,7 @@ _bfd_coff_final_link (abfd, info) finfo.contents = NULL; finfo.external_relocs = NULL; finfo.internal_relocs = NULL; + finfo.global_to_static = false; debug_merge_allocated = false; coff_data (abfd)->link_info = info; @@ -469,7 +606,10 @@ _bfd_coff_final_link (abfd, info) /* Compute the file positions for all the sections. */ if (! abfd->output_has_begun) - bfd_coff_compute_section_file_positions (abfd); + { + if (! bfd_coff_compute_section_file_positions (abfd)) + goto error_return; + } /* Count the line numbers and relocation entries required for the output file. Set the file positions for the relocs. */ @@ -479,19 +619,25 @@ _bfd_coff_final_link (abfd, info) max_lineno_count = 0; max_reloc_count = 0; + long_section_names = false; for (o = abfd->sections; o != NULL; o = o->next) { o->reloc_count = 0; o->lineno_count = 0; for (p = o->link_order_head; p != NULL; p = p->next) { - if (p->type == bfd_indirect_link_order) { asection *sec; sec = p->u.indirect.section; + /* Mark all sections which are to be included in the + link. This will normally be every section. We need + to do this so that we can identify any sections which + the linker has decided to not include. */ + sec->linker_mark = true; + if (info->strip == strip_none || info->strip == strip_some) o->lineno_count += sec->lineno_count; @@ -519,6 +665,20 @@ _bfd_coff_final_link (abfd, info) o->rel_filepos = rel_filepos; rel_filepos += o->reloc_count * relsz; } + + if (bfd_coff_long_section_names (abfd) + && strlen (o->name) > SCNNMLEN) + { + /* This section has a long name which must go in the string + table. This must correspond to the code in + coff_write_object_contents which puts the string index + into the s_name field of the section header. That is why + we pass hash as false. */ + if (_bfd_stringtab_add (finfo.strtab, o->name, false, false) + == (bfd_size_type) -1) + goto error_return; + long_section_names = true; + } } /* If doing a relocateable link, allocate space for the pointers we @@ -661,9 +821,9 @@ _bfd_coff_final_link (abfd, info) == bfd_target_coff_flavour)) { sub = p->u.indirect.section->owner; - if (! sub->output_has_begun) + if (! bfd_coff_link_output_has_begun (sub, & finfo)) { - if (! coff_link_input_bfd (&finfo, sub)) + if (! _bfd_coff_link_input_bfd (&finfo, sub)) goto error_return; sub->output_has_begun = true; } @@ -671,7 +831,7 @@ _bfd_coff_final_link (abfd, info) else if (p->type == bfd_section_reloc_link_order || p->type == bfd_symbol_reloc_link_order) { - if (! coff_reloc_link_order (abfd, &finfo, o, p)) + if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p)) goto error_return; } else @@ -682,7 +842,10 @@ _bfd_coff_final_link (abfd, info) } } - /* Free up the buffers used by coff_link_input_bfd. */ + if (! bfd_coff_final_link_postscript (abfd, & finfo)) + goto error_return; + + /* Free up the buffers used by _bfd_coff_link_input_bfd. */ coff_debug_merge_hash_table_free (&finfo.debug_merge); debug_merge_allocated = false; @@ -740,21 +903,33 @@ _bfd_coff_final_link (abfd, info) return false; } + /* If doing task linking (ld --task-link) then make a pass through the + global symbols, writing out any that are defined, and making them + static. */ + if (info->task_link) + { + finfo.failed = false; + coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_task_globals, + (PTR) &finfo); + if (finfo.failed) + goto error_return; + } + /* Write out the global symbols. */ finfo.failed = false; - coff_link_hash_traverse (coff_hash_table (info), coff_write_global_sym, + coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym, (PTR) &finfo); if (finfo.failed) goto error_return; - /* The outsyms buffer is used by coff_write_global_sym. */ + /* The outsyms buffer is used by _bfd_coff_write_global_sym. */ if (finfo.outsyms != NULL) { free (finfo.outsyms); finfo.outsyms = NULL; } - if (info->relocateable) + if (info->relocateable && max_output_reloc_count > 0) { /* Now that we have written out all the global symbols, we know the symbol indices to use for relocs against them, and we can @@ -814,8 +989,15 @@ _bfd_coff_final_link (abfd, info) finfo.section_info = NULL; } + /* If we have optimized stabs strings, output them. */ + if (coff_hash_table (info)->stab_info != NULL) + { + if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info)) + return false; + } + /* Write out the string table. */ - if (obj_raw_syment_count (abfd) != 0) + if (obj_raw_syment_count (abfd) != 0 || long_section_names) { if (bfd_seek (abfd, (obj_sym_filepos (abfd) @@ -931,7 +1113,7 @@ char **dst; static int process_embedded_commands (output_bfd, info, abfd) bfd *output_bfd; - struct bfd_link_info *info; + struct bfd_link_info *info ATTRIBUTE_UNUSED; bfd *abfd; { asection *sec = bfd_get_section_by_name (abfd, ".drectve"); @@ -1012,15 +1194,68 @@ process_embedded_commands (output_bfd, info, abfd) return 1; } +/* Place a marker against all symbols which are used by relocations. + This marker can be picked up by the 'do we skip this symbol ?' + loop in _bfd_coff_link_input_bfd() and used to prevent skipping + that symbol. + */ + +static void +mark_relocs (finfo, input_bfd) + struct coff_final_link_info * finfo; + bfd * input_bfd; +{ + asection * a; + + if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0) + return; + + for (a = input_bfd->sections; a != (asection *) NULL; a = a->next) + { + struct internal_reloc * internal_relocs; + struct internal_reloc * irel; + struct internal_reloc * irelend; + + + if ((a->flags & SEC_RELOC) == 0 || a->reloc_count < 1) + continue; + + /* Read in the relocs. */ + internal_relocs = _bfd_coff_read_internal_relocs + (input_bfd, a, false, + finfo->external_relocs, + finfo->info->relocateable, + (finfo->info->relocateable + ? (finfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count) + : finfo->internal_relocs) + ); + + if (internal_relocs == NULL) + continue; + + irel = internal_relocs; + irelend = irel + a->reloc_count; + + /* Place a mark in the sym_indices array (whose entries have + been initialised to 0) for all of the symbols that are used + in the relocation table. This will then be picked up in the + skip/don't pass */ + + for (; irel < irelend; irel++) + { + finfo->sym_indices[ irel->r_symndx ] = -1; + } + } +} + /* Link an input file into the linker output file. This function handles all the sections and relocations of the input file at once. */ boolean -coff_link_input_bfd (finfo, input_bfd) +_bfd_coff_link_input_bfd (finfo, input_bfd) struct coff_final_link_info *finfo; bfd *input_bfd; { - boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); boolean (*adjust_symndx) PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, struct internal_reloc *, boolean *)); @@ -1046,7 +1281,6 @@ coff_link_input_bfd (finfo, input_bfd) /* Move all the symbols to the output file. */ output_bfd = finfo->output_bfd; - sym_is_global = coff_backend_info (input_bfd)->_bfd_coff_sym_is_global; strings = NULL; syment_base = obj_raw_syment_count (output_bfd); isymesz = bfd_coff_symesz (input_bfd); @@ -1079,17 +1313,32 @@ coff_link_input_bfd (finfo, input_bfd) output_index = syment_base; outsym = finfo->outsyms; - if (coff_data(output_bfd)->pe) - { - if (!process_embedded_commands (output_bfd, finfo->info, input_bfd)) - return false; - } + if (coff_data (output_bfd)->pe) + { + if (! process_embedded_commands (output_bfd, finfo->info, input_bfd)) + return false; + } + + /* If we are going to perform relocations and also strip/discard some symbols + then we must make sure that we do not strip/discard those symbols that are + going to be involved in the relocations */ + if (( finfo->info->strip != strip_none + || finfo->info->discard != discard_none) + && finfo->info->relocateable) + { + /* mark the symbol array as 'not-used' */ + memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp); + + mark_relocs (finfo, input_bfd); + } while (esym < esym_end) { struct internal_syment isym; + enum coff_symbol_classification classification; boolean skip; boolean global; + boolean dont_skip_symbol; int add; bfd_coff_swap_sym_in (input_bfd, (PTR) esym, (PTR) isymp); @@ -1100,16 +1349,33 @@ coff_link_input_bfd (finfo, input_bfd) the symbol. */ isym = *isymp; - if (isym.n_scnum != 0) - *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum); - else + classification = bfd_coff_classify_symbol (input_bfd, &isym); + switch (classification) { - if (isym.n_value == 0) - *secpp = bfd_und_section_ptr; - else - *secpp = bfd_com_section_ptr; + default: + abort (); + case COFF_SYMBOL_GLOBAL: + case COFF_SYMBOL_PE_SECTION: + case COFF_SYMBOL_LOCAL: + *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum); + break; + case COFF_SYMBOL_COMMON: + *secpp = bfd_com_section_ptr; + break; + case COFF_SYMBOL_UNDEFINED: + *secpp = bfd_und_section_ptr; + break; } + /* Extract the flag indicating if this symbol is used by a + relocation. */ + if ((finfo->info->strip != strip_none + || finfo->info->discard != discard_none) + && finfo->info->relocateable) + dont_skip_symbol = *indexp; + else + dont_skip_symbol = false; + *indexp = -1; skip = false; @@ -1117,36 +1383,60 @@ coff_link_input_bfd (finfo, input_bfd) add = 1 + isym.n_numaux; /* If we are stripping all symbols, we want to skip this one. */ - if (finfo->info->strip == strip_all) + if (finfo->info->strip == strip_all && ! dont_skip_symbol) skip = true; if (! skip) { - if (isym.n_sclass == C_EXT - || (sym_is_global && (*sym_is_global) (input_bfd, &isym))) + switch (classification) { + default: + abort (); + case COFF_SYMBOL_GLOBAL: + case COFF_SYMBOL_COMMON: + case COFF_SYMBOL_PE_SECTION: /* This is a global symbol. Global symbols come at the end of the symbol table, so skip them for now. - Function symbols, however, are an exception, and are - not moved to the end. */ + Locally defined function symbols, however, are an + exception, and are not moved to the end. */ global = true; if (! ISFCN (isym.n_type)) skip = true; - } - else - { + break; + + case COFF_SYMBOL_UNDEFINED: + /* Undefined symbols are left for the end. */ + global = true; + skip = true; + break; + + case COFF_SYMBOL_LOCAL: /* This is a local symbol. Skip it if we are discarding local symbols. */ - if (finfo->info->discard == discard_all) + if (finfo->info->discard == discard_all && ! dont_skip_symbol) skip = true; + break; } } /* If we stripping debugging symbols, and this is a debugging - symbol, then skip it. */ + symbol, then skip it. FIXME: gas sets the section to N_ABS + for some types of debugging symbols; I don't know if this is + a bug or not. In any case, we handle it here. */ if (! skip && finfo->info->strip == strip_debugger - && isym.n_scnum == N_DEBUG) + && ! dont_skip_symbol + && (isym.n_scnum == N_DEBUG + || (isym.n_scnum == N_ABS + && (isym.n_sclass == C_AUTO + || isym.n_sclass == C_REG + || isym.n_sclass == C_MOS + || isym.n_sclass == C_MOE + || isym.n_sclass == C_MOU + || isym.n_sclass == C_ARG + || isym.n_sclass == C_REGPARM + || isym.n_sclass == C_FIELD + || isym.n_sclass == C_EOS)))) skip = true; /* If some symbols are stripped based on the name, work out the @@ -1162,13 +1452,13 @@ coff_link_input_bfd (finfo, input_bfd) if (name == NULL) return false; - if ((finfo->info->strip == strip_some - && (bfd_hash_lookup (finfo->info->keep_hash, name, false, + if (! dont_skip_symbol + && ((finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false) == NULL)) - || (! global - && finfo->info->discard == discard_l - && strncmp (name, finfo->info->lprefix, - finfo->info->lprefix_len) == 0)) + || (! global + && finfo->info->discard == discard_l + && bfd_is_local_label_name (input_bfd, name)))) skip = true; } @@ -1189,7 +1479,6 @@ coff_link_input_bfd (finfo, input_bfd) struct coff_debug_merge_element **epp; bfd_byte *esl, *eslend; struct internal_syment *islp; - struct coff_debug_merge_type *mtl; name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); if (name == NULL) @@ -1197,9 +1486,9 @@ coff_link_input_bfd (finfo, input_bfd) /* Ignore fake names invented by compiler; treat them all as the same name. */ - if (*name == '~' || *name == '.' + if (*name == '~' || *name == '.' || *name == '$' || (*name == bfd_get_symbol_leading_char (input_bfd) - && (name[1] == '~' || name[1] == '.'))) + && (name[1] == '~' || name[1] == '.' || name[1] == '$'))) name = ""; mh = coff_debug_merge_hash_lookup (&finfo->debug_merge, name, @@ -1293,42 +1582,50 @@ coff_link_input_bfd (finfo, input_bfd) } /* See if we already have a definition which matches this - type. */ - for (mtl = mh->types; mtl != NULL; mtl = mtl->next) + type. We always output the type if it has no elements, + for simplicity. */ + if (mt->elements == NULL) + bfd_release (input_bfd, (PTR) mt); + else { - struct coff_debug_merge_element *me, *mel; + struct coff_debug_merge_type *mtl; - if (mtl->class != mt->class) - continue; - - for (me = mt->elements, mel = mtl->elements; - me != NULL && mel != NULL; - me = me->next, mel = mel->next) + for (mtl = mh->types; mtl != NULL; mtl = mtl->next) { - if (strcmp (me->name, mel->name) != 0 - || me->type != mel->type - || me->tagndx != mel->tagndx) + struct coff_debug_merge_element *me, *mel; + + if (mtl->class != mt->class) + continue; + + for (me = mt->elements, mel = mtl->elements; + me != NULL && mel != NULL; + me = me->next, mel = mel->next) + { + if (strcmp (me->name, mel->name) != 0 + || me->type != mel->type + || me->tagndx != mel->tagndx) + break; + } + + if (me == NULL && mel == NULL) break; } - if (me == NULL && mel == NULL) - break; - } - - if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base) - { - /* This is the first definition of this type. */ - mt->indx = output_index; - mt->next = mh->types; - mh->types = mt; - } - else - { - /* This is a redefinition which can be merged. */ - bfd_release (input_bfd, (PTR) mt); - *indexp = mtl->indx; - add = (eslend - esym) / isymesz; - skip = true; + if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base) + { + /* This is the first definition of this type. */ + mt->indx = output_index; + mt->next = mh->types; + mh->types = mt; + } + else + { + /* This is a redefinition which can be merged. */ + bfd_release (input_bfd, (PTR) mt); + *indexp = mtl->indx; + add = (eslend - esym) / isymesz; + skip = true; + } } } @@ -1361,9 +1658,11 @@ coff_link_input_bfd (finfo, input_bfd) if (isym.n_scnum > 0) { isym.n_scnum = (*secpp)->output_section->target_index; - isym.n_value += ((*secpp)->output_section->vma - + (*secpp)->output_offset - - (*secpp)->vma); + isym.n_value += (*secpp)->output_offset; + if (! obj_pe (input_bfd)) + isym.n_value -= (*secpp)->vma; + if (! obj_pe (finfo->output_bfd)) + isym.n_value += (*secpp)->output_section->vma; } /* The value of a C_FILE symbol is the symbol index of the @@ -1414,6 +1713,15 @@ coff_link_input_bfd (finfo, input_bfd) finfo->last_file = isym; } + /* If doing task linking, convert normal global function symbols to + static functions. */ + + if (finfo->info->task_link + && (isym.n_sclass == C_EXT + || isym.n_sclass == C_WEAKEXT + || (obj_pe (input_bfd) && isym.n_sclass == C_NT_WEAK))) + isym.n_sclass = C_STAT; + /* Output the symbol. */ bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) outsym); @@ -1428,7 +1736,13 @@ coff_link_input_bfd (finfo, input_bfd) indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd)) / isymesz); h = obj_coff_sym_hashes (input_bfd)[indx]; - BFD_ASSERT (h != NULL); + if (h == NULL) + { + /* This can happen if there were errors earlier in + the link. */ + bfd_set_error (bfd_error_bad_value); + return false; + } h->indx = output_index; } @@ -1477,7 +1791,12 @@ coff_link_input_bfd (finfo, input_bfd) if (*indexp < 0) { h = *sym_hash; - BFD_ASSERT (h->numaux == isymp->n_numaux); + + /* The m68k-motorola-sysv assembler will sometimes + generate two symbols with the same name, but only one + will have aux entries. */ + BFD_ASSERT (isymp->n_numaux == 0 + || h->numaux == isymp->n_numaux); } esym += isymesz; @@ -1534,7 +1853,8 @@ coff_link_input_bfd (finfo, input_bfd) if (ISFCN (isymp->n_type) || ISTAG (isymp->n_sclass) - || isymp->n_sclass == C_BLOCK) + || isymp->n_sclass == C_BLOCK + || isymp->n_sclass == C_FCN) { indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l; if (indx > 0 @@ -1544,7 +1864,9 @@ coff_link_input_bfd (finfo, input_bfd) the index of the next symbol we are going to include. I don't know if this is entirely right. */ - while (finfo->sym_indices[indx] < 0 + while ((finfo->sym_indices[indx] < 0 + || ((bfd_size_type) finfo->sym_indices[indx] + < syment_base)) && indx < obj_raw_syment_count (input_bfd)) ++indx; if (indx >= obj_raw_syment_count (input_bfd)) @@ -1566,6 +1888,81 @@ coff_link_input_bfd (finfo, input_bfd) else auxp->x_sym.x_tagndx.l = symindx; } + + /* The .bf symbols are supposed to be linked through + the endndx field. We need to carry this list + across object files. */ + if (i == 0 + && h == NULL + && isymp->n_sclass == C_FCN + && (isymp->_n._n_n._n_zeroes != 0 + || isymp->_n._n_n._n_offset == 0) + && isymp->_n._n_name[0] == '.' + && isymp->_n._n_name[1] == 'b' + && isymp->_n._n_name[2] == 'f' + && isymp->_n._n_name[3] == '\0') + { + if (finfo->last_bf_index != -1) + { + finfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l = + *indexp; + + if ((bfd_size_type) finfo->last_bf_index + >= syment_base) + { + PTR auxout; + + /* The last .bf symbol is in this input + file. This will only happen if the + assembler did not set up the .bf + endndx symbols correctly. */ + auxout = (PTR) (finfo->outsyms + + ((finfo->last_bf_index + - syment_base) + * osymesz)); + bfd_coff_swap_aux_out (output_bfd, + (PTR) &finfo->last_bf, + isymp->n_type, + isymp->n_sclass, + 0, isymp->n_numaux, + auxout); + } + else + { + /* We have already written out the last + .bf aux entry. We need to write it + out again. We borrow *outsym + temporarily. FIXME: This case should + be made faster. */ + bfd_coff_swap_aux_out (output_bfd, + (PTR) &finfo->last_bf, + isymp->n_type, + isymp->n_sclass, + 0, isymp->n_numaux, + (PTR) outsym); + if (bfd_seek (output_bfd, + (obj_sym_filepos (output_bfd) + + finfo->last_bf_index * osymesz), + SEEK_SET) != 0 + || bfd_write (outsym, osymesz, 1, + output_bfd) != osymesz) + return false; + } + } + + if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0) + finfo->last_bf_index = -1; + else + { + /* The endndx field of this aux entry must + be updated with the symbol number of the + next .bf symbol. */ + finfo->last_bf = *auxp; + finfo->last_bf_index = (((outsym - finfo->outsyms) + / osymesz) + + syment_base); + } + } } if (h == NULL) @@ -1735,14 +2132,22 @@ coff_link_input_bfd (finfo, input_bfd) for (o = input_bfd->sections; o != NULL; o = o->next) { bfd_byte *contents; + struct coff_section_tdata *secdata; - if ((o->flags & SEC_HAS_CONTENTS) == 0) + if (! o->linker_mark) + { + /* This section was omitted from the link. */ + continue; + } + + if ((o->flags & SEC_HAS_CONTENTS) == 0 + || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0)) { if ((o->flags & SEC_RELOC) != 0 && o->reloc_count != 0) { ((*_bfd_error_handler) - ("%s: relocs in section `%s', but it has no contents", + (_("%s: relocs in section `%s', but it has no contents"), bfd_get_filename (input_bfd), bfd_get_section_name (input_bfd, o))); bfd_set_error (bfd_error_no_contents); @@ -1752,9 +2157,9 @@ coff_link_input_bfd (finfo, input_bfd) continue; } - if (coff_section_data (input_bfd, o) != NULL - && coff_section_data (input_bfd, o)->contents != NULL) - contents = coff_section_data (input_bfd, o)->contents; + secdata = coff_section_data (input_bfd, o); + if (secdata != NULL && secdata->contents != NULL) + contents = secdata->contents; else { if (! bfd_get_section_contents (input_bfd, o, finfo->contents, @@ -1858,9 +2263,10 @@ coff_link_input_bfd (finfo, input_bfd) char buf[SYMNMLEN + 1]; /* This reloc is against a symbol we are - stripping. It would be possible to - handle this case, but I don't think it's - worth it. */ + stripping. This should have been handled + by the 'dont_skip_symbol' code in the while + loop at the top of this function. */ + is = finfo->internal_syms + irel->r_symndx; name = (_bfd_coff_internal_syment_name @@ -1881,12 +2287,22 @@ coff_link_input_bfd (finfo, input_bfd) } /* Write out the modified section contents. */ - if (! bfd_set_section_contents (output_bfd, o->output_section, - contents, o->output_offset, - (o->_cooked_size != 0 - ? o->_cooked_size - : o->_raw_size))) - return false; + if (secdata == NULL || secdata->stab_info == NULL) + { + if (! bfd_set_section_contents (output_bfd, o->output_section, + contents, o->output_offset, + (o->_cooked_size != 0 + ? o->_cooked_size + : o->_raw_size))) + return false; + } + else + { + if (! (_bfd_write_section_stabs + (output_bfd, &coff_hash_table (finfo->info)->stab_info, + o, &secdata->stab_info, contents))) + return false; + } } if (! finfo->info->keep_memory) @@ -1901,7 +2317,7 @@ coff_link_input_bfd (finfo, input_bfd) /* Write out a global symbol. Called via coff_link_hash_traverse. */ boolean -coff_write_global_sym (h, data) +_bfd_coff_write_global_sym (h, data) struct coff_link_hash_entry *h; PTR data; { @@ -1948,8 +2364,9 @@ coff_write_global_sym (h, data) else isym.n_scnum = sec->target_index; isym.n_value = (h->root.u.def.value - + sec->vma + h->root.u.def.section->output_offset); + if (! obj_pe (finfo->output_bfd)) + isym.n_value += sec->vma; } break; @@ -1991,6 +2408,21 @@ coff_write_global_sym (h, data) if (isym.n_sclass == C_NULL) isym.n_sclass = C_EXT; + /* If doing task linking and this is the pass where we convert + defined globals to statics, then do that conversion now. If the + symbol is not being converted, just ignore it and it will be + output during a later pass. */ + if (finfo->global_to_static) + { + if (isym.n_sclass != C_EXT + && isym.n_sclass != C_WEAKEXT + && (! obj_pe (output_bfd) || isym.n_sclass != C_NT_WEAK)) + { + return true; + } + isym.n_sclass = C_STAT; + } + isym.n_numaux = h->numaux; bfd_coff_swap_sym_out (output_bfd, (PTR) &isym, (PTR) finfo->outsyms); @@ -2029,10 +2461,41 @@ coff_write_global_sym (h, data) return true; } +/* Write out task global symbols, converting them to statics. Called + via coff_link_hash_traverse. Calls bfd_coff_write_global_sym to do + the dirty work, if the symbol we are processing needs conversion. */ + +boolean +_bfd_coff_write_task_globals (h, data) + struct coff_link_hash_entry *h; + PTR data; +{ + struct coff_final_link_info *finfo = (struct coff_final_link_info *) data; + boolean rtnval = true; + boolean save_global_to_static; + + if (h->indx < 0) + { + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + save_global_to_static = finfo->global_to_static; + finfo->global_to_static = true; + rtnval = _bfd_coff_write_global_sym (h, data); + finfo->global_to_static = save_global_to_static; + break; + default: + break; + } + } + return (rtnval); +} + /* Handle a link order which is supposed to generate a reloc. */ boolean -coff_reloc_link_order (output_bfd, finfo, output_section, link_order) +_bfd_coff_reloc_link_order (output_bfd, finfo, output_section, link_order) bfd *output_bfd; struct coff_final_link_info *finfo; asection *output_section; @@ -2119,9 +2582,10 @@ coff_reloc_link_order (output_bfd, finfo, output_section, link_order) { struct coff_link_hash_entry *h; - h = coff_link_hash_lookup (coff_hash_table (finfo->info), - link_order->u.reloc.p->u.name, - false, false, true); + h = ((struct coff_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, finfo->info, + link_order->u.reloc.p->u.name, + false, false, true)); if (h != NULL) { if (h->indx >= 0) @@ -2196,6 +2660,14 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, h = NULL; sym = NULL; } + else if (symndx < 0 + || (unsigned long) symndx >= obj_raw_syment_count (input_bfd)) + { + (*_bfd_error_handler) + ("%s: illegal symbol index %ld in relocs", + bfd_get_filename (input_bfd), symndx); + return false; + } else { h = obj_coff_sym_hashes (input_bfd)[symndx]; @@ -2218,6 +2690,18 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, if (howto == NULL) return false; + /* If we are doing a relocateable link, then we can just ignore + a PC relative reloc that is pcrel_offset. It will already + have the correct value. If this is not a relocateable link, + then we should ignore the symbol value. */ + if (howto->pc_relative && howto->pcrel_offset) + { + if (info->relocateable) + continue; + if (sym != NULL && sym->n_scnum != 0) + addend += sym->n_value; + } + val = 0; if (h == NULL) @@ -2234,8 +2718,9 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, sec = sections[symndx]; val = (sec->output_section->vma + sec->output_offset - + sym->n_value - - sec->vma); + + sym->n_value); + if (! obj_pe (input_bfd)) + val -= sec->vma; } } else @@ -2263,18 +2748,26 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, if (info->base_file) { /* Emit a reloc if the backend thinks it needs it. */ - if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto)) + if (sym && pe_data (output_bfd)->in_reloc_p (output_bfd, howto)) { - /* relocation to a symbol in a section which - isn't absolute - we output the address here - to a file */ - bfd_vma addr = rel->r_vaddr - - input_section->vma - + input_section->output_offset - + input_section->output_section->vma; - if (coff_data(output_bfd)->pe) + /* Relocation to a symbol in a section which isn't + absolute. We output the address here to a file. + This file is then read by dlltool when generating the + reloc section. Note that the base file is not + portable between systems. We write out a long here, + and dlltool reads in a long. */ + long addr = (rel->r_vaddr + - input_section->vma + + input_section->output_offset + + input_section->output_section->vma); + if (coff_data (output_bfd)->pe) addr -= pe_data(output_bfd)->pe_opthdr.ImageBase; - fwrite (&addr, 1,4, (FILE *) info->base_file); + if (fwrite (&addr, 1, sizeof (long), (FILE *) info->base_file) + != sizeof (long)) + { + bfd_set_error (bfd_error_system_call); + return false; + } } } @@ -2289,6 +2782,13 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, abort (); case bfd_reloc_ok: break; + case bfd_reloc_outofrange: + (*_bfd_error_handler) + (_("%s: bad reloc address 0x%lx in section `%s'"), + bfd_get_filename (input_bfd), + (unsigned long) rel->r_vaddr, + bfd_get_section_name (input_bfd, input_section)); + return false; case bfd_reloc_overflow: { const char *name;