X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Fcoffgen.c;h=bec1a424831131a4559858745d8dbf5969eaee64;hb=d218dba3f491191322e50df74376faa11c4a9f6b;hp=a22f67a69d3f0e11077ea1ca63c019b1c5d61607;hpb=a5c71af8d3c7c535f27614947f72883233658706;p=binutils-gdb.git diff --git a/bfd/coffgen.c b/bfd/coffgen.c index a22f67a69d3..bec1a424831 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -1,5 +1,5 @@ /* Support for the generic parts of COFF, for BFD. - Copyright (C) 1990-2014 Free Software Foundation, Inc. + Copyright (C) 1990-2022 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -37,6 +37,7 @@ coff_data (abfd). */ #include "sysdep.h" +#include #include "bfd.h" #include "libbfd.h" #include "coff/internal.h" @@ -45,14 +46,14 @@ /* Take a section header read from a coff file (in HOST byte order), and make a BFD "section" out of it. This is used by ECOFF. */ -static bfd_boolean +static bool make_a_section_from_file (bfd *abfd, struct internal_scnhdr *hdr, unsigned int target_index) { asection *return_section; char *name; - bfd_boolean result = TRUE; + bool result = true; flagword flags; name = NULL; @@ -72,10 +73,10 @@ make_a_section_from_file (bfd *abfd, const char *strings; /* Flag that this BFD uses long names, even though the format might - expect them to be off by default. This won't directly affect the - format of any output BFD created from this one, but the information - can be used to decide what to do. */ - bfd_coff_set_long_section_names (abfd, TRUE); + expect them to be off by default. This won't directly affect the + format of any output BFD created from this one, but the information + can be used to decide what to do. */ + bfd_coff_set_long_section_names (abfd, true); memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1); buf[SCNNMLEN - 1] = '\0'; strindex = strtol (buf, &p, 10); @@ -83,14 +84,14 @@ make_a_section_from_file (bfd *abfd, { strings = _bfd_coff_read_string_table (abfd); if (strings == NULL) - return FALSE; + return false; if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) - return FALSE; + return false; strings += strindex; name = (char *) bfd_alloc (abfd, - (bfd_size_type) strlen (strings) + 1 + 1); + (bfd_size_type) strlen (strings) + 1 + 1); if (name == NULL) - return FALSE; + return false; strcpy (name, strings); } } @@ -99,16 +100,16 @@ make_a_section_from_file (bfd *abfd, { /* Assorted wastage to null-terminate the name, thanks AT&T! */ name = (char *) bfd_alloc (abfd, - (bfd_size_type) sizeof (hdr->s_name) + 1 + 1); + (bfd_size_type) sizeof (hdr->s_name) + 1 + 1); if (name == NULL) - return FALSE; + return false; strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); name[sizeof (hdr->s_name)] = 0; } return_section = bfd_make_section_anyway (abfd, name); if (return_section == NULL) - return FALSE; + return false; return_section->vma = hdr->s_vaddr; return_section->lma = hdr->s_paddr; @@ -128,7 +129,7 @@ make_a_section_from_file (bfd *abfd, if (! bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name, return_section, & flags)) - result = FALSE; + result = false; return_section->flags = flags; @@ -146,8 +147,9 @@ make_a_section_from_file (bfd *abfd, /* Compress/decompress DWARF debug sections with names: .debug_* and .zdebug_*, after the section flags is set. */ if ((flags & SEC_DEBUGGING) + && strlen (name) > 7 && ((name[1] == 'd' && name[6] == '_') - || (name[1] == 'z' && name[7] == '_'))) + || (strlen (name) > 8 && name[1] == 'z' && name[7] == '_'))) { enum { nothing, compress, decompress } action = nothing; char *new_name = NULL; @@ -172,30 +174,35 @@ make_a_section_from_file (bfd *abfd, case compress: if (!bfd_init_section_compress_status (abfd, return_section)) { - (*_bfd_error_handler) - (_("%B: unable to initialize compress status for section %s"), + _bfd_error_handler + /* xgettext: c-format */ + (_("%pB: unable to initialize compress status for section %s"), abfd, name); - return FALSE; + return false; } - if (name[1] != 'z') + if (return_section->compress_status == COMPRESS_SECTION_DONE) { - unsigned int len = strlen (name); - - new_name = bfd_alloc (abfd, len + 2); - if (new_name == NULL) - return FALSE; - new_name[0] = '.'; - new_name[1] = 'z'; - memcpy (new_name + 2, name + 1, len); + if (name[1] != 'z') + { + unsigned int len = strlen (name); + + new_name = bfd_alloc (abfd, len + 2); + if (new_name == NULL) + return false; + new_name[0] = '.'; + new_name[1] = 'z'; + memcpy (new_name + 2, name + 1, len); + } } - break; + break; case decompress: if (!bfd_init_section_decompress_status (abfd, return_section)) { - (*_bfd_error_handler) - (_("%B: unable to initialize decompress status for section %s"), + _bfd_error_handler + /* xgettext: c-format */ + (_("%pB: unable to initialize decompress status for section %s"), abfd, name); - return FALSE; + return false; } if (name[1] == 'z') { @@ -203,14 +210,14 @@ make_a_section_from_file (bfd *abfd, new_name = bfd_alloc (abfd, len); if (new_name == NULL) - return FALSE; + return false; new_name[0] = '.'; memcpy (new_name + 1, name + 2, len - 1); } break; } if (new_name != NULL) - bfd_rename_section (abfd, return_section, new_name); + bfd_rename_section (return_section, new_name); } return result; @@ -218,12 +225,12 @@ make_a_section_from_file (bfd *abfd, /* Read in a COFF object and make it into a BFD. This is used by ECOFF as well. */ -const bfd_target * +bfd_cleanup coff_real_object_p (bfd *, - unsigned, - struct internal_filehdr *, - struct internal_aouthdr *); -const bfd_target * + unsigned, + struct internal_filehdr *, + struct internal_aouthdr *); +bfd_cleanup coff_real_object_p (bfd *abfd, unsigned nscns, struct internal_filehdr *internal_f, @@ -250,14 +257,14 @@ coff_real_object_p (bfd *abfd, if ((internal_f->f_flags & F_EXEC) != 0) abfd->flags |= D_PAGED; - bfd_get_symcount (abfd) = internal_f->f_nsyms; + abfd->symcount = internal_f->f_nsyms; if (internal_f->f_nsyms) abfd->flags |= HAS_SYMS; if (internal_a != (struct internal_aouthdr *) NULL) - bfd_get_start_address (abfd) = internal_a->entry; + abfd->start_address = internal_a->entry; else - bfd_get_start_address (abfd) = 0; + abfd->start_address = 0; /* Set up the tdata area. ECOFF uses its own routine, and overrides abfd->flags. */ @@ -268,13 +275,10 @@ coff_real_object_p (bfd *abfd, scnhsz = bfd_coff_scnhsz (abfd); readsize = (bfd_size_type) nscns * scnhsz; - external_sections = (char *) bfd_alloc (abfd, readsize); + external_sections = (char *) _bfd_alloc_and_read (abfd, readsize, readsize); if (!external_sections) goto fail; - if (bfd_bread ((void *) external_sections, readsize, abfd) != readsize) - goto fail; - /* Set the arch/mach *before* swapping in sections; section header swapping may depend on arch/mach info. */ if (! bfd_coff_set_arch_mach_hook (abfd, (void *) internal_f)) @@ -295,21 +299,23 @@ coff_real_object_p (bfd *abfd, } } - return abfd->xvec; + _bfd_coff_free_symbols (abfd); + return _bfd_no_cleanup; fail: + _bfd_coff_free_symbols (abfd); bfd_release (abfd, tdata); fail2: abfd->tdata.any = tdata_save; abfd->flags = oflags; - bfd_get_start_address (abfd) = ostart; - return (const bfd_target *) NULL; + abfd->start_address = ostart; + return NULL; } /* Turn a COFF file into a BFD, but fail with bfd_error_wrong_format if it is not a COFF file. This is also used by ECOFF. */ -const bfd_target * +bfd_cleanup coff_object_p (bfd *abfd) { bfd_size_type filhsz; @@ -323,14 +329,11 @@ coff_object_p (bfd *abfd) filhsz = bfd_coff_filhsz (abfd); aoutsz = bfd_coff_aoutsz (abfd); - filehdr = bfd_alloc (abfd, filhsz); + filehdr = _bfd_alloc_and_read (abfd, filhsz, filhsz); if (filehdr == NULL) - return NULL; - if (bfd_bread (filehdr, filhsz, abfd) != filhsz) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_wrong_format); - bfd_release (abfd, filehdr); return NULL; } bfd_coff_swap_filehdr_in (abfd, filehdr, &internal_f); @@ -356,15 +359,14 @@ coff_object_p (bfd *abfd) { void * opthdr; - opthdr = bfd_alloc (abfd, aoutsz); + opthdr = _bfd_alloc_and_read (abfd, aoutsz, internal_f.f_opthdr); if (opthdr == NULL) return NULL; - if (bfd_bread (opthdr, (bfd_size_type) internal_f.f_opthdr, abfd) - != internal_f.f_opthdr) - { - bfd_release (abfd, opthdr); - return NULL; - } + /* PR 17512: file: 11056-1136-0.004. */ + if (internal_f.f_opthdr < aoutsz) + memset (((char *) opthdr) + internal_f.f_opthdr, 0, + aoutsz - internal_f.f_opthdr); + bfd_coff_swap_aouthdr_in (abfd, opthdr, (void *) &internal_a); bfd_release (abfd, opthdr); } @@ -463,7 +465,10 @@ _bfd_coff_internal_syment_name (bfd *abfd, if (strings == NULL) return NULL; } - if (sym->_n._n_n._n_offset >= obj_coff_strings_len (abfd)) + /* PR 17910: Only check for string overflow if the length has been set. + Some DLLs, eg those produced by Visual Studio, may not set the length field. */ + if (obj_coff_strings_len (abfd) > 0 + && sym->_n._n_n._n_offset >= obj_coff_strings_len (abfd)) return NULL; return strings + sym->_n._n_n._n_offset; } @@ -481,9 +486,9 @@ _bfd_coff_internal_syment_name (bfd *abfd, struct internal_reloc * _bfd_coff_read_internal_relocs (bfd *abfd, asection *sec, - bfd_boolean cache, + bool cache, bfd_byte *external_relocs, - bfd_boolean require_internal, + bool require_internal, struct internal_reloc *internal_relocs) { bfd_size_type relsz; @@ -539,11 +544,8 @@ _bfd_coff_read_internal_relocs (bfd *abfd, for (; erel < erel_end; erel += relsz, irel++) bfd_coff_swap_reloc_in (abfd, (void *) erel, (void *) irel); - if (free_external != NULL) - { - free (free_external); - free_external = NULL; - } + free (free_external); + free_external = NULL; if (cache && free_internal != NULL) { @@ -561,10 +563,8 @@ _bfd_coff_read_internal_relocs (bfd *abfd, return internal_relocs; error_return: - if (free_external != NULL) - free (free_external); - if (free_internal != NULL) - free (free_internal); + free (free_external); + free (free_internal); return NULL; } @@ -582,7 +582,7 @@ coff_count_linenumbers (bfd *abfd) if (limit == 0) { /* This may be from the backend linker, in which case the - lineno_count in the sections is correct. */ + lineno_count in the sections is correct. */ for (s = abfd->sections; s != NULL; s = s->next) total += s->lineno_count; return total; @@ -600,13 +600,13 @@ coff_count_linenumbers (bfd *abfd) coff_symbol_type *q = coffsymbol (q_maybe); /* The AIX 4.1 compiler can sometimes generate line numbers - attached to debugging symbols. We try to simply ignore - those here. */ + attached to debugging symbols. We try to simply ignore + those here. */ if (q->lineno != NULL && q->symbol.section->owner != NULL) { /* This symbol has line numbers. Increment the owning - section's linenumber count. */ + section's linenumber count. */ alent *l = q->lineno; do @@ -628,22 +628,6 @@ coff_count_linenumbers (bfd *abfd) return total; } -/* Takes a bfd and a symbol, returns a pointer to the coff specific - area of the symbol if there is one. */ - -coff_symbol_type * -coff_symbol_from (bfd *ignore_abfd ATTRIBUTE_UNUSED, - asymbol *symbol) -{ - if (!bfd_family_coff (bfd_asymbol_bfd (symbol))) - return (coff_symbol_type *) NULL; - - if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL) - return (coff_symbol_type *) NULL; - - return (coff_symbol_type *) symbol; -} - static void fixup_symbol_value (bfd *abfd, coff_symbol_type *coff_symbol_ptr, @@ -678,11 +662,11 @@ fixup_symbol_value (bfd *abfd, syment->n_value = (coff_symbol_ptr->symbol.value + coff_symbol_ptr->symbol.section->output_offset); if (! obj_pe (abfd)) - { - syment->n_value += (syment->n_sclass == C_STATLAB) - ? coff_symbol_ptr->symbol.section->output_section->lma - : coff_symbol_ptr->symbol.section->output_section->vma; - } + { + syment->n_value += (syment->n_sclass == C_STATLAB) + ? coff_symbol_ptr->symbol.section->output_section->lma + : coff_symbol_ptr->symbol.section->output_section->vma; + } } else { @@ -701,7 +685,7 @@ fixup_symbol_value (bfd *abfd, chain, and that the last one points to the first external symbol. We do that here too. */ -bfd_boolean +bool coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) { unsigned int symbol_count = bfd_get_symcount (bfd_ptr); @@ -728,7 +712,7 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) amt = sizeof (asymbol *) * ((bfd_size_type) symbol_count + 1); newsyms = (asymbol **) bfd_alloc (bfd_ptr, amt); if (!newsyms) - return FALSE; + return false; bfd_ptr->outsymbols = newsyms; for (i = 0; i < symbol_count; i++) if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0 @@ -760,8 +744,9 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) { - coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + coff_symbol_type *coff_symbol_ptr; + coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; if (coff_symbol_ptr && coff_symbol_ptr->native) { @@ -789,7 +774,7 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) obj_conv_table_size (bfd_ptr) = native_index; - return TRUE; + return true; } /* Run thorough the symbol table again, and fix it so that all @@ -805,9 +790,9 @@ coff_mangle_symbols (bfd *bfd_ptr) for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) { - coff_symbol_type *coff_symbol_ptr = - coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + coff_symbol_type *coff_symbol_ptr; + coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); if (coff_symbol_ptr && coff_symbol_ptr->native) { int i; @@ -825,8 +810,8 @@ coff_mangle_symbols (bfd *bfd_ptr) if (s->fix_line) { /* The value is the offset into the line number entries - for the symbol's section. On output, the symbol's - section should be N_DEBUG. */ + for the symbol's section. On output, the symbol's + section should be N_DEBUG. */ s->u.syment.n_value = (coff_symbol_ptr->symbol.section->output_section->line_filepos + s->u.syment.n_value * bfd_coff_linesz (bfd_ptr)); @@ -862,6 +847,34 @@ coff_mangle_symbols (bfd *bfd_ptr) } } +static void +coff_write_auxent_fname (bfd *abfd, + char *str, + union internal_auxent *auxent, + bfd_size_type *string_size_p) +{ + unsigned int str_length = strlen (str); + unsigned int filnmlen = bfd_coff_filnmlen (abfd); + + if (bfd_coff_long_filenames (abfd)) + { + if (str_length <= filnmlen) + strncpy (auxent->x_file.x_n.x_fname, str, filnmlen); + else + { + auxent->x_file.x_n.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE; + auxent->x_file.x_n.x_n.x_zeroes = 0; + *string_size_p += str_length + 1; + } + } + else + { + strncpy (auxent->x_file.x_n.x_fname, str, filnmlen); + if (str_length > filnmlen) + str[filnmlen] = '\0'; + } +} + static void coff_fix_symbol_name (bfd *abfd, asymbol *symbol, @@ -871,7 +884,6 @@ coff_fix_symbol_name (bfd *abfd, bfd_size_type *debug_string_size_p) { unsigned int name_length; - union internal_auxent *auxent; char *name = (char *) (symbol->name); if (name == NULL) @@ -886,40 +898,19 @@ coff_fix_symbol_name (bfd *abfd, if (native->u.syment.n_sclass == C_FILE && native->u.syment.n_numaux > 0) { - unsigned int filnmlen; - if (bfd_coff_force_symnames_in_strings (abfd)) { - native->u.syment._n._n_n._n_offset = + native->u.syment._n._n_n._n_offset = (*string_size_p + STRING_SIZE_SIZE); native->u.syment._n._n_n._n_zeroes = 0; *string_size_p += 6; /* strlen(".file") + 1 */ } else - strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); + strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); BFD_ASSERT (! (native + 1)->is_sym); - auxent = &(native + 1)->u.auxent; - - filnmlen = bfd_coff_filnmlen (abfd); - - if (bfd_coff_long_filenames (abfd)) - { - if (name_length <= filnmlen) - strncpy (auxent->x_file.x_fname, name, filnmlen); - else - { - auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE; - auxent->x_file.x_n.x_zeroes = 0; - *string_size_p += name_length + 1; - } - } - else - { - strncpy (auxent->x_file.x_fname, name, filnmlen); - if (name_length > filnmlen) - name[filnmlen] = '\0'; - } + coff_write_auxent_fname (abfd, name, &(native + 1)->u.auxent, + string_size_p); } else { @@ -983,7 +974,7 @@ coff_fix_symbol_name (bfd *abfd, /* Write a symbol out to a COFF file. */ -static bfd_boolean +static bool coff_write_symbol (bfd *abfd, asymbol *symbol, combined_entry_type *native, @@ -1026,10 +1017,10 @@ coff_write_symbol (bfd *abfd, symesz = bfd_coff_symesz (abfd); buf = bfd_alloc (abfd, symesz); if (!buf) - return FALSE; + return false; bfd_coff_swap_sym_out (abfd, &native->u.syment, buf); if (bfd_bwrite (buf, symesz, abfd) != symesz) - return FALSE; + return false; bfd_release (abfd, buf); if (native->u.syment.n_numaux > 0) @@ -1040,17 +1031,25 @@ coff_write_symbol (bfd *abfd, auxesz = bfd_coff_auxesz (abfd); buf = bfd_alloc (abfd, auxesz); if (!buf) - return FALSE; + return false; for (j = 0; j < native->u.syment.n_numaux; j++) { BFD_ASSERT (! (native + j + 1)->is_sym); + + /* Adjust auxent only if this isn't the filename + auxiliary entry. */ + if (native->u.syment.n_sclass == C_FILE + && (native + j + 1)->u.auxent.x_file.x_ftype) + coff_write_auxent_fname (abfd, (char *) (native + j + 1)->extrap, + &(native + j + 1)->u.auxent, string_size_p); + bfd_coff_swap_aux_out (abfd, &((native + j + 1)->u.auxent), type, n_sclass, (int) j, native->u.syment.n_numaux, buf); if (bfd_bwrite (buf, auxesz, abfd) != auxesz) - return FALSE; + return false; } bfd_release (abfd, buf); } @@ -1059,17 +1058,18 @@ coff_write_symbol (bfd *abfd, set_index (symbol, *written); *written += numaux + 1; - return TRUE; + return true; } /* Write out a symbol to a COFF file that does not come from a COFF file originally. This symbol may have been created by the linker, or we may be linking a non COFF file to a COFF file. */ -bfd_boolean +bool coff_write_alien_symbol (bfd *abfd, asymbol *symbol, struct internal_syment *isym, + union internal_auxent *iaux, bfd_vma *written, bfd_size_type *string_size_p, asection **debug_string_section_p, @@ -1081,7 +1081,7 @@ coff_write_alien_symbol (bfd *abfd, ? symbol->section->output_section : symbol->section; struct bfd_link_info *link_info = coff_data (abfd)->link_info; - bfd_boolean ret; + bool ret; if ((!link_info || link_info->strip_discarded) && !bfd_is_abs_section (symbol->section) @@ -1089,12 +1089,13 @@ coff_write_alien_symbol (bfd *abfd, { symbol->name = ""; if (isym != NULL) - memset (isym, 0, sizeof (*isym)); - return TRUE; + memset (isym, 0, sizeof (*isym)); + return true; } + memset (dummy, 0, sizeof dummy); native = dummy; - native->is_sym = TRUE; - native[1].is_sym = FALSE; + native->is_sym = true; + native[1].is_sym = false; native->u.syment.n_type = T_NULL; native->u.syment.n_flags = 0; native->u.syment.n_numaux = 0; @@ -1116,13 +1117,13 @@ coff_write_alien_symbol (bfd *abfd, else if (symbol->flags & BSF_DEBUGGING) { /* There isn't much point to writing out a debugging symbol - unless we are prepared to convert it into COFF debugging - format. So, we just ignore them. We must clobber the symbol - name to keep it from being put in the string table. */ + unless we are prepared to convert it into COFF debugging + format. So, we just ignore them. We must clobber the symbol + name to keep it from being put in the string table. */ symbol->name = ""; if (isym != NULL) - memset (isym, 0, sizeof (*isym)); - return TRUE; + memset (isym, 0, sizeof (*isym)); + return true; } else { @@ -1133,9 +1134,9 @@ coff_write_alien_symbol (bfd *abfd, native->u.syment.n_value += output_section->vma; /* Copy the any flags from the file header into the symbol. - FIXME: Why? */ + FIXME: Why? */ { - coff_symbol_type *c = coff_symbol_from (abfd, symbol); + coff_symbol_type *c = coff_symbol_from (symbol); if (c != (coff_symbol_type *) NULL) native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; } @@ -1155,12 +1156,14 @@ coff_write_alien_symbol (bfd *abfd, debug_string_section_p, debug_string_size_p); if (isym != NULL) *isym = native->u.syment; + if (iaux != NULL && native->u.syment.n_numaux) + *iaux = native[1].u.auxent; return ret; } /* Write a native symbol to a COFF file. */ -static bfd_boolean +static bool coff_write_native_symbol (bfd *abfd, coff_symbol_type *symbol, bfd_vma *written, @@ -1177,7 +1180,7 @@ coff_write_native_symbol (bfd *abfd, && symbol->symbol.section->output_section == bfd_abs_section_ptr) { symbol->symbol.name = ""; - return TRUE; + return true; } BFD_ASSERT (native->is_sym); @@ -1206,7 +1209,7 @@ coff_write_native_symbol (bfd *abfd, + symbol->symbol.section->output_offset); count++; } - symbol->done_lineno = TRUE; + symbol->done_lineno = true; if (! bfd_is_const_section (symbol->symbol.section->output_section)) symbol->symbol.section->output_section->moving_line_filepos += @@ -1219,13 +1222,14 @@ coff_write_native_symbol (bfd *abfd, } static void -null_error_handler (const char * fmt ATTRIBUTE_UNUSED, ...) +null_error_handler (const char *fmt ATTRIBUTE_UNUSED, + va_list ap ATTRIBUTE_UNUSED) { } /* Write out the COFF symbols. */ -bfd_boolean +bool coff_write_symbols (bfd *abfd) { bfd_size_type string_size; @@ -1260,22 +1264,22 @@ coff_write_symbols (bfd *abfd) /* Seek to the right place. */ if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) - return FALSE; + return false; /* Output all the symbols we have. */ written = 0; for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { asymbol *symbol = *p; - coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol); + coff_symbol_type *c_symbol = coff_symbol_from (symbol); if (c_symbol == (coff_symbol_type *) NULL || c_symbol->native == (combined_entry_type *) NULL) { - if (!coff_write_alien_symbol (abfd, symbol, NULL, &written, + if (!coff_write_alien_symbol (abfd, symbol, NULL, NULL, &written, &string_size, &debug_string_section, &debug_string_size)) - return FALSE; + return false; } else { @@ -1320,7 +1324,7 @@ coff_write_symbols (bfd *abfd) if (!coff_write_native_symbol (abfd, c_symbol, &written, &string_size, &debug_string_section, &debug_string_size)) - return FALSE; + return false; } } @@ -1339,7 +1343,7 @@ coff_write_symbols (bfd *abfd) #endif if (bfd_bwrite ((void *) buffer, (bfd_size_type) sizeof (buffer), abfd) != sizeof (buffer)) - return FALSE; + return false; /* Handle long section names. This code must handle section names just as they are handled in coff_write_object_contents. */ @@ -1356,7 +1360,7 @@ coff_write_symbols (bfd *abfd) { if (bfd_bwrite (o->name, (bfd_size_type) (len + 1), abfd) != len + 1) - return FALSE; + return false; } } } @@ -1367,8 +1371,9 @@ coff_write_symbols (bfd *abfd) { asymbol *q = *p; size_t name_length = strlen (q->name); - coff_symbol_type *c_symbol = coff_symbol_from (abfd, q); + coff_symbol_type *c_symbol = coff_symbol_from (q); size_t maxlen; + bool is_c_file = false; /* Figure out whether the symbol name should go in the string table. Symbol names that are short enough are stored @@ -1385,7 +1390,7 @@ coff_write_symbols (bfd *abfd) else if (! c_symbol->native->is_sym) maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; - + else if (bfd_coff_symname_in_debug (abfd, &c_symbol->native->u.syment)) /* This symbol name is in the XCOFF .debug section. @@ -1395,10 +1400,11 @@ coff_write_symbols (bfd *abfd) else if (c_symbol->native->u.syment.n_sclass == C_FILE && c_symbol->native->u.syment.n_numaux > 0) { + is_c_file=true; if (bfd_coff_force_symnames_in_strings (abfd)) { if (bfd_bwrite (".file", (bfd_size_type) 6, abfd) != 6) - return FALSE; + return false; } maxlen = bfd_coff_filnmlen (abfd); } @@ -1409,15 +1415,44 @@ coff_write_symbols (bfd *abfd) { if (bfd_bwrite ((void *) (q->name), (bfd_size_type) name_length + 1, abfd) != name_length + 1) - return FALSE; + return false; + } + + /* Add strings for C_FILE aux entries. */ + if (is_c_file + && c_symbol->native->u.syment.n_numaux > 1) + { + for (int j = 1; j < c_symbol->native->u.syment.n_numaux; j++) + { + char *str; + size_t str_length; + + /* Add strings from aux entries only if this isn't the + filename auxiliary entry. */ + if (!c_symbol->native[j + 1].u.auxent.x_file.x_ftype) + continue; + + if (c_symbol->native[j + 1].u.auxent.x_file.x_n.x_fname[0] != 0) + continue; + + str = (char *) c_symbol->native[j + 1].extrap; + str_length = strlen (str); + if (str_length > maxlen) + { + if (bfd_bwrite ((void *) (str), (bfd_size_type) str_length + 1, + abfd) != str_length + 1) + return false; + } + + } } } } else { /* We would normally not write anything here, but we'll write - out 4 so that any stupid coff reader which tries to read the - string table even when there isn't one won't croak. */ + out 4 so that any stupid coff reader which tries to read the + string table even when there isn't one won't croak. */ unsigned int size = STRING_SIZE_SIZE; bfd_byte buffer[STRING_SIZE_SIZE]; @@ -1428,7 +1463,7 @@ coff_write_symbols (bfd *abfd) #endif if (bfd_bwrite ((void *) buffer, (bfd_size_type) STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE) - return FALSE; + return false; } /* Make sure the .debug section was created to be the correct size. @@ -1442,10 +1477,10 @@ coff_write_symbols (bfd *abfd) 1 << debug_string_section->alignment_power) == debug_string_section->size))); - return TRUE; + return true; } -bfd_boolean +bool coff_write_linenumbers (bfd *abfd) { asection *s; @@ -1455,14 +1490,14 @@ coff_write_linenumbers (bfd *abfd) linesz = bfd_coff_linesz (abfd); buff = bfd_alloc (abfd, linesz); if (!buff) - return FALSE; + return false; for (s = abfd->sections; s != (asection *) NULL; s = s->next) { if (s->lineno_count) { asymbol **q = abfd->outsymbols; if (bfd_seek (abfd, s->line_filepos, SEEK_SET) != 0) - return FALSE; + return false; /* Find all the linenumbers in this section. */ while (*q) { @@ -1483,7 +1518,7 @@ coff_write_linenumbers (bfd *abfd) bfd_coff_swap_lineno_out (abfd, &out, buff); if (bfd_bwrite (buff, (bfd_size_type) linesz, abfd) != linesz) - return FALSE; + return false; l++; while (l->line_number) { @@ -1492,7 +1527,7 @@ coff_write_linenumbers (bfd *abfd) bfd_coff_swap_lineno_out (abfd, &out, buff); if (bfd_bwrite (buff, (bfd_size_type) linesz, abfd) != linesz) - return FALSE; + return false; l++; } } @@ -1502,7 +1537,7 @@ coff_write_linenumbers (bfd *abfd) } } bfd_release (abfd, buff); - return TRUE; + return true; } alent * @@ -1519,7 +1554,8 @@ coff_pointerize_aux (bfd *abfd, combined_entry_type *table_base, combined_entry_type *symbol, unsigned int indaux, - combined_entry_type *auxent) + combined_entry_type *auxent, + combined_entry_type *table_end) { unsigned int type = symbol->u.syment.n_type; unsigned int n_sclass = symbol->u.syment.n_sclass; @@ -1537,6 +1573,8 @@ coff_pointerize_aux (bfd *abfd, return; if (n_sclass == C_FILE) return; + if (n_sclass == C_DWARF) + return; BFD_ASSERT (! auxent->is_sym); /* Otherwise patch up. */ @@ -1545,15 +1583,22 @@ coff_pointerize_aux (bfd *abfd, if ((ISFCN (type) || ISTAG (n_sclass) || n_sclass == C_BLOCK || n_sclass == C_FCN) - && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0) + && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0 + && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l + < (long) obj_raw_syment_count (abfd) + && table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l + < table_end) { auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; auxent->fix_end = 1; } + /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can generate one, so we must be careful to ignore it. */ - if (auxent->u.auxent.x_sym.x_tagndx.l > 0) + if ((unsigned long) auxent->u.auxent.x_sym.x_tagndx.l + < obj_raw_syment_count (abfd) + && table_base + auxent->u.auxent.x_sym.x_tagndx.l < table_end) { auxent->u.auxent.x_sym.x_tagndx.p = table_base + auxent->u.auxent.x_sym.x_tagndx.l; @@ -1580,19 +1625,20 @@ build_debug_section (bfd *abfd, asection ** sect_return) return NULL; } - sec_size = sect->size; - debug_section = (char *) bfd_alloc (abfd, sec_size); - if (debug_section == NULL) - return NULL; - /* Seek to the beginning of the `.debug' section and read it. Save the current position first; it is needed by our caller. Then read debug section and reset the file pointer. */ position = bfd_tell (abfd); - if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0 - || bfd_bread (debug_section, sec_size, abfd) != sec_size - || bfd_seek (abfd, position, SEEK_SET) != 0) + if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0) + return NULL; + + sec_size = sect->size; + debug_section = (char *) _bfd_alloc_and_read (abfd, sec_size, sec_size); + if (debug_section == NULL) + return NULL; + + if (bfd_seek (abfd, position, SEEK_SET) != 0) return NULL; * sect_return = sect; @@ -1623,37 +1669,31 @@ copy_name (bfd *abfd, char *name, size_t maxlen) /* Read in the external symbols. */ -bfd_boolean +bool _bfd_coff_get_external_symbols (bfd *abfd) { - bfd_size_type symesz; - bfd_size_type size; + size_t symesz; + size_t size; void * syms; if (obj_coff_external_syms (abfd) != NULL) - return TRUE; + return true; symesz = bfd_coff_symesz (abfd); - - size = obj_raw_syment_count (abfd) * symesz; - if (size == 0) - return TRUE; - - syms = bfd_malloc (size); - if (syms == NULL) - return FALSE; - - if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 - || bfd_bread (syms, size, abfd) != size) + if (_bfd_mul_overflow (obj_raw_syment_count (abfd), symesz, &size)) { - if (syms != NULL) - free (syms); - return FALSE; + bfd_set_error (bfd_error_file_truncated); + return false; } - obj_coff_external_syms (abfd) = syms; + if (size == 0) + return true; - return TRUE; + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) + return false; + syms = _bfd_malloc_and_read (abfd, size, size); + obj_coff_external_syms (abfd) = syms; + return syms != NULL; } /* Read in the external strings. The strings are not loaded until @@ -1668,7 +1708,10 @@ _bfd_coff_read_string_table (bfd *abfd) char extstrsize[STRING_SIZE_SIZE]; bfd_size_type strsize; char *strings; - file_ptr pos; + ufile_ptr pos; + ufile_ptr filesize; + size_t symesz; + size_t size; if (obj_coff_strings (abfd) != NULL) return obj_coff_strings (abfd); @@ -1679,9 +1722,16 @@ _bfd_coff_read_string_table (bfd *abfd) return NULL; } + symesz = bfd_coff_symesz (abfd); pos = obj_sym_filepos (abfd); - pos += obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); - if (bfd_seek (abfd, pos, SEEK_SET) != 0) + if (_bfd_mul_overflow (obj_raw_syment_count (abfd), symesz, &size) + || pos + size < pos) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + + if (bfd_seek (abfd, pos + size, SEEK_SET) != 0) return NULL; if (bfd_bread (extstrsize, (bfd_size_type) sizeof extstrsize, abfd) @@ -1702,24 +1752,27 @@ _bfd_coff_read_string_table (bfd *abfd) #endif } - if (strsize < STRING_SIZE_SIZE) + filesize = bfd_get_file_size (abfd); + if (strsize < STRING_SIZE_SIZE + || (filesize != 0 && strsize > filesize)) { - (*_bfd_error_handler) - (_("%B: bad string table size %lu"), abfd, (unsigned long) strsize); + _bfd_error_handler + /* xgettext: c-format */ + (_("%pB: bad string table size %" PRIu64), abfd, (uint64_t) strsize); bfd_set_error (bfd_error_bad_value); return NULL; } strings = (char *) bfd_malloc (strsize + 1); + if (strings == NULL) + return NULL; + /* PR 17521 file: 079-54929-0.004. A corrupt file could contain an index that points into the first STRING_SIZE_SIZE bytes of the string table, so make sure that they are zero. */ memset (strings, 0, STRING_SIZE_SIZE); - if (strings == NULL) - return NULL; - if (bfd_bread (strings + STRING_SIZE_SIZE, strsize - STRING_SIZE_SIZE, abfd) != strsize - STRING_SIZE_SIZE) { @@ -1736,15 +1789,19 @@ _bfd_coff_read_string_table (bfd *abfd) /* Free up the external symbols and strings read from a COFF file. */ -bfd_boolean +bool _bfd_coff_free_symbols (bfd *abfd) { + if (! bfd_family_coff (abfd)) + return false; + if (obj_coff_external_syms (abfd) != NULL && ! obj_coff_keep_syms (abfd)) { free (obj_coff_external_syms (abfd)); obj_coff_external_syms (abfd) = NULL; } + if (obj_coff_strings (abfd) != NULL && ! obj_coff_keep_strings (abfd)) { @@ -1752,7 +1809,8 @@ _bfd_coff_free_symbols (bfd *abfd) obj_coff_strings (abfd) = NULL; obj_coff_strings_len (abfd) = 0; } - return TRUE; + + return true; } /* Read a symbol table into freshly bfd_allocated memory, swap it, and @@ -1781,17 +1839,21 @@ coff_get_normalized_symtab (bfd *abfd) if (! _bfd_coff_get_external_symbols (abfd)) return NULL; - size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); + size = obj_raw_syment_count (abfd); + /* Check for integer overflow. */ + if (size > (bfd_size_type) -1 / sizeof (combined_entry_type)) + return NULL; + size *= sizeof (combined_entry_type); internal = (combined_entry_type *) bfd_zalloc (abfd, size); if (internal == NULL && size != 0) return NULL; internal_end = internal + obj_raw_syment_count (abfd); - + raw_src = (char *) obj_coff_external_syms (abfd); /* Mark the end of the symbols. */ symesz = bfd_coff_symesz (abfd); - raw_end = (char *) raw_src + obj_raw_syment_count (abfd) * symesz; + raw_end = PTR_ADD (raw_src, obj_raw_syment_count (abfd) * symesz); /* FIXME SOMEDAY. A string table size of zero is very weird, but probably possible. If one shows up, it will probably kill us. */ @@ -1806,33 +1868,41 @@ coff_get_normalized_symtab (bfd *abfd) bfd_coff_swap_sym_in (abfd, (void *) raw_src, (void *) & internal_ptr->u.syment); symbol_ptr = internal_ptr; - internal_ptr->is_sym = TRUE; + internal_ptr->is_sym = true; + + /* PR 17512: Prevent buffer overrun. */ + if (symbol_ptr->u.syment.n_numaux > ((raw_end - 1) - raw_src) / symesz) + { + bfd_release (abfd, internal); + return NULL; + } for (i = 0; i < symbol_ptr->u.syment.n_numaux; i++) { internal_ptr++; - /* PR 17512: Prevent buffer overrun. */ - if (internal_ptr >= internal_end) - return NULL; - raw_src += symesz; + bfd_coff_swap_aux_in (abfd, (void *) raw_src, symbol_ptr->u.syment.n_type, symbol_ptr->u.syment.n_sclass, (int) i, symbol_ptr->u.syment.n_numaux, &(internal_ptr->u.auxent)); - internal_ptr->is_sym = FALSE; + + internal_ptr->is_sym = false; coff_pointerize_aux (abfd, internal, symbol_ptr, i, - internal_ptr); + internal_ptr, internal_end); } } - /* Free the raw symbols, but not the strings (if we have them). */ - obj_coff_keep_strings (abfd) = TRUE; - if (! _bfd_coff_free_symbols (abfd)) - return NULL; + /* Free the raw symbols. */ + if (obj_coff_external_syms (abfd) != NULL + && ! obj_coff_keep_syms (abfd)) + { + free (obj_coff_external_syms (abfd)); + obj_coff_external_syms (abfd) = NULL; + } for (internal_ptr = internal; internal_ptr < internal_end; internal_ptr++) @@ -1848,7 +1918,7 @@ coff_get_normalized_symtab (bfd *abfd) the text ".file" is redundant. */ BFD_ASSERT (! aux->is_sym); - if (aux->u.auxent.x_file.x_n.x_zeroes == 0) + if (aux->u.auxent.x_file.x_n.x_n.x_zeroes == 0) { /* The filename is a long one, point into the string table. */ if (string_table == NULL) @@ -1858,32 +1928,65 @@ coff_get_normalized_symtab (bfd *abfd) return NULL; } - if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_offset) + if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_n.x_offset) >= obj_coff_strings_len (abfd)) internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); else internal_ptr->u.syment._n._n_n._n_offset = - (bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_offset)); + (bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_n.x_offset)); } else { /* Ordinary short filename, put into memory anyway. The - Microsoft PE tools sometimes store a filename in - multiple AUX entries. */ + Microsoft PE tools sometimes store a filename in + multiple AUX entries. */ if (internal_ptr->u.syment.n_numaux > 1 && coff_data (abfd)->pe) internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) copy_name (abfd, - aux->u.auxent.x_file.x_fname, + aux->u.auxent.x_file.x_n.x_fname, internal_ptr->u.syment.n_numaux * symesz); else internal_ptr->u.syment._n._n_n._n_offset = ((bfd_hostptr_t) copy_name (abfd, - aux->u.auxent.x_file.x_fname, + aux->u.auxent.x_file.x_n.x_fname, (size_t) bfd_coff_filnmlen (abfd))); } + + /* Normalize other strings available in C_FILE aux entries. */ + if (!coff_data (abfd)->pe) + for (int numaux = 1; numaux < internal_ptr->u.syment.n_numaux; numaux++) + { + aux = internal_ptr + numaux + 1; + BFD_ASSERT (! aux->is_sym); + + if (aux->u.auxent.x_file.x_n.x_n.x_zeroes == 0) + { + /* The string information is a long one, point into the string table. */ + if (string_table == NULL) + { + string_table = _bfd_coff_read_string_table (abfd); + if (string_table == NULL) + return NULL; + } + + if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_n.x_offset) + >= obj_coff_strings_len (abfd)) + aux->u.auxent.x_file.x_n.x_n.x_offset = (bfd_hostptr_t) _(""); + else + aux->u.auxent.x_file.x_n.x_n.x_offset = + (bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_n.x_offset)); + } + else + aux->u.auxent.x_file.x_n.x_n.x_offset = + ((bfd_hostptr_t) + copy_name (abfd, + aux->u.auxent.x_file.x_n.x_fname, + (size_t) bfd_coff_filnmlen (abfd))); + } + } else { @@ -1894,7 +1997,7 @@ coff_get_normalized_symtab (bfd *abfd) char *newstring; /* Find the length of this string without walking into memory - that isn't ours. */ + that isn't ours. */ for (i = 0; i < 8; ++i) if (internal_ptr->u.syment._n._n_name[i] == '\0') break; @@ -1911,7 +2014,7 @@ coff_get_normalized_symtab (bfd *abfd) else if (!bfd_coff_symname_in_debug (abfd, &internal_ptr->u.syment)) { /* Long name already. Point symbol at the string in the - table. */ + table. */ if (string_table == NULL) { string_table = _bfd_coff_read_string_table (abfd); @@ -1965,13 +2068,20 @@ coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) bfd_set_error (bfd_error_invalid_operation); return -1; } - return (asect->reloc_count + 1) * sizeof (arelent *); +#if SIZEOF_LONG == SIZEOF_INT + if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } +#endif + return (asect->reloc_count + 1L) * sizeof (arelent *); } asymbol * coff_make_empty_symbol (bfd *abfd) { - bfd_size_type amt = sizeof (coff_symbol_type); + size_t amt = sizeof (coff_symbol_type); coff_symbol_type *new_symbol = (coff_symbol_type *) bfd_zalloc (abfd, amt); if (new_symbol == NULL) @@ -1979,7 +2089,7 @@ coff_make_empty_symbol (bfd *abfd) new_symbol->symbol.section = 0; new_symbol->native = NULL; new_symbol->lineno = NULL; - new_symbol->done_lineno = FALSE; + new_symbol->done_lineno = false; new_symbol->symbol.the_bfd = abfd; return & new_symbol->symbol; @@ -1992,7 +2102,7 @@ coff_bfd_make_debug_symbol (bfd *abfd, void * ptr ATTRIBUTE_UNUSED, unsigned long sz ATTRIBUTE_UNUSED) { - bfd_size_type amt = sizeof (coff_symbol_type); + size_t amt = sizeof (coff_symbol_type); coff_symbol_type *new_symbol = (coff_symbol_type *) bfd_alloc (abfd, amt); if (new_symbol == NULL) @@ -2003,11 +2113,11 @@ coff_bfd_make_debug_symbol (bfd *abfd, new_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt); if (!new_symbol->native) return NULL; - new_symbol->native->is_sym = TRUE; + new_symbol->native->is_sym = true; new_symbol->symbol.section = bfd_abs_section_ptr; new_symbol->symbol.flags = BSF_DEBUGGING; new_symbol->lineno = NULL; - new_symbol->done_lineno = FALSE; + new_symbol->done_lineno = false; new_symbol->symbol.the_bfd = abfd; return & new_symbol->symbol; @@ -2021,81 +2131,10 @@ coff_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret) if (coffsymbol (symbol)->native != NULL && coffsymbol (symbol)->native->fix_value && coffsymbol (symbol)->native->is_sym) - ret->value = coffsymbol (symbol)->native->u.syment.n_value - - (bfd_hostptr_t) obj_raw_syments (abfd); -} - -/* Return the COFF syment for a symbol. */ - -bfd_boolean -bfd_coff_get_syment (bfd *abfd, - asymbol *symbol, - struct internal_syment *psyment) -{ - coff_symbol_type *csym; - - csym = coff_symbol_from (abfd, symbol); - if (csym == NULL || csym->native == NULL - || ! csym->native->is_sym) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - *psyment = csym->native->u.syment; - - if (csym->native->fix_value) - psyment->n_value = psyment->n_value - - (bfd_hostptr_t) obj_raw_syments (abfd); - - /* FIXME: We should handle fix_line here. */ - - return TRUE; -} - -/* Return the COFF auxent for a symbol. */ - -bfd_boolean -bfd_coff_get_auxent (bfd *abfd, - asymbol *symbol, - int indx, - union internal_auxent *pauxent) -{ - coff_symbol_type *csym; - combined_entry_type *ent; - - csym = coff_symbol_from (abfd, symbol); - - if (csym == NULL - || csym->native == NULL - || ! csym->native->is_sym - || indx >= csym->native->u.syment.n_numaux) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - ent = csym->native + indx + 1; - - BFD_ASSERT (! ent->is_sym); - *pauxent = ent->u.auxent; - - if (ent->fix_tag) - pauxent->x_sym.x_tagndx.l = - ((combined_entry_type *) pauxent->x_sym.x_tagndx.p - - obj_raw_syments (abfd)); - - if (ent->fix_end) - pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l = - ((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p - - obj_raw_syments (abfd)); - - if (ent->fix_scnlen) - pauxent->x_csect.x_scnlen.l = - ((combined_entry_type *) pauxent->x_csect.x_scnlen.p - - obj_raw_syments (abfd)); - - return TRUE; + ret->value + = (((bfd_hostptr_t) coffsymbol (symbol)->native->u.syment.n_value + - (bfd_hostptr_t) obj_raw_syments (abfd)) + / sizeof (combined_entry_type)); } /* Print out information about COFF symbol. */ @@ -2143,9 +2182,11 @@ coff_print_symbol (bfd *abfd, if (! combined->fix_value) val = (bfd_vma) combined->u.syment.n_value; else - val = combined->u.syment.n_value - (bfd_hostptr_t) root; + val = (((bfd_hostptr_t) combined->u.syment.n_value + - (bfd_hostptr_t) root) + / sizeof (combined_entry_type)); - fprintf (file, "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x", + fprintf (file, "(sec %2d)(fl 0x%02x)(ty %4x)(scl %3d) (nx %d) 0x", combined->u.syment.n_scnum, combined->u.syment.n_flags, combined->u.syment.n_type, @@ -2174,6 +2215,18 @@ coff_print_symbol (bfd *abfd, { case C_FILE: fprintf (file, "File "); + /* Add additional information if this isn't the filename + auxiliary entry. */ + if (auxp->u.auxent.x_file.x_ftype) + fprintf (file, "ftype %d fname \"%s\"", + auxp->u.auxent.x_file.x_ftype, + (char *) auxp->u.auxent.x_file.x_n.x_n.x_offset); + break; + + case C_DWARF: + fprintf (file, "AUX scnlen 0x%lx nreloc %ld", + (unsigned long) auxp->u.auxent.x_sect.x_scnlen, + auxp->u.auxent.x_sect.x_nreloc); break; case C_STAT: @@ -2193,7 +2246,7 @@ coff_print_symbol (bfd *abfd, auxp->u.auxent.x_scn.x_comdat); break; } - /* Otherwise fall through. */ + /* Fall through. */ case C_EXT: case C_AIX_WEAKEXT: if (ISFCN (combined->u.syment.n_type)) @@ -2213,7 +2266,7 @@ coff_print_symbol (bfd *abfd, llnos, next); break; } - /* Otherwise fall through. */ + /* Fall through. */ default: fprintf (file, "AUX lnno %d size 0x%x tagndx %ld", auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno, @@ -2260,7 +2313,7 @@ coff_print_symbol (bfd *abfd, function for the is_local_label_name entry point, but some may override it. */ -bfd_boolean +bool _bfd_coff_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) { @@ -2271,17 +2324,17 @@ _bfd_coff_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, section, calculate and return the name of the source file and the line nearest to the wanted location. */ -bfd_boolean +bool coff_find_nearest_line_with_names (bfd *abfd, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - const struct dwarf_debug_section *debug_sections) + asymbol **symbols, + asection *section, + bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr, + const struct dwarf_debug_section *debug_sections) { - bfd_boolean found; + bool found; unsigned int i; unsigned int line_base; coff_data_type *cof = coff_data (abfd); @@ -2290,7 +2343,7 @@ coff_find_nearest_line_with_names (bfd *abfd, combined_entry_type *pend; alent *l; struct coff_section_tdata *sec_data; - bfd_size_type amt; + size_t amt; /* Before looking through the symbol table, try to use a .stab section to find the information. */ @@ -2298,17 +2351,58 @@ coff_find_nearest_line_with_names (bfd *abfd, &found, filename_ptr, functionname_ptr, line_ptr, &coff_data(abfd)->line_info)) - return FALSE; + return false; if (found) - return TRUE; + return true; /* Also try examining DWARF2 debugging information. */ if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, filename_ptr, functionname_ptr, - line_ptr, NULL, debug_sections, 0, + line_ptr, NULL, debug_sections, &coff_data(abfd)->dwarf2_find_line_info)) - return TRUE; + return true; + + sec_data = coff_section_data (abfd, section); + + /* If the DWARF lookup failed, but there is DWARF information available + then the problem might be that the file has been rebased. This tool + changes the VMAs of all the sections, but it does not update the DWARF + information. So try again, using a bias against the address sought. */ + if (coff_data (abfd)->dwarf2_find_line_info != NULL) + { + bfd_signed_vma bias = 0; + + /* Create a cache of the result for the next call. */ + if (sec_data == NULL && section->owner == abfd) + { + amt = sizeof (struct coff_section_tdata); + section->used_by_bfd = bfd_zalloc (abfd, amt); + sec_data = (struct coff_section_tdata *) section->used_by_bfd; + } + + if (sec_data != NULL && sec_data->saved_bias) + bias = sec_data->saved_bias; + else if (symbols) + { + bias = _bfd_dwarf2_find_symbol_bias (symbols, + & coff_data (abfd)->dwarf2_find_line_info); + + if (sec_data) + { + sec_data->saved_bias = true; + sec_data->bias = bias; + } + } + + if (bias + && _bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, + offset + bias, + filename_ptr, functionname_ptr, + line_ptr, NULL, debug_sections, + &coff_data(abfd)->dwarf2_find_line_info)) + return true; + } *filename_ptr = 0; *functionname_ptr = 0; @@ -2316,15 +2410,15 @@ coff_find_nearest_line_with_names (bfd *abfd, /* Don't try and find line numbers in a non coff file. */ if (!bfd_family_coff (abfd)) - return FALSE; + return false; if (cof == NULL) - return FALSE; + return false; /* Find the first C_FILE symbol. */ p = cof->raw_syments; if (!p) - return FALSE; + return false; pend = p + cof->raw_syment_count; while (p < pend) @@ -2341,7 +2435,7 @@ coff_find_nearest_line_with_names (bfd *abfd, bfd_vma maxdiff; /* Look through the C_FILE symbols to find the best one. */ - sec_vma = bfd_get_section_vma (abfd, section); + sec_vma = bfd_section_vma (section); *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; maxdiff = (bfd_vma) 0 - (bfd_vma) 1; while (1) @@ -2374,7 +2468,7 @@ coff_find_nearest_line_with_names (bfd *abfd, file_addr += coff_section_from_bfd_index (abfd, p2->u.syment.n_scnum)->vma; /* We use <= MAXDIFF here so that if we get a zero length - file, we actually use the next file entry. */ + file, we actually use the next file entry. */ if (p2 < pend && offset + sec_vma >= file_addr && offset + sec_vma - file_addr <= maxdiff) @@ -2383,21 +2477,30 @@ coff_find_nearest_line_with_names (bfd *abfd, maxdiff = offset + sec_vma - p2->u.syment.n_value; } + if (p->u.syment.n_value >= cof->raw_syment_count) + break; + /* Avoid endless loops on erroneous files by ensuring that we always move forward in the file. */ if (p >= cof->raw_syments + p->u.syment.n_value) break; p = cof->raw_syments + p->u.syment.n_value; - if (p > pend || p->u.syment.n_sclass != C_FILE) + if (!p->is_sym || p->u.syment.n_sclass != C_FILE) break; } } - /* Now wander though the raw linenumbers of the section. */ - /* If we have been called on this section before, and the offset we - want is further down then we can prime the lookup loop. */ - sec_data = coff_section_data (abfd, section); + if (section->lineno_count == 0) + { + *functionname_ptr = NULL; + *line_ptr = 0; + return true; + } + + /* Now wander though the raw linenumbers of the section. + If we have been called on this section before, and the offset + we want is further down then we can prime the lookup loop. */ if (sec_data != NULL && sec_data->i > 0 && offset >= sec_data->offset) @@ -2426,6 +2529,7 @@ coff_find_nearest_line_with_names (bfd *abfd, coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); if (coff->symbol.value > offset) break; + *functionname_ptr = coff->symbol.name; last_value = coff->symbol.value; if (coff->native) @@ -2437,11 +2541,15 @@ coff_find_nearest_line_with_names (bfd *abfd, /* In XCOFF a debugging symbol can follow the function symbol. */ - if (s->u.syment.n_scnum == N_DEBUG) + if (((size_t) ((char *) s - (char *) obj_raw_syments (abfd)) + < obj_raw_syment_count (abfd) * sizeof (*s)) + && s->u.syment.n_scnum == N_DEBUG) s = s + 1 + s->u.syment.n_numaux; /* S should now point to the .bf of the function. */ - if (s->u.syment.n_numaux) + if (((size_t) ((char *) s - (char *) obj_raw_syments (abfd)) + < obj_raw_syment_count (abfd) * sizeof (*s)) + && s->u.syment.n_numaux) { /* The linenumber is stored in the auxent. */ union internal_auxent *a = &((s + 1)->u.auxent); @@ -2482,6 +2590,7 @@ coff_find_nearest_line_with_names (bfd *abfd, section->used_by_bfd = bfd_zalloc (abfd, amt); sec_data = (struct coff_section_tdata *) section->used_by_bfd; } + if (sec_data != NULL) { sec_data->offset = offset; @@ -2490,10 +2599,10 @@ coff_find_nearest_line_with_names (bfd *abfd, sec_data->line_base = line_base; } - return TRUE; + return true; } -bfd_boolean +bool coff_find_nearest_line (bfd *abfd, asymbol **symbols, asection *section, @@ -2506,17 +2615,17 @@ coff_find_nearest_line (bfd *abfd, if (discriminator_ptr) *discriminator_ptr = 0; return coff_find_nearest_line_with_names (abfd, symbols, section, offset, - filename_ptr, functionname_ptr, - line_ptr, dwarf_debug_sections); + filename_ptr, functionname_ptr, + line_ptr, dwarf_debug_sections); } -bfd_boolean +bool coff_find_inliner_info (bfd *abfd, const char **filename_ptr, const char **functionname_ptr, unsigned int *line_ptr) { - bfd_boolean found; + bool found; found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, functionname_ptr, line_ptr, @@ -2529,7 +2638,7 @@ coff_sizeof_headers (bfd *abfd, struct bfd_link_info *info) { size_t size; - if (!info->relocatable) + if (!bfd_link_relocatable (info)) size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); else size = bfd_coff_filhsz (abfd); @@ -2540,18 +2649,18 @@ coff_sizeof_headers (bfd *abfd, struct bfd_link_info *info) /* Change the class of a coff symbol held by BFD. */ -bfd_boolean -bfd_coff_set_symbol_class (bfd * abfd, - asymbol * symbol, - unsigned int symbol_class) +bool +bfd_coff_set_symbol_class (bfd * abfd, + asymbol * symbol, + unsigned int symbol_class) { coff_symbol_type * csym; - csym = coff_symbol_from (abfd, symbol); + csym = coff_symbol_from (symbol); if (csym == NULL) { bfd_set_error (bfd_error_invalid_operation); - return FALSE; + return false; } else if (csym->native == NULL) { @@ -2561,13 +2670,13 @@ bfd_coff_set_symbol_class (bfd * abfd, coff_write_alien_symbol(). */ combined_entry_type * native; - bfd_size_type amt = sizeof (* native); + size_t amt = sizeof (* native); native = (combined_entry_type *) bfd_zalloc (abfd, amt); if (native == NULL) - return FALSE; + return false; - native->is_sym = TRUE; + native->is_sym = true; native->u.syment.n_type = T_NULL; native->u.syment.n_sclass = symbol_class; @@ -2600,20 +2709,10 @@ bfd_coff_set_symbol_class (bfd * abfd, else csym->native->u.syment.n_sclass = symbol_class; - return TRUE; + return true; } -struct coff_comdat_info * -bfd_coff_get_comdat_section (bfd *abfd, struct bfd_section *sec) -{ - if (bfd_get_flavour (abfd) == bfd_target_coff_flavour - && coff_section_data (abfd, sec) != NULL) - return coff_section_data (abfd, sec)->comdat; - else - return NULL; -} - -bfd_boolean +bool _bfd_coff_section_already_linked (bfd *abfd, asection *sec, struct bfd_link_info *info) @@ -2624,22 +2723,25 @@ _bfd_coff_section_already_linked (bfd *abfd, struct bfd_section_already_linked_hash_entry *already_linked_list; struct coff_comdat_info *s_comdat; + if (sec->output_section == bfd_abs_section_ptr) + return false; + flags = sec->flags; if ((flags & SEC_LINK_ONCE) == 0) - return FALSE; + return false; /* The COFF backend linker doesn't support group sections. */ if ((flags & SEC_GROUP) != 0) - return FALSE; + return false; - name = bfd_get_section_name (abfd, sec); + name = bfd_section_name (sec); s_comdat = bfd_coff_get_comdat_section (abfd, sec); if (s_comdat != NULL) key = s_comdat->name; else { - if (CONST_STRNEQ (name, ".gnu.linkonce.") + if (startswith (name, ".gnu.linkonce.") && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) key++; else @@ -2666,7 +2768,8 @@ _bfd_coff_section_already_linked (bfd *abfd, .gnu.linkonce.*.. */ if (((s_comdat != NULL) == (l_comdat != NULL) && strcmp (name, l->sec->name) == 0) - || (l->sec->owner->flags & BFD_PLUGIN) != 0) + || (l->sec->owner->flags & BFD_PLUGIN) != 0 + || (sec->owner->flags & BFD_PLUGIN) != 0) { /* The section has already been linked. See if we should issue a warning. */ @@ -2677,5 +2780,490 @@ _bfd_coff_section_already_linked (bfd *abfd, /* This is the first section with this name. Record it. */ if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); - return FALSE; + return false; +} + +/* Initialize COOKIE for input bfd ABFD. */ + +static bool +init_reloc_cookie (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + bfd *abfd) +{ + /* Sometimes the symbol table does not yet have been loaded here. */ + bfd_coff_slurp_symbol_table (abfd); + + cookie->abfd = abfd; + cookie->sym_hashes = obj_coff_sym_hashes (abfd); + + cookie->symbols = obj_symbols (abfd); + + return true; +} + +/* Free the memory allocated by init_reloc_cookie, if appropriate. */ + +static void +fini_reloc_cookie (struct coff_reloc_cookie *cookie ATTRIBUTE_UNUSED, + bfd *abfd ATTRIBUTE_UNUSED) +{ + /* Nothing to do. */ +} + +/* Initialize the relocation information in COOKIE for input section SEC + of input bfd ABFD. */ + +static bool +init_reloc_cookie_rels (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + bfd *abfd, + asection *sec) +{ + if (sec->reloc_count == 0) + { + cookie->rels = NULL; + cookie->relend = NULL; + cookie->rel = NULL; + return true; + } + + cookie->rels = _bfd_coff_read_internal_relocs (abfd, sec, false, NULL, + 0, NULL); + + if (cookie->rels == NULL) + return false; + + cookie->rel = cookie->rels; + cookie->relend = (cookie->rels + sec->reloc_count); + return true; +} + +/* Free the memory allocated by init_reloc_cookie_rels, + if appropriate. */ + +static void +fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie, + asection *sec) +{ + if (cookie->rels + /* PR 20401. The relocs may not have been cached, so check first. + If the relocs were loaded by init_reloc_cookie_rels() then this + will be the case. FIXME: Would performance be improved if the + relocs *were* cached ? */ + && coff_section_data (NULL, sec) + && coff_section_data (NULL, sec)->relocs != cookie->rels) + free (cookie->rels); +} + +/* Initialize the whole of COOKIE for input section SEC. */ + +static bool +init_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info, + asection *sec) +{ + if (!init_reloc_cookie (cookie, info, sec->owner)) + return false; + + if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) + { + fini_reloc_cookie (cookie, sec->owner); + return false; + } + return true; +} + +/* Free the memory allocated by init_reloc_cookie_for_section, + if appropriate. */ + +static void +fini_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, + asection *sec) +{ + fini_reloc_cookie_rels (cookie, sec); + fini_reloc_cookie (cookie, sec->owner); +} + +static asection * +_bfd_coff_gc_mark_hook (asection *sec, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct internal_reloc *rel ATTRIBUTE_UNUSED, + struct coff_link_hash_entry *h, + struct internal_syment *sym) +{ + if (h != NULL) + { + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; + + case bfd_link_hash_common: + return h->root.u.c.p->section; + + case bfd_link_hash_undefweak: + if (h->symbol_class == C_NT_WEAK && h->numaux == 1) + { + /* PE weak externals. A weak symbol may include an auxiliary + record indicating that if the weak symbol is not resolved, + another external symbol is used instead. */ + struct coff_link_hash_entry *h2 = + h->auxbfd->tdata.coff_obj_data->sym_hashes[ + h->aux->x_sym.x_tagndx.l]; + + if (h2 && h2->root.type != bfd_link_hash_undefined) + return h2->root.u.def.section; + } + break; + + case bfd_link_hash_undefined: + default: + break; + } + return NULL; + } + + return coff_section_from_bfd_index (sec->owner, sym->n_scnum); +} + +/* COOKIE->rel describes a relocation against section SEC, which is + a section we've decided to keep. Return the section that contains + the relocation symbol, or NULL if no section contains it. */ + +static asection * +_bfd_coff_gc_mark_rsec (struct bfd_link_info *info, asection *sec, + coff_gc_mark_hook_fn gc_mark_hook, + struct coff_reloc_cookie *cookie) +{ + struct coff_link_hash_entry *h; + + h = cookie->sym_hashes[cookie->rel->r_symndx]; + if (h != NULL) + { + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct coff_link_hash_entry *) h->root.u.i.link; + + return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); + } + + return (*gc_mark_hook) (sec, info, cookie->rel, NULL, + &(cookie->symbols + + obj_convert (sec->owner)[cookie->rel->r_symndx])->native->u.syment); +} + +static bool _bfd_coff_gc_mark + (struct bfd_link_info *, asection *, coff_gc_mark_hook_fn); + +/* COOKIE->rel describes a relocation against section SEC, which is + a section we've decided to keep. Mark the section that contains + the relocation symbol. */ + +static bool +_bfd_coff_gc_mark_reloc (struct bfd_link_info *info, + asection *sec, + coff_gc_mark_hook_fn gc_mark_hook, + struct coff_reloc_cookie *cookie) +{ + asection *rsec; + + rsec = _bfd_coff_gc_mark_rsec (info, sec, gc_mark_hook, cookie); + if (rsec && !rsec->gc_mark) + { + if (bfd_get_flavour (rsec->owner) != bfd_target_coff_flavour) + rsec->gc_mark = 1; + else if (!_bfd_coff_gc_mark (info, rsec, gc_mark_hook)) + return false; + } + return true; +} + +/* The mark phase of garbage collection. For a given section, mark + it and any sections in this section's group, and all the sections + which define symbols to which it refers. */ + +static bool +_bfd_coff_gc_mark (struct bfd_link_info *info, + asection *sec, + coff_gc_mark_hook_fn gc_mark_hook) +{ + bool ret = true; + + sec->gc_mark = 1; + + /* Look through the section relocs. */ + if ((sec->flags & SEC_RELOC) != 0 + && sec->reloc_count > 0) + { + struct coff_reloc_cookie cookie; + + if (!init_reloc_cookie_for_section (&cookie, info, sec)) + ret = false; + else + { + for (; cookie.rel < cookie.relend; cookie.rel++) + { + if (!_bfd_coff_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) + { + ret = false; + break; + } + } + fini_reloc_cookie_for_section (&cookie, sec); + } + } + + return ret; +} + +static bool +_bfd_coff_gc_mark_extra_sections (struct bfd_link_info *info, + coff_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED) +{ + bfd *ibfd; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + asection *isec; + bool some_kept; + + if (bfd_get_flavour (ibfd) != bfd_target_coff_flavour) + continue; + + /* Ensure all linker created sections are kept, and see whether + any other section is already marked. */ + some_kept = false; + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + { + if ((isec->flags & SEC_LINKER_CREATED) != 0) + isec->gc_mark = 1; + else if (isec->gc_mark) + some_kept = true; + } + + /* If no section in this file will be kept, then we can + toss out debug sections. */ + if (!some_kept) + continue; + + /* Keep debug and special sections like .comment when they are + not part of a group, or when we have single-member groups. */ + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + if ((isec->flags & SEC_DEBUGGING) != 0 + || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + isec->gc_mark = 1; + } + return true; +} + +/* Sweep symbols in swept sections. Called via coff_link_hash_traverse. */ + +static bool +coff_gc_sweep_symbol (struct coff_link_hash_entry *h, + void *data ATTRIBUTE_UNUSED) +{ + if (h->root.type == bfd_link_hash_warning) + h = (struct coff_link_hash_entry *) h->root.u.i.link; + + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && !h->root.u.def.section->gc_mark + && !(h->root.u.def.section->owner->flags & DYNAMIC)) + { + /* Do our best to hide the symbol. */ + h->root.u.def.section = bfd_und_section_ptr; + h->symbol_class = C_HIDDEN; + } + + return true; +} + +/* The sweep phase of garbage collection. Remove all garbage sections. */ + +typedef bool (*gc_sweep_hook_fn) + (bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); + +static bool +coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + bfd *sub; + + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_coff_flavour) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + { + /* Keep debug and special sections. */ + if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0 + || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + o->gc_mark = 1; + else if (startswith (o->name, ".idata") + || startswith (o->name, ".pdata") + || startswith (o->name, ".xdata") + || startswith (o->name, ".rsrc")) + o->gc_mark = 1; + + if (o->gc_mark) + continue; + + /* Skip sweeping sections already excluded. */ + if (o->flags & SEC_EXCLUDE) + continue; + + /* Since this is early in the link process, it is simple + to remove a section from the output. */ + o->flags |= SEC_EXCLUDE; + + if (info->print_gc_sections && o->size != 0) + /* xgettext: c-format */ + _bfd_error_handler (_("removing unused section '%pA' in file '%pB'"), + o, sub); + +#if 0 + /* But we also have to update some of the relocation + info we collected before. */ + if (gc_sweep_hook + && (o->flags & SEC_RELOC) != 0 + && o->reloc_count > 0 + && !bfd_is_abs_section (o->output_section)) + { + struct internal_reloc *internal_relocs; + bool r; + + internal_relocs + = _bfd_coff_link_read_relocs (o->owner, o, NULL, NULL, + info->keep_memory); + if (internal_relocs == NULL) + return false; + + r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs); + + if (coff_section_data (o)->relocs != internal_relocs) + free (internal_relocs); + + if (!r) + return false; + } +#endif + } + } + + /* Remove the symbols that were in the swept sections from the dynamic + symbol table. */ + coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol, + NULL); + + return true; +} + +/* Keep all sections containing symbols undefined on the command-line, + and the section containing the entry symbol. */ + +static void +_bfd_coff_gc_keep (struct bfd_link_info *info) +{ + struct bfd_sym_chain *sym; + + for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) + { + struct coff_link_hash_entry *h; + + h = coff_link_hash_lookup (coff_hash_table (info), sym->name, + false, false, false); + + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && !bfd_is_abs_section (h->root.u.def.section)) + h->root.u.def.section->flags |= SEC_KEEP; + } +} + +/* Do mark and sweep of unused sections. */ + +bool +bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + bfd *sub; + + /* FIXME: Should we implement this? */ +#if 0 + const bfd_coff_backend_data *bed = coff_backend_info (abfd); + + if (!bed->can_gc_sections + || !is_coff_hash_table (info->hash)) + { + _bfd_error_handler(_("warning: gc-sections option ignored")); + return true; + } +#endif + + _bfd_coff_gc_keep (info); + + /* Grovel through relocs to find out who stays ... */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_coff_flavour) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + { + if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP + || startswith (o->name, ".vectors") + || startswith (o->name, ".ctors") + || startswith (o->name, ".dtors")) + && !o->gc_mark) + { + if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook)) + return false; + } + } + } + + /* Allow the backend to mark additional target specific sections. */ + _bfd_coff_gc_mark_extra_sections (info, _bfd_coff_gc_mark_hook); + + /* ... and mark SEC_EXCLUDE for those that go. */ + return coff_gc_sweep (abfd, info); +} + +/* Return name used to identify a comdat group. */ + +const char * +bfd_coff_group_name (bfd *abfd, const asection *sec) +{ + struct coff_comdat_info *ci = bfd_coff_get_comdat_section (abfd, sec); + if (ci != NULL) + return ci->name; + return NULL; +} + +bool +_bfd_coff_close_and_cleanup (bfd *abfd) +{ + struct coff_tdata *tdata = coff_data (abfd); + + if (tdata != NULL) + { + /* PR 25447: + Do not clear the keep_syms and keep_strings flags. + These may have been set by pe_ILF_build_a_bfd() indicating + that the syms and strings pointers are not to be freed. */ + if (bfd_get_format (abfd) == bfd_object + && bfd_family_coff (abfd) + && !_bfd_coff_free_symbols (abfd)) + return false; + + if (bfd_get_format (abfd) == bfd_object + || bfd_get_format (abfd) == bfd_core) + _bfd_dwarf2_cleanup_debug_info (abfd, &tdata->dwarf2_find_line_info); + } + return _bfd_generic_close_and_cleanup (abfd); }