--- binutils-2.20/bfd/coffcode.h 2009-09-10 13:47:12.000000000 +0200 +++ binutils-2.20/bfd/coffcode.h 2011-03-11 12:39:35.801109247 +0100 @@ -5597,7 +5597,7 @@ #endif #ifndef coff_bfd_gc_sections -#define coff_bfd_gc_sections bfd_generic_gc_sections +#define coff_bfd_gc_sections bfd_coff_gc_sections #endif #ifndef coff_bfd_merge_sections --- binutils-2.20/bfd/cofflink.c 2009-10-06 12:57:53.000000000 +0200 +++ binutils-2.20/bfd/cofflink.c 2011-03-11 13:33:25.393108669 +0100 @@ -3056,3 +3056,451 @@ } return TRUE; } + +/* Initialize COOKIE for input bfd ABFD. */ + +static bfd_boolean +init_reloc_cookie (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd) +{ + const bfd_coff_backend_data *bed; + + bed = coff_backend_info (abfd); + + cookie->abfd = abfd; + cookie->sym_hashes = obj_coff_sym_hashes (abfd); + + /* FIXME: Sometimes the symbol table does not yet have been loaded here; + is this the correct way to handle it? */ + bfd_coff_slurp_symbol_table(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) +{ + /* FIXME: Nothing to do for the COFF case it seems? */ +#if 0 + coff_Internal_Shdr *symtab_hdr; + + symtab_hdr = &coff_tdata (abfd)->symtab_hdr; + if (cookie->locsyms != NULL + && symtab_hdr->contents != (unsigned char *) cookie->locsyms) + free (cookie->locsyms); +#endif +} + + +/* Initialize the relocation information in COOKIE for input section SEC + of input bfd ABFD. */ + +static bfd_boolean +init_reloc_cookie_rels (struct coff_reloc_cookie *cookie, + struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd, + asection *sec) +{ + const bfd_coff_backend_data *bed; + + if (sec->reloc_count == 0) + { + cookie->rels = NULL; + cookie->relend = NULL; + } + else + { + bed = coff_backend_info (abfd); + 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); + } + cookie->rel = cookie->rels; + 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 && coff_section_data (NULL, sec)->relocs != cookie->rels) + free (cookie->rels); +} + +/* Initialize the whole of COOKIE for input section SEC. */ + +static bfd_boolean +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)) + goto error1; + if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) + goto error2; + return TRUE; + + error2: + fini_reloc_cookie (cookie, sec->owner); + error1: + return FALSE; +} + +/* 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; + + default: + break; + } + } + else + return coff_section_from_bfd_index (sec->owner, sym->n_scnum); + /* FIXME: is the above corrent? elflink.c has: + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); */ + + return NULL; +} + +/* 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 +bfd_boolean +_bfd_coff_gc_mark (struct bfd_link_info *info, + asection *sec, + coff_gc_mark_hook_fn gc_mark_hook); + +/* 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 bfd_boolean +_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 +bfd_boolean +_bfd_coff_gc_mark (struct bfd_link_info *info, + asection *sec, + coff_gc_mark_hook_fn gc_mark_hook) +{ + bfd_boolean ret; + + sec->gc_mark = 1; + + /* FIXME: elflink.c has "Mark all the sections in the group." + functionality here - does COFF require something similar? */ + + /* FIXME: elflink.c has some eh_frame handling here - does COFF + require something similar? */ + + /* Look through the section relocs. */ + ret = TRUE; + 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); + } + + } + + /* FIXME: elflink.c has some eh_frame handling here - does COFF + require something similar? */ + + return ret; +} + +/* Sweep symbols in swept sections. Called via coff_link_hash_traverse. */ + +struct coff_gc_sweep_symbol_info +{ + struct bfd_link_info *info; + void (*hide_symbol) (struct bfd_link_info *, struct coff_link_hash_entry *, + bfd_boolean); +}; + +static bfd_boolean +coff_gc_sweep_symbol (struct coff_link_hash_entry *h, void *data) +{ + + 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)) + { + struct coff_gc_sweep_symbol_info *inf ATTRIBUTE_UNUSED = + (struct coff_gc_sweep_symbol_info *) data; + /* FIXME: elflink.c hides the symbol here - how can we do this for COFF? + (*inf->hide_symbol) (inf->info, h, TRUE); */ + } + + return TRUE; +} + +/* The sweep phase of garbage collection. Remove all garbage sections. */ + +typedef bfd_boolean (*gc_sweep_hook_fn) + (bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); + +static bfd_boolean +coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) +{ + bfd *sub; + struct coff_gc_sweep_symbol_info sweep_info; + + 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) + { + + /* FIXME: We must preserve the import table, but is this the correct + way to do it? */ + if (strncmp(o->name, ".idata", 6) == 0) + o->gc_mark = 1; + + /* FIXME: elflink.c has some section group + functionality here - does COFF require something similar? */ + + if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0 + || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + { + /* Keep debug and special sections. */ + 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) + _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name); + + /* FIXME: Do we need something like this for COFF? */ +#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; + bfd_boolean 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. GCFIXME: Anyone know how to get them out of the + static symbol table as well? */ + + sweep_info.info = info; + /* FIXME: Do we need this for COFF? + sweep_info.hide_symbol = bed->coff_backend_hide_symbol; */ + coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol, + &sweep_info); + + /* FIXME: Do we need this for COFF? + _bfd_coff_link_renumber_dynsyms (abfd, info, §ion_sym_count); */ + + 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 + /* FIXME: elflink.c has more conditions - what about COFF? + && (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. */ + +bfd_boolean +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); + + /* FIXME: elflink.c has some eh_frame handling here - does COFF + require something similar? */ + + /* FIXME: elflink.c does two things here: + - Apply transitive closure to the vtable entry usage info. + - Kill the vtable relocations that were not used. + does COFF require something similar? */ + + /* FIXME: elflink.c does a traverse with bfd_elf_gc_mark_dynamic_ref_symbol + here - does COFF require something similar? */ + + /* 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) { + /* FIXME: Is this the proper way to check for global constructors? */ + if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP || strncmp(o->name, ".ctors", 6) == 0) && !o->gc_mark) { + if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook)) { + return FALSE; + } + } + } + } + + /* FIXME: elflink.c has an hook for gc_mark_extra_sections + here - does COFF require something similar? */ + + /* ... and mark SEC_EXCLUDE for those that go. */ + return coff_gc_sweep (abfd, info); +} + --- binutils-2.20/bfd/libcoff.h 2009-09-07 10:15:19.000000000 +0200 +++ binutils-2.20/bfd/libcoff.h 2011-03-11 12:44:53.233609622 +0100 @@ -284,6 +284,14 @@ struct stab_info stab_info; }; +struct coff_reloc_cookie +{ + struct internal_reloc *rels, *rel, *relend; + struct coff_symbol_struct *symbols; /* Symtab for input bfd. */ + bfd *abfd; + struct coff_link_hash_entry **sym_hashes; +}; + /* Look up an entry in a COFF linker hash table. */ #define coff_link_hash_lookup(table, string, create, copy, follow) \ @@ -560,6 +568,8 @@ extern bfd_boolean _bfd_coff_generic_relocate_section (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, struct internal_reloc *, struct internal_syment *, asection **); +extern bfd_boolean bfd_coff_gc_sections + (bfd *abfd, struct bfd_link_info *info); extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); extern bfd_boolean _bfd_coff_write_global_sym @@ -676,6 +686,10 @@ COFF_SYMBOL_PE_SECTION }; +typedef asection * (*coff_gc_mark_hook_fn) + (asection *, struct bfd_link_info *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *); + typedef struct { void (*_bfd_coff_swap_aux_in)