diff options
Diffstat (limited to 'contrib/binutils/bfd/cofflink.c')
-rw-r--r-- | contrib/binutils/bfd/cofflink.c | 539 |
1 files changed, 407 insertions, 132 deletions
diff --git a/contrib/binutils/bfd/cofflink.c b/contrib/binutils/bfd/cofflink.c index 7b2b8305dbf0..609f6653e098 100644 --- a/contrib/binutils/bfd/cofflink.c +++ b/contrib/binutils/bfd/cofflink.c @@ -1,5 +1,5 @@ /* COFF specific linker code. - Copyright 1994, 1995, 1996, 1997 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. @@ -40,6 +40,16 @@ static int process_embedded_commands PARAMS ((bfd *, struct bfd_link_info *, bfd *)); static void mark_relocs PARAMS ((struct coff_final_link_info *, bfd *)); +/* Define macros so that the ISFCN, et. al., macros work correctly. + These macros are defined in include/coff/internal.h in terms of + N_TMASK, etc. These definitions require a user to define local + variables with the appropriate names, and with values from the + coff_data (abfd) structure. */ + +#define N_TMASK n_tmask +#define N_BTSHFT n_btshft +#define N_BTMASK n_btmask + /* Create an entry in a COFF linker hash table. */ struct bfd_hash_entry * @@ -225,30 +235,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 -#ifdef C_SYSTEM - || sym.n_sclass == C_SYSTEM -#endif - || (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]; @@ -290,7 +295,9 @@ coff_link_add_symbols (abfd, info) bfd *abfd; struct bfd_link_info *info; { - boolean (*sym_is_global) PARAMS ((bfd *, struct internal_syment *)); + unsigned int n_tmask = coff_data (abfd)->local_n_tmask; + unsigned int n_btshft = coff_data (abfd)->local_n_btshft; + unsigned int n_btmask = coff_data (abfd)->local_n_btmask; boolean keep_syms; boolean default_copy; bfd_size_type symcount; @@ -304,8 +311,6 @@ coff_link_add_symbols (abfd, info) keep_syms = obj_coff_keep_syms (abfd); obj_coff_keep_syms (abfd) = true; - sym_is_global = coff_backend_info (abfd)->_bfd_coff_sym_is_global; - if (info->keep_memory) default_copy = false; else @@ -332,21 +337,20 @@ 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 -#ifdef C_SYSTEM - || sym.n_sclass == C_SYSTEM -#endif - || (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. */ @@ -363,33 +367,119 @@ coff_link_add_symbols (abfd, info) value = sym.n_value; - if (sym.n_scnum == 0) - { - if (value == 0) - { - flags = 0; - section = bfd_und_section_ptr; - } - else - { - flags = BSF_GLOBAL; - section = bfd_com_section_ptr; - } - } - else + switch (classification) { + 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 (! (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 (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) + { + 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; + } + } + + /* The Microsoft Visual C compiler does string pooling by + hashing the constants to an internal symbol name, and + relying on the the linker comdat support to discard + duplicate names. However, if one string is a literal and + one is a data initializer, one will end up in the .data + section and one will end up in the .rdata section. The + Microsoft linker will combine them into the .data + section, which seems to be wrong since it might cause the + literal to change. + + As long as there are no external references to the + symbols, which there shouldn't be, we can treat the .data + and .rdata instances as separate symbols. The comdat + code in the linker will do the appropriate merging. Here + we avoid getting a multiple definition error for one of + these special symbols. + + FIXME: I don't think this will work in the case where + there are two object files which use the constants as a + literal and two object files which use it as a data + initializer. One or the other of the second object files + is going to wind up with an inappropriate reference. */ + if (obj_pe (abfd) + && (classification == COFF_SYMBOL_GLOBAL + || classification == COFF_SYMBOL_PE_SECTION) + && section->comdat != NULL + && strncmp (name, "??_", 3) == 0 + && strcmp (name, section->comdat->name) == 0) + { + if (*sym_hash == NULL) + *sym_hash = coff_link_hash_lookup (coff_hash_table (info), + name, false, copy, false); + if (*sym_hash != NULL + && (*sym_hash)->root.type == bfd_link_hash_defined + && (*sym_hash)->root.u.def.section->comdat != NULL + && strcmp ((*sym_hash)->root.u.def.section->comdat->name, + section->comdat->name) == 0) + addit = false; + } + + if (addit) + { + 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 (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) + (*sym_hash)->coff_link_hash_flags |= + COFF_LINK_HASH_PE_SECTION_SYMBOL; + + /* Limit the alignment of a common symbol to the possible + alignment of a section. There is no point to permitting + a higher alignment for a common symbol: we can not + guarantee it, and it may cause us to allocate extra space + in the common section. */ if (section == bfd_com_section_ptr && (*sym_hash)->root.type == bfd_link_hash_common && ((*sym_hash)->root.u.c.p->alignment_power @@ -399,24 +489,44 @@ coff_link_add_symbols (abfd, info) if (info->hash->creator->flavour == bfd_get_flavour (abfd)) { - if (((*sym_hash)->class == C_NULL - && (*sym_hash)->type == T_NULL) - || sym.n_scnum != 0 - || (sym.n_value != 0 - && (*sym_hash)->root.type != bfd_link_hash_defined)) - { - (*sym_hash)->class = sym.n_sclass; - 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 we don't have any symbol information currently in + the hash table, or if we are looking at a symbol + definition, then update the symbol class and type in + the hash table. */ + if (((*sym_hash)->class == C_NULL + && (*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_defweak)) + { + (*sym_hash)->class = sym.n_sclass; + if (sym.n_type != T_NULL) + { + /* We want to warn if the type changed, but not + if it changed from an unspecified type. + Testing the whole type byte may work, but the + change from (e.g.) a function of unspecified + type to function of known type also wants to + skip the warning. */ + if ((*sym_hash)->type != T_NULL + && (*sym_hash)->type != sym.n_type + && !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type) + && (BTYPE ((*sym_hash)->type) == T_NULL + || BTYPE (sym.n_type) == T_NULL))) + (*_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)); + + /* We don't want to change from a meaningful + base type to a null one, but if we know + nothing, take what little we might now know. */ + if (BTYPE (sym.n_type) != T_NULL + || (*sym_hash)->type == T_NULL) + (*sym_hash)->type = sym.n_type; + } + (*sym_hash)->auxbfd = abfd; if (sym.n_numaux != 0) { union internal_auxent *alloc; @@ -441,6 +551,26 @@ 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; @@ -768,7 +898,7 @@ _bfd_coff_final_link (abfd, info) == bfd_target_coff_flavour)) { sub = p->u.indirect.section->owner; - if (! bfd_coff_link_output_has_begun (sub)) + if (! bfd_coff_link_output_has_begun (sub, & finfo)) { if (! _bfd_coff_link_input_bfd (&finfo, sub)) goto error_return; @@ -1060,7 +1190,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"); @@ -1203,15 +1333,17 @@ _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 *)); + unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask; + unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft; +#if 0 + unsigned int n_btmask = coff_data (input_bfd)->local_n_btmask; +#endif boolean (*adjust_symndx) PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, struct internal_reloc *, boolean *)); bfd *output_bfd; const char *strings; bfd_size_type syment_base; - unsigned int n_tmask; - unsigned int n_btshft; boolean copy, hash; bfd_size_type isymesz; bfd_size_type osymesz; @@ -1229,7 +1361,6 @@ _bfd_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); @@ -1237,13 +1368,6 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) linesz = bfd_coff_linesz (input_bfd); BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd)); - n_tmask = coff_data (input_bfd)->local_n_tmask; - n_btshft = coff_data (input_bfd)->local_n_btshft; - - /* Define macros so that ISFCN, et. al., macros work correctly. */ -#define N_TMASK n_tmask -#define N_BTSHFT n_btshft - copy = false; if (! finfo->info->keep_memory) copy = true; @@ -1284,6 +1408,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) while (esym < esym_end) { struct internal_syment isym; + enum coff_symbol_classification classification; boolean skip; boolean global; boolean dont_skip_symbol; @@ -1297,14 +1422,22 @@ _bfd_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 @@ -1328,26 +1461,34 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) if (! skip) { - if (isym.n_sclass == C_EXT -#ifdef C_SYSTEM - || isym.n_sclass == C_SYSTEM -#endif - || (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 && ! dont_skip_symbol) skip = true; + break; } } @@ -1455,7 +1596,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) { const char *elename; char elebuf[SYMNMLEN + 1]; - char *copy; + char *name_copy; bfd_coff_swap_sym_in (input_bfd, (PTR) esl, (PTR) islp); @@ -1470,12 +1611,13 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) if (elename == NULL) return false; - copy = (char *) bfd_alloc (input_bfd, strlen (elename) + 1); - if (copy == NULL) + name_copy = (char *) bfd_alloc (input_bfd, + strlen (elename) + 1); + if (name_copy == NULL) return false; - strcpy (copy, elename); + strcpy (name_copy, elename); - (*epp)->name = copy; + (*epp)->name = name_copy; (*epp)->type = islp->n_type; (*epp)->tagndx = 0; if (islp->n_numaux >= 1 @@ -1587,31 +1729,76 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; } - if (isym.n_scnum > 0) + switch (isym.n_sclass) { - isym.n_scnum = (*secpp)->output_section->target_index; - 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; - } + case C_AUTO: + case C_MOS: + case C_EOS: + case C_MOE: + case C_MOU: + case C_UNTAG: + case C_STRTAG: + case C_ENTAG: + case C_TPDEF: + case C_ARG: + case C_USTATIC: + case C_REG: + case C_REGPARM: + case C_FIELD: + /* The symbol value should not be modified. */ + break; + + case C_FCN: + if (obj_pe (input_bfd) + && strcmp (isym.n_name, ".bf") != 0 + && isym.n_scnum > 0) + { + /* For PE, .lf and .ef get their value left alone, + while .bf gets relocated. However, they all have + "real" section numbers, and need to be moved into + the new section. */ + isym.n_scnum = (*secpp)->output_section->target_index; + break; + } + /* Fall through. */ + default: + case C_LABEL: /* Not completely sure about these 2 */ + case C_EXTDEF: + case C_BLOCK: + case C_EFCN: + case C_NULL: + case C_EXT: + case C_STAT: + case C_SECTION: + case C_NT_WEAK: + /* Compute new symbol location. */ + if (isym.n_scnum > 0) + { + isym.n_scnum = (*secpp)->output_section->target_index; + 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; + } + break; + + case C_FILE: + /* The value of a C_FILE symbol is the symbol index of + the next C_FILE symbol. The value of the last C_FILE + symbol is the symbol index to the first external + symbol (actually, coff_renumber_symbols does not get + this right--it just sets the value of the last C_FILE + symbol to zero--and nobody has ever complained about + it). We try to get this right, below, just before we + write the symbols out, but in the general case we may + have to write the symbol out twice. */ - /* The value of a C_FILE symbol is the symbol index of the - next C_FILE symbol. The value of the last C_FILE symbol - is the symbol index to the first external symbol - (actually, coff_renumber_symbols does not get this - right--it just sets the value of the last C_FILE symbol - to zero--and nobody has ever complained about it). We - try to get this right, below, just before we write the - symbols out, but in the general case we may have to write - the symbol out twice. */ - if (isym.n_sclass == C_FILE) - { if (finfo->last_file_index != -1 && finfo->last_file.n_value != (long) output_index) { - /* We must correct the value of the last C_FILE entry. */ + /* We must correct the value of the last C_FILE + entry. */ finfo->last_file.n_value = output_index; if ((bfd_size_type) finfo->last_file_index >= syment_base) { @@ -1643,12 +1830,16 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) finfo->last_file_index = output_index; finfo->last_file = isym; + break; } /* If doing task linking, convert normal global function symbols to static functions. */ - if (finfo->info->task_link && isym.n_sclass == C_EXT) + 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. */ @@ -1920,6 +2111,8 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) bfd_vma offset; bfd_byte *eline; bfd_byte *elineend; + bfd_byte *oeline; + boolean skipping; /* FIXME: If SEC_HAS_CONTENTS is not for the section, then build_link_order in ldwrite.c will not have created a @@ -1941,7 +2134,9 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) offset = o->output_section->vma + o->output_offset - o->vma; eline = finfo->linenos; + oeline = finfo->linenos; elineend = eline + linesz * o->lineno_count; + skipping = false; for (; eline < elineend; eline += linesz) { struct internal_lineno iline; @@ -1961,11 +2156,13 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) if (indx < 0) { /* These line numbers are attached to a symbol - which we are stripping. We should really - just discard the line numbers, but that would - be a pain because we have already counted - them. */ - indx = 0; + which we are stripping. We must discard the + line numbers because reading them back with + no associated symbol (or associating them all + with symbol #0) will fail. We can't regain + the space in the output file, but at least + they're dense. */ + skipping = true; } else { @@ -2004,23 +2201,32 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) is.n_type, is.n_sclass, 0, is.n_numaux, auxptr); } + + skipping = false; } iline.l_addr.l_symndx = indx; } - bfd_coff_swap_lineno_out (output_bfd, (PTR) &iline, (PTR) eline); + if (!skipping) + { + bfd_coff_swap_lineno_out (output_bfd, (PTR) &iline, + (PTR) oeline); + oeline += linesz; + } } if (bfd_seek (output_bfd, (o->output_section->line_filepos + o->output_section->lineno_count * linesz), SEEK_SET) != 0 - || bfd_write (finfo->linenos, linesz, o->lineno_count, - output_bfd) != linesz * o->lineno_count) + || (bfd_write (finfo->linenos, 1, oeline - finfo->linenos, + output_bfd) + != (bfd_size_type) (oeline - finfo->linenos))) return false; - o->output_section->lineno_count += o->lineno_count; + o->output_section->lineno_count += + (oeline - finfo->linenos) / linesz; } } @@ -2076,7 +2282,7 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) && 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); @@ -2219,7 +2425,10 @@ _bfd_coff_link_input_bfd (finfo, input_bfd) if (secdata == NULL || secdata->stab_info == NULL) { if (! bfd_set_section_contents (output_bfd, o->output_section, - contents, o->output_offset, + contents, + (file_ptr) + (o->output_offset * + bfd_octets_per_byte (output_bfd)), (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size))) @@ -2337,12 +2546,15 @@ _bfd_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 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) + if (isym.n_sclass != C_EXT + && isym.n_sclass != C_WEAKEXT + && (! obj_pe (output_bfd) || isym.n_sclass != C_NT_WEAK)) { return true; } @@ -2369,11 +2581,64 @@ _bfd_coff_write_global_sym (h, data) ++obj_raw_syment_count (output_bfd); - /* Write out any associated aux entries. There normally will be - none. If there are any, I have no idea how to modify them. */ + /* Write out any associated aux entries. Most of the aux entries + will have been modified in _bfd_coff_link_input_bfd. We have to + handle section aux entries here, now that we have the final + relocation and line number counts. */ for (i = 0; i < isym.n_numaux; i++) { - bfd_coff_swap_aux_out (output_bfd, (PTR) (h->aux + i), isym.n_type, + union internal_auxent *auxp; + + auxp = h->aux + i; + + /* Look for a section aux entry here using the same tests that + coff_swap_aux_out uses. */ + if (i == 0 + && (isym.n_sclass == C_STAT + || isym.n_sclass == C_HIDDEN) + && isym.n_type == T_NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + asection *sec; + + sec = h->root.u.def.section->output_section; + if (sec != NULL) + { + auxp->x_scn.x_scnlen = (sec->_cooked_size != 0 + ? sec->_cooked_size + : sec->_raw_size); + + /* For PE, an overflow on the final link reportedly does + not matter. FIXME: Why not? */ + + if (sec->reloc_count > 0xffff + && (! obj_pe (output_bfd) + || finfo->info->relocateable)) + (*_bfd_error_handler) + (_("%s: %s: reloc overflow: 0x%lx > 0xffff"), + bfd_get_filename (output_bfd), + bfd_get_section_name (output_bfd, sec), + sec->reloc_count); + + if (sec->lineno_count > 0xffff + && (! obj_pe (output_bfd) + || finfo->info->relocateable)) + (*_bfd_error_handler) + (_("%s: warning: %s: line number overflow: 0x%lx > 0xffff"), + bfd_get_filename (output_bfd), + bfd_get_section_name (output_bfd, sec), + sec->lineno_count); + + auxp->x_scn.x_nreloc = sec->reloc_count; + auxp->x_scn.x_nlinno = sec->lineno_count; + auxp->x_scn.x_checksum = 0; + auxp->x_scn.x_associated = 0; + auxp->x_scn.x_comdat = 0; + } + } + + bfd_coff_swap_aux_out (output_bfd, (PTR) auxp, isym.n_type, isym.n_sclass, i, isym.n_numaux, (PTR) finfo->outsyms); if (bfd_write (finfo->outsyms, symesz, 1, output_bfd) != symesz) @@ -2475,7 +2740,9 @@ _bfd_coff_reloc_link_order (output_bfd, finfo, output_section, link_order) break; } ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, - (file_ptr) link_order->offset, size); + (file_ptr) + (link_order->offset * + bfd_octets_per_byte (output_bfd)), size); free (buf); if (! ok) return false; @@ -2586,6 +2853,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]; @@ -2658,7 +2933,7 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, { if (! ((*info->callbacks->undefined_symbol) (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma))) + rel->r_vaddr - input_section->vma, true))) return false; } } @@ -2702,7 +2977,7 @@ _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, break; case bfd_reloc_outofrange: (*_bfd_error_handler) - ("%s: bad reloc address 0x%lx in section `%s'", + (_("%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)); |