ELF Section-level Garbage Collection.
authorRichard Henderson <rth@redhat.com>
Tue, 30 Jun 1998 10:02:22 +0000 (10:02 +0000)
committerRichard Henderson <rth@redhat.com>
Tue, 30 Jun 1998 10:02:22 +0000 (10:02 +0000)
14 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/coffcode.h
bfd/elf-m10300.c
bfd/elf.c
bfd/elf32-m68k.c
bfd/elf32-mips.c
bfd/elflink.h
bfd/evax-alpha.c
bfd/ieee.c
bfd/libbfd.h
bfd/reloc.c
bfd/section.c
bfd/targets.c

index 02ff947..814b34f 100644 (file)
@@ -1,3 +1,69 @@
+Thu Jun 25 18:31:41 1998  Richard Henderson  <rth@cygnus.com>
+
+       ELF Section-level Garbage Collection:
+       * bfd.c (bfd_gc_sections): New.
+       * aout-adobe.c: Hook to default implementation.
+       * aout-target.h, aout-tic30.c, binary.c, bout.c: Likewise.
+       * coff-alpha.c, coff-mips.c, coff-rs6000.c, coffcode.h: Likewise.
+       * evax-alpha.c, i386msdos.c, i386os9k.c, ieee.c: Likewise.
+       * ihex.c, nlm-target.h, oasys.c, ppcboot.c, srec.c: Likewise.
+       * tekhex.c, versados.c: Likewise.
+       * libbfd-in.h (_bfd_nolink_bfd_gc_sections): New.
+       * targets.c (BFD_JUMP_TABLE_LINK): Add _bfd_gc_sections.
+
+       * reloc.c (BFD_RELOC_VTABLE_INHERIT, BFD_RELOC_VTABLE_ENTRY): New.
+       (bfd_generic_gc_sections): New.
+       * section.c (SEC_KEEP): New.
+       (asection): Add gc_mark member.
+
+       * elfcode.h (elf_gc*): New name remappings.
+       * elflink.h (elf_link_input_bfd): Don't set contents on stabs
+       sections to be excluded.
+       (elf_gc_mark, elf_gc_sweep, elf_gc_sweep_symbol): New.
+       (elf_gc_propogate_vtable_entries_used): New.
+       (elf_gc_smash_unused_vtentry_relocs): New.
+       (elf_gc_sections, elf_gc_record_vtinherit, elf_gc_record_vtentry): New.
+       (elf_gc_common_finalize_got_offsets): New.
+       (elf_gc_allocate_got_offsets, elf_gc_common_final_link): New.
+       * elfxx-target.h: Add and default gc hooks.
+
+       * elf-bfd.h (struct elf_link_hash_entry): Swap got_offset/plt_offset
+       for unions. 
+       (struct elf_obj_tdata): Likewise for local_got_offsets.
+       * elf.c, elf-i386.c, elf32-m68k.c, elf32-mips.c: Update all uses.
+       * elf32-ppc.c, elf32-sparc.c, elf64-alpha.c: Likewise.
+       * elf64-sparc.c, elflink.h: Likewise.
+
+       * elf-bfd.h (struct elf_link_hash_entry): Add vtable members.
+       (ELF_LINK_HASH_MARK): Define.
+       (struct elf_backend_data): Add GC hooks.
+       * elf.c (_bfd_elf_link_hash_newfunc): Zero vtable members.
+
+       * elf-m10300.c (mn10300_elf_check_relocs): New.
+       (mn10300_elf_gc_mark_hook): New.
+       (R_MN10300_GNU_VTINHERIT, R_MN10300_GNU_VTENTRY): New.
+       (elf_mn10300_howto, mn10300_reloc_map): Handle them.
+       (mn10300_elf_final_link_relocate): Likewise.
+       (mn10300_elf_relocate_section): Likewise.
+       (elf_backend_can_gc_sections): Define.
+       * elf32-mips.c (R_MIPS_GNU_VTINHERIT, R_MIPS_GNU_VTENTRY): New.
+       (elf_mips_gnu_vtinherit_howto, elf_mips_gnu_vtentry_howto): New.
+       (bfd_elf32_bfd_reloc_type_lookup): Handle them.
+       (mips_info_to_howto_rel): Likewise.
+       (mips_elf_relocate_section): Likewise.
+       (mips_elf_check_relocs): Likewise.
+       (mips_elf_gc_mark_hook, mips_elf_gc_sweep_hook): New.
+       (elf_backend_can_gc_sections): Define.
+       * elf32-ppc.c (R_PPC_GNU_VTINHERIT, R_PPC_GNU_VTENTRY): New.
+       (ppc_elf_howto_raw): Handle them.
+       (ppc_elf_reloc_type_lookup): Likewise.
+       (ppc_elf_relocate_section): Likewise.
+       (ppc_elf_check_relocs): Reference count .got and .plt entires.
+       Handle new vtable relocs.
+       (ppc_elf_adjust_dynamic_symbol): Recognize unused .plt entries.
+       (ppc_elf_gc_mark_hook, ppc_elf_gc_sweep_hook): New.
+       (elf_backend_can_gc_sections): Define.
+
 Fri Jun 26 10:48:23 1998  Jeffrey A Law  (law@cygnus.com)
 
        * archures.c (bfd_mach_mn10300): Define.
index 2af3b74..96fab37 100644 (file)
@@ -965,6 +965,9 @@ typedef struct sec
           else up the line will take care of it later.  */
 #define SEC_LINKER_CREATED 0x800000
 
+        /* This section should not be subject to garbage collection.  */
+#define SEC_KEEP 0x1000000
+
         /*  End of section flags.  */
 
         /* Some internal packed boolean fields.  */
@@ -978,6 +981,9 @@ typedef struct sec
         /* A mark flag used by some of the linker backends.  */
        unsigned int linker_mark : 1;
 
+        /* A mark flag used by some linker backends for garbage collection.  */
+       unsigned int gc_mark : 1;
+
         /* End of internal packed boolean fields.  */
 
         /*  The virtual memory address of the section - where it will be
@@ -2129,6 +2135,26 @@ instruction. */
 significant 8 bits of a 24 bit word are placed into the least
 significant 8 bits of the opcode. */
   BFD_RELOC_TIC30_LDP,
+
+/* These two relocations are used by the linker to determine which of 
+the entries in a C++ virtual function table are actually used.  When
+the --gc-sections option is given, the linker will zero out the entries
+that are not used, so that the code for those functions need not be
+included in the output.
+
+VTABLE_INHERIT is a zero-space relocation used to describe to the
+linker the inheritence tree of a C++ virtual function table.  The
+relocation's symbol should be the parent class' vtable, and the
+relocation should be located at the child vtable.
+
+VTABLE_ENTRY is a zero-space relocation that describes the use of a
+virtual function table entry.  The reloc's symbol should refer to the
+table of the class mentioned in the code.  Off of that base, an offset
+describes the entry that is being used.  For Rela hosts, this offset 
+is stored in the reloc's addend.  For Rel hosts, we are forced to put
+this offset in the reloc's section offset. */
+  BFD_RELOC_VTABLE_INHERIT,
+  BFD_RELOC_VTABLE_ENTRY,
   BFD_RELOC_UNUSED };
 typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
 reloc_howto_type *
@@ -2577,6 +2603,9 @@ bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags));
 #define bfd_relax_section(abfd, section, link_info, again) \
        BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again))
 
+#define bfd_gc_sections(abfd, link_info) \
+       BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
+
 #define bfd_link_hash_table_create(abfd) \
        BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
 
@@ -2871,7 +2900,8 @@ CAT(NAME,_bfd_relax_section),\
 CAT(NAME,_bfd_link_hash_table_create),\
 CAT(NAME,_bfd_link_add_symbols),\
 CAT(NAME,_bfd_final_link),\
-CAT(NAME,_bfd_link_split_section)
+CAT(NAME,_bfd_link_split_section),\
+CAT(NAME,_bfd_gc_sections)
   int        (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
   bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
                     struct bfd_link_info *, struct bfd_link_order *,
@@ -2895,7 +2925,10 @@ CAT(NAME,_bfd_link_split_section)
    /* Should this section be split up into smaller pieces during linking.  */
   boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *));
 
-  /* Routines to handle dynamic symbols and relocs.  */
+   /* Remove sections that are not referenced from the output.  */
+  boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *));
+
+   /* Routines to handle dynamic symbols and relocs.  */
 #define BFD_JUMP_TABLE_DYNAMIC(NAME)\
 CAT(NAME,_get_dynamic_symtab_upper_bound),\
 CAT(NAME,_canonicalize_dynamic_symtab),\
index c2c5f31..99bf9e5 100644 (file)
@@ -3401,7 +3401,7 @@ coff_slurp_line_table (abfd, asect)
                  || (unsigned long) symndx >= obj_raw_syment_count (abfd))
                {
                  (*_bfd_error_handler)
-                   ("%s: warning: illegal symbol index %ld in line numbers",
+                   (_("%s: warning: illegal symbol index %ld in line numbers"),
                     bfd_get_filename (abfd), dst.l_addr.l_symndx);
                  symndx = 0;
                  warned = true;
@@ -3415,7 +3415,7 @@ coff_slurp_line_table (abfd, asect)
              if (sym->lineno != NULL && ! warned)
                {
                  (*_bfd_error_handler)
-                   ("%s: warning: duplicate line number information for `%s'",
+                   (_("%s: warning: duplicate line number information for `%s'"),
                     bfd_get_filename (abfd),
                     bfd_asymbol_name (&sym->symbol));
                }
@@ -3519,7 +3519,7 @@ coff_slurp_symbol_table (abfd)
 #ifdef COFF_WITH_PE
             /* PE uses storage class 0x68 to denote a section symbol */
             case C_SECTION:
-           /* PE uses storage class 0x67 for a weak external symbol.  */
+           /* PE uses storage class 0x69 for a weak external symbol.  */
            case C_NT_WEAK:
 #endif
              if ((src->u.syment.n_scnum) == 0)
@@ -3738,7 +3738,7 @@ coff_slurp_symbol_table (abfd)
            case C_HIDDEN:      /* ext symbol in dmert public lib */
            default:
              (*_bfd_error_handler)
-               ("%s: Unrecognized storage class %d for %s symbol `%s'",
+               (_("%s: Unrecognized storage class %d for %s symbol `%s'"),
                 bfd_get_filename (abfd), src->u.syment.n_sclass,
                 dst->symbol.section->name, dst->symbol.name);
              dst->symbol.flags = BSF_DEBUGGING;
@@ -3922,7 +3922,7 @@ coff_slurp_reloc_table (abfd, asect, symbols)
          if (dst.r_symndx < 0 || dst.r_symndx >= obj_conv_table_size (abfd))
            {
              (*_bfd_error_handler)
-               ("%s: warning: illegal symbol index %ld in relocs",
+               (_("%s: warning: illegal symbol index %ld in relocs"),
                 bfd_get_filename (abfd), dst.r_symndx);
              cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
              ptr = NULL;
@@ -3960,7 +3960,7 @@ coff_slurp_reloc_table (abfd, asect, symbols)
       if (cache_ptr->howto == NULL)
        {
          (*_bfd_error_handler)
-           ("%s: illegal relocation type %d at address 0x%lx",
+           (_("%s: illegal relocation type %d at address 0x%lx"),
             bfd_get_filename (abfd), dst.r_type, (long) dst.r_vaddr);
          bfd_set_error (bfd_error_bad_value);
          return false;
@@ -4299,3 +4299,7 @@ static CONST bfd_coff_backend_data bfd_coff_std_swap_table =
 #ifndef coff_bfd_relax_section
 #define coff_bfd_relax_section             bfd_generic_relax_section
 #endif
+
+#ifndef coff_bfd_gc_sections
+#define coff_bfd_gc_sections               bfd_generic_gc_sections
+#endif
index a2f60ba..1cb8e74 100644 (file)
@@ -92,6 +92,12 @@ static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
 static void mn10300_info_to_howto
   PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+static boolean mn10300_elf_check_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
+static asection *mn10300_elf_gc_mark_hook
+  PARAMS ((bfd *, struct bfd_link_info *info, Elf_Internal_Rela *,
+          struct elf_link_hash_entry *, Elf_Internal_Sym *));
 static boolean mn10300_elf_relax_delete_bytes
   PARAMS ((bfd *, asection *, bfd_vma, int));
 static boolean mn10300_elf_symbol_address_p
@@ -115,6 +121,11 @@ enum reloc_type
   R_MN10300_PCREL32,
   R_MN10300_PCREL16,
   R_MN10300_PCREL8,
+
+  /* These are GNU extensions to enable C++ vtable garbage collection.  */
+  R_MN10300_GNU_VTINHERIT,
+  R_MN10300_GNU_VTENTRY,
+
   R_MN10300_MAX
 };
 
@@ -218,6 +229,36 @@ static reloc_howto_type elf_mn10300_howto_table[] =
         0xff,
         0xff,
         true),
+
+  /* GNU extension to record C++ vtable hierarchy */
+  HOWTO (R_MN10300_GNU_VTINHERIT, /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_MN10300_GNU_VTINHERIT", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable member usage */
+  HOWTO (R_MN10300_GNU_VTENTRY,        /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_MN10300_GNU_VTENTRY", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false),                /* pcrel_offset */
 };
 
 struct mn10300_reloc_map
@@ -235,6 +276,8 @@ static const struct mn10300_reloc_map mn10300_reloc_map[] =
   { BFD_RELOC_32_PCREL, R_MN10300_PCREL32, },
   { BFD_RELOC_16_PCREL, R_MN10300_PCREL16, },
   { BFD_RELOC_8_PCREL, R_MN10300_PCREL8, },
+  { BFD_RELOC_VTABLE_INHERIT, R_MN10300_GNU_VTINHERIT },
+  { BFD_RELOC_VTABLE_ENTRY, R_MN10300_GNU_VTENTRY },
 };
 
 static reloc_howto_type *
@@ -270,6 +313,109 @@ mn10300_info_to_howto (abfd, cache_ptr, dst)
   cache_ptr->howto = &elf_mn10300_howto_table[r_type];
 }
 
+/* Look through the relocs for a section during the first phase.
+   Since we don't do .gots or .plts, we just need to consider the
+   virtual table relocs for gc.  */
+
+static boolean
+mn10300_elf_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+
+  if (info->relocateable)
+    return true;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      struct elf_link_hash_entry *h;
+      unsigned long r_symndx;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       /* This relocation describes the C++ object vtable hierarchy.
+          Reconstruct it for later use during GC.  */
+       case R_MN10300_GNU_VTINHERIT:
+         if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+           return false;
+         break;
+
+       /* This relocation describes which C++ vtable entries are actually
+          used.  Record for later use during GC.  */
+       case R_MN10300_GNU_VTENTRY:
+         if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return false;
+         break;
+       }
+    }
+
+  return true;
+}
+
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+mn10300_elf_gc_mark_hook (abfd, info, rel, h, sym)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       case R_MN10300_GNU_VTINHERIT:
+       case R_MN10300_GNU_VTENTRY:
+         break;
+
+       default:
+         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;
+           }
+       }
+    }
+  else
+    {
+      if (!(elf_bad_symtab (abfd)
+           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+               && sym->st_shndx != SHN_COMMON))
+       {
+         return bfd_section_from_elf_index (abfd, sym->st_shndx);
+       }
+    }
+
+  return NULL;
+}
+
 /* Perform a relocation as part of a final link.  */
 static bfd_reloc_status_type
 mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
@@ -292,7 +438,6 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
 
   switch (r_type)
     {
-
     case R_MN10300_NONE:
       return bfd_reloc_ok;
 
@@ -352,6 +497,10 @@ mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd,
       bfd_put_32 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
+    case R_MN10300_GNU_VTINHERIT:
+    case R_MN10300_GNU_VTENTRY:
+      return bfd_reloc_ok;
+
     default:
       return bfd_reloc_notsupported;
     }
@@ -396,6 +545,11 @@ mn10300_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       r_type = ELF32_R_TYPE (rel->r_info);
       howto = elf_mn10300_howto_table + r_type;
 
+      /* Just skip the vtable gc relocs.  */
+      if (r_type == R_MN10300_GNU_VTINHERIT
+         || r_type == R_MN10300_GNU_VTENTRY)
+       continue;
+
       if (info->relocateable)
        {
          /* This is a relocateable link.  We don't have to change
@@ -2556,9 +2710,12 @@ _bfd_mn10300_elf_object_p (abfd)
 #define ELF_MACHINE_CODE       EM_CYGNUS_MN10300
 #define ELF_MAXPAGESIZE                0x1000
 
-#define elf_info_to_howto      mn10300_info_to_howto
-#define elf_info_to_howto_rel  0
-#define elf_backend_relocate_section mn10300_elf_relocate_section
+#define elf_info_to_howto              mn10300_info_to_howto
+#define elf_info_to_howto_rel          0
+#define elf_backend_can_gc_sections    1
+#define elf_backend_check_relocs       mn10300_elf_check_relocs
+#define elf_backend_gc_mark_hook       mn10300_elf_gc_mark_hook
+#define elf_backend_relocate_section   mn10300_elf_relocate_section
 #define bfd_elf32_bfd_relax_section    mn10300_elf_relax_section
 #define bfd_elf32_bfd_get_relocated_section_contents \
                                mn10300_elf_get_relocated_section_contents
index af26c8c..f5f34aa 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -840,10 +840,12 @@ _bfd_elf_link_hash_newfunc (entry, table, string)
       ret->dynindx = -1;
       ret->dynstr_index = 0;
       ret->weakdef = NULL;
-      ret->got_offset = (bfd_vma) -1;
-      ret->plt_offset = (bfd_vma) -1;
+      ret->got.offset = (bfd_vma) -1;
+      ret->plt.offset = (bfd_vma) -1;
       ret->linker_section_pointer = (elf_linker_section_pointers_t *)0;
       ret->verinfo.verdef = NULL;
+      ret->vtable_entries_used = NULL;
+      ret->vtable_parent = NULL;
       ret->type = STT_NOTYPE;
       ret->other = 0;
       /* Assume that we have been called by a non-ELF symbol reader.
@@ -2178,6 +2180,7 @@ map_sections_to_segments (abfd)
       if (phdr_size == 0)
        phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr;
       if ((abfd->flags & D_PAGED) == 0
+         || sections[0]->lma < phdr_size
          || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
        phdr_in_section = false;
     }
index 774d185..bf65def 100644 (file)
@@ -1,5 +1,5 @@
 /* Motorola 68k series support for 32-bit ELF
-   Copyright 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -38,6 +38,8 @@ static boolean elf_m68k_check_relocs
           const Elf_Internal_Rela *));
 static boolean elf_m68k_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf_m68k_adjust_dynindx
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_m68k_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_m68k_relocate_section
@@ -414,12 +416,12 @@ elf_m68k_check_relocs (abfd, info, sec, relocs)
 
          if (h != NULL)
            {
-             if (h->got_offset != (bfd_vma) -1)
+             if (h->got.offset != (bfd_vma) -1)
                {
                  /* We have already allocated space in the .got.  */
                  break;
                }
-             h->got_offset = sgot->_raw_size;
+             h->got.offset = sgot->_raw_size;
 
              /* Make sure this symbol is output as a dynamic symbol.  */
              if (h->dynindx == -1)
@@ -699,7 +701,7 @@ elf_m68k_adjust_dynamic_symbol (info, h)
          h->root.u.def.value = s->_raw_size;
        }
 
-      h->plt_offset = s->_raw_size;
+      h->plt.offset = s->_raw_size;
 
       /* Make room for this entry.  */
       s->_raw_size += PLT_ENTRY_SIZE;
@@ -911,7 +913,8 @@ elf_m68k_size_dynamic_sections (output_bfd, info)
                                                  s->output_section);
                  target = bfd_get_section_by_name (output_bfd, outname + 5);
                  if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0)
+                     && (target->flags & SEC_READONLY) != 0
+                     && (target->flags & SEC_ALLOC) != 0)
                    reltext = true;
                }
 
@@ -984,6 +987,51 @@ elf_m68k_size_dynamic_sections (output_bfd, info)
        }
     }
 
+  /* If we are generating a shared library, we generate a section
+     symbol for each output section for which we might need to copy
+     relocs.  These are local symbols, which means that they must come
+     first in the dynamic symbol table.  That means we must increment
+     the dynamic symbol index of every other dynamic symbol.  */
+  if (info->shared)
+    {
+      int c;
+
+      c = 0;
+      for (s = output_bfd->sections; s != NULL; s = s->next)
+       {
+         if ((s->flags & SEC_LINKER_CREATED) != 0
+             || (s->flags & SEC_ALLOC) == 0)
+           continue;
+
+         elf_section_data (s)->dynindx = c + 1;
+
+         /* These symbols will have no names, so we don't need to
+             fiddle with dynstr_index.  */
+
+         ++c;
+       }
+
+      elf_link_hash_traverse (elf_hash_table (info),
+                             elf_m68k_adjust_dynindx,
+                             (PTR) &c);
+      elf_hash_table (info)->dynsymcount += c;
+    }
+
+  return true;
+}
+
+/* Increment the index of a dynamic symbol by a given amount.  Called
+   via elf_link_hash_traverse.  */
+
+static boolean
+elf_m68k_adjust_dynindx (h, cparg)
+     struct elf_link_hash_entry *h;
+     PTR cparg;
+{
+  int *cp = (int *) cparg;
+
+  if (h->dynindx != -1)
+    h->dynindx += *cp;
   return true;
 }
 
@@ -1114,7 +1162,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
                    || r_type == R_68K_PLT8O
                    || r_type == R_68K_PLT16O
                    || r_type == R_68K_PLT32O)
-                  && h->plt_offset != (bfd_vma) -1)
+                  && h->plt.offset != (bfd_vma) -1)
                  || ((r_type == R_68K_GOT8O
                       || r_type == R_68K_GOT16O
                       || r_type == R_68K_GOT32O
@@ -1192,7 +1240,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
 
            if (h != NULL)
              {
-               off = h->got_offset;
+               off = h->got.offset;
                BFD_ASSERT (off != (bfd_vma) -1);
 
                if (!elf_hash_table (info)->dynamic_sections_created
@@ -1218,7 +1266,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
                      {
                        bfd_put_32 (output_bfd, relocation,
                                    sgot->contents + off);
-                       h->got_offset |= 1;
+                       h->got.offset |= 1;
                      }
                  }
              }
@@ -1286,7 +1334,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
          if (h == NULL)
            break;
 
-         if (h->plt_offset == (bfd_vma) -1)
+         if (h->plt.offset == (bfd_vma) -1)
            {
              /* We didn't make a PLT entry for this symbol.  This
                 happens when statically linking PIC code, or when
@@ -1302,7 +1350,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
 
          relocation = (splt->output_section->vma
                        + splt->output_offset
-                       + h->plt_offset);
+                       + h->plt.offset);
          break;
 
        case R_68K_PLT8O:
@@ -1310,7 +1358,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_68K_PLT32O:
          /* Relocation is the offset of the entry for this symbol in
             the procedure linkage table.  */
-         BFD_ASSERT (h != NULL && h->plt_offset == (bfd_vma) -1);
+         BFD_ASSERT (h != NULL && h->plt.offset != (bfd_vma) -1);
 
          if (splt == NULL)
            {
@@ -1318,7 +1366,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
              BFD_ASSERT (splt != NULL);
            }
 
-         relocation = h->plt_offset;
+         relocation = h->plt.offset;
 
          /* This relocation does not use the addend.  */
          rel->r_addend = 0;
@@ -1442,8 +1490,7 @@ elf_m68k_relocate_section (output_bfd, info, input_bfd, input_section,
 
                          osec = sec->output_section;
                          indx = elf_section_data (osec)->dynindx;
-                         if (indx == 0)
-                           abort ();
+                         BFD_ASSERT (indx > 0);
                        }
 
                      relocate = false;
@@ -1526,7 +1573,7 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   dynobj = elf_hash_table (info)->dynobj;
 
-  if (h->plt_offset != (bfd_vma) -1)
+  if (h->plt.offset != (bfd_vma) -1)
     {
       asection *splt;
       asection *sgot;
@@ -1549,7 +1596,7 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
         corresponds to this symbol.  This is the index of this symbol
         in all the symbols for which we are making plt entries.  The
         first entry in the procedure linkage table is reserved.  */
-      plt_index = h->plt_offset / PLT_ENTRY_SIZE - 1;
+      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
 
       /* Get the offset into the .got table of the entry that
         corresponds to this function.  Each .got entry is 4 bytes.
@@ -1557,7 +1604,7 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
       got_offset = (plt_index + 3) * 4;
 
       /* Fill in the entry in the procedure linkage table.  */
-      memcpy (splt->contents + h->plt_offset, elf_m68k_plt_entry,
+      memcpy (splt->contents + h->plt.offset, elf_m68k_plt_entry,
              PLT_ENTRY_SIZE);
       /* The offset is relative to the first extension word.  */
       bfd_put_32 (output_bfd,
@@ -1565,19 +1612,19 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
                   + sgot->output_offset
                   + got_offset
                   - (splt->output_section->vma
-                     + h->plt_offset + 2)),
-                 splt->contents + h->plt_offset + 4);
+                     + h->plt.offset + 2)),
+                 splt->contents + h->plt.offset + 4);
 
       bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela),
-                 splt->contents + h->plt_offset + 10);
-      bfd_put_32 (output_bfd, - (h->plt_offset + 16),
-                 splt->contents + h->plt_offset + 16);
+                 splt->contents + h->plt.offset + 10);
+      bfd_put_32 (output_bfd, - (h->plt.offset + 16),
+                 splt->contents + h->plt.offset + 16);
 
       /* Fill in the entry in the global offset table.  */
       bfd_put_32 (output_bfd,
                  (splt->output_section->vma
                   + splt->output_offset
-                  + h->plt_offset
+                  + h->plt.offset
                   + 8),
                  sgot->contents + got_offset);
 
@@ -1599,7 +1646,7 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
        }
     }
 
-  if (h->got_offset != (bfd_vma) -1)
+  if (h->got.offset != (bfd_vma) -1)
     {
       asection *sgot;
       asection *srela;
@@ -1614,7 +1661,7 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       rela.r_offset = (sgot->output_section->vma
                       + sgot->output_offset
-                      + (h->got_offset &~ 1));
+                      + (h->got.offset &~ 1));
 
       /* If this is a -Bsymbolic link, and the symbol is defined
         locally, we just want to emit a RELATIVE reloc.  Likewise if
@@ -1628,12 +1675,12 @@ elf_m68k_finish_dynamic_symbol (output_bfd, info, h, sym)
          rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
          rela.r_addend = bfd_get_signed_32 (output_bfd,
                                             (sgot->contents
-                                             + (h->got_offset & ~1)));
+                                             + (h->got.offset & ~1)));
        }
       else
        {
          bfd_put_32 (output_bfd, (bfd_vma) 0,
-                     sgot->contents + (h->got_offset & ~1));
+                     sgot->contents + (h->got.offset & ~1));
          rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT);
          rela.r_addend = 0;
        }
@@ -1796,6 +1843,50 @@ elf_m68k_finish_dynamic_sections (output_bfd, info)
 
   elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
 
+  if (info->shared)
+    {
+      asection *sdynsym;
+      asection *s;
+      Elf_Internal_Sym sym;
+      int c;
+
+      /* Set up the section symbols for the output sections.  */
+
+      sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (sdynsym != NULL);
+
+      sym.st_size = 0;
+      sym.st_name = 0;
+      sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+      sym.st_other = 0;
+
+      c = 0;
+      for (s = output_bfd->sections; s != NULL; s = s->next)
+       {
+         int indx;
+
+         if (elf_section_data (s)->dynindx == 0)
+           continue;
+
+         sym.st_value = s->vma;
+
+         indx = elf_section_data (s)->this_idx;
+         BFD_ASSERT (indx > 0);
+         sym.st_shndx = indx;
+
+         bfd_elf32_swap_symbol_out (output_bfd, &sym,
+                                    (PTR) (((Elf32_External_Sym *)
+                                            sdynsym->contents)
+                                           + elf_section_data (s)->dynindx));
+
+         ++c;
+       }
+
+      /* Set the sh_info field of the output .dynsym section to the
+         index of the first global symbol.  */
+      elf_section_data (sdynsym->output_section)->this_hdr.sh_info = c + 1;
+    }
+
   return true;
 }
 
index 854fa27..60a0275 100644 (file)
@@ -317,12 +317,15 @@ enum reloc_type
   R_MIPS_max,
   /* These relocs are used for the mips16.  */
   R_MIPS16_26 = 100,
-  R_MIPS16_GPREL = 101
+  R_MIPS16_GPREL = 101,
 /* start-sanitize-sky */
   /* These relocs are for the dvp.  */
-  R_MIPS_DVP_11_PCREL = 120,
-  R_MIPS_DVP_27_S4 = 121
+  R_MIPS_DVP_11_PCREL = 120,
+  R_MIPS_DVP_27_S4 = 121,
 /* end-sanitize-sky */
+  /* These are GNU extensions to enable C++ vtable garbage collection.  */
+  R_MIPS_GNU_VTINHERIT = 253,
+  R_MIPS_GNU_VTENTRY = 254
 };
 
 static reloc_howto_type elf_mips_howto_table[] =
@@ -814,6 +817,38 @@ static reloc_howto_type elf_mips_dvp_27_s4_howto =
         false);                /* pcrel_offset */
 /* end-sanitize-sky */
 
+/* GNU extension to record C++ vtable hierarchy */
+static reloc_howto_type elf_mips_gnu_vtinherit_howto =
+  HOWTO (R_MIPS_GNU_VTINHERIT, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_MIPS_GNU_VTINHERIT", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false);                /* pcrel_offset */
+
+/* GNU extension to record C++ vtable member usage */
+static reloc_howto_type elf_mips_gnu_vtentry_howto =
+  HOWTO (R_MIPS_GNU_VTENTRY,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_MIPS_GNU_VTENTRY",  /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false);                /* pcrel_offset */
+
 /* Do a R_MIPS_HI16 relocation.  This has to be done in combination
    with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to
    the HI16.  Here we just save the information we need; we do the
@@ -1662,30 +1697,32 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
        return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
     }
 
-  /* We need to handle BFD_RELOC_CTOR specially.
-
-     Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
-     size of addresses on this architecture.  */
-  if (code == BFD_RELOC_CTOR)
+  switch (code)
     {
+    case BFD_RELOC_CTOR:
+      /* We need to handle BFD_RELOC_CTOR specially.
+        Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
+        size of addresses on this architecture.  */
       if (bfd_arch_bits_per_address (abfd) == 32)
        return &elf_mips_howto_table[(int) R_MIPS_32];
       else
        return &elf_mips_ctor64_howto;
-    }
 
-  /* Special handling for the MIPS16 relocs, since they are made up
-     reloc types with a large value.  */
-  if (code == BFD_RELOC_MIPS16_JMP)
-    return &elf_mips16_jump_howto;
-  else if (code == BFD_RELOC_MIPS16_GPREL)
-    return &elf_mips16_gprel_howto;
+    case BFD_RELOC_MIPS16_JMP:
+      return &elf_mips16_jump_howto;
+    case BFD_RELOC_MIPS16_GPREL:
+      return &elf_mips16_gprel_howto;
 /* start-sanitize-sky */
-  else if (code == BFD_RELOC_MIPS_DVP_11_PCREL)
-    return &elf_mips_dvp_11_pcrel_howto;
-  else if (code == BFD_RELOC_MIPS_DVP_27_S4)
-    return &elf_mips_dvp_27_s4_howto;
+    case BFD_RELOC_MIPS_DVP_11_PCREL:
+      return &elf_mips_dvp_11_pcrel_howto;
+    case BFD_RELOC_MIPS_DVP_27_S4:
+      return &elf_mips_dvp_27_s4_howto;
 /* end-sanitize-sky */
+    case BFD_RELOC_VTABLE_INHERIT:
+      return &elf_mips_gnu_vtinherit_howto;
+    case BFD_RELOC_VTABLE_ENTRY:
+      return &elf_mips_gnu_vtentry_howto;
+    }
 
   return NULL;
 }
@@ -1701,20 +1738,33 @@ mips_info_to_howto_rel (abfd, cache_ptr, dst)
   unsigned int r_type;
 
   r_type = ELF32_R_TYPE (dst->r_info);
-  if (r_type == R_MIPS16_26)
-    cache_ptr->howto = &elf_mips16_jump_howto;
-  else if (r_type == R_MIPS16_GPREL)
-    cache_ptr->howto = &elf_mips16_gprel_howto;
+  switch (r_type)
+    {
+    case R_MIPS16_26:
+      cache_ptr->howto = &elf_mips16_jump_howto;
+      break;
+    case R_MIPS16_GPREL:
+      cache_ptr->howto = &elf_mips16_gprel_howto;
+      break;
 /* start-sanitize-sky */
-  else if (r_type == R_MIPS_DVP_11_PCREL)
-    cache_ptr->howto = &elf_mips_dvp_11_pcrel_howto;
-  else if (r_type == R_MIPS_DVP_27_S4)
-    cache_ptr->howto = &elf_mips_dvp_27_s4_howto;
+    case R_MIPS_DVP_11_PCREL:
+      cache_ptr->howto = &elf_mips_dvp_11_pcrel_howto;
+      break;
+    case R_MIPS_DVP_27_S4:
+      cache_ptr->howto = &elf_mips_dvp_27_s4_howto;
+      break;
 /* end-sanitize-sky */
-  else
-    {
+    case R_MIPS_GNU_VTINHERIT:
+      cache_ptr->howto = &elf_mips_gnu_vtinherit_howto;
+      break;
+    case R_MIPS_GNU_VTENTRY:
+      cache_ptr->howto = &elf_mips_gnu_vtentry_howto;
+      break;
+
+    default:
       BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
       cache_ptr->howto = &elf_mips_howto_table[r_type];
+      break;
     }
 
   /* The addend for a GPREL16 or LITERAL relocation comes from the GP
@@ -2558,7 +2608,7 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec)
   else if (strcmp (name, SHNAME_DVP_OVERLAY_TABLE) == 0)
     {
       hdr->sh_type = SHT_DVP_OVERLAY_TABLE;
-      hdr->sh_entsize = sizeof (Elf64_Dvp_External_Overlay);
+      hdr->sh_entsize = sizeof (Elf32_Dvp_External_Overlay);
       /* The sh_link field is set in final_write_processing.  */
     }
   else if (strcmp (name, SHNAME_DVP_OVERLAY_STRTAB) == 0)
@@ -3792,7 +3842,7 @@ mips_elf_output_extsym (h, data)
        {
          output_section = sec->output_section;
          if (output_section != NULL)
-           h->esym.asym.value = (h->root.plt_offset
+           h->esym.asym.value = (h->root.plt.offset
                                  + sec->output_offset
                                  + output_section->vma);
          else
@@ -4815,6 +4865,9 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_reloc_status_type r;
 
       r_type = ELF32_R_TYPE (rel->r_info);
+      if (r_type == R_MIPS_GNU_VTINHERIT
+         || r_type == R_MIPS_GNU_VTENTRY)
+       continue;
       if ((r_type < 0 || r_type >= (int) R_MIPS_max)
 /* start-sanitize-sky */
          && r_type != R_MIPS_DVP_11_PCREL
@@ -5239,7 +5292,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              /* This symbol must be registered as a global symbol
                 having the corresponding got entry.  */
-             BFD_ASSERT (h->got_offset != (bfd_vma) -1);
+             BFD_ASSERT (h->got.offset != (bfd_vma) -1);
 
              offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
              BFD_ASSERT (g->local_gotno <= offset
@@ -5259,7 +5312,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              /* This must be a global symbol with a got entry.  The
                  next reloc must be the corresponding LO16 reloc.  */
-             BFD_ASSERT (h != NULL && h->got_offset != (bfd_vma) -1);
+             BFD_ASSERT (h != NULL && h->got.offset != (bfd_vma) -1);
              BFD_ASSERT ((rel + 1) < relend);
              BFD_ASSERT ((int) ELF32_R_TYPE ((rel + 1)->r_info)
                          == (r_type == R_MIPS_CALL_HI16
@@ -6210,7 +6263,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                return false;
            }
 
-         if (h->got_offset != (bfd_vma) -1)
+         if (h->got.offset != (bfd_vma) -1)
            {
              /* We have already allocated space in the .got.  */
              break;
@@ -6222,7 +6275,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
            g->global_gotsym = h->dynindx;
 
          /* Make this symbol to have the corresponding got entry.  */
-         h->got_offset = 0;
+         h->got.offset = 0;
 
          /* We need a stub, not a plt entry for the undefined
             function.  But we record it as if it needs plt.  See
@@ -6246,7 +6299,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                    return false;
                }
 
-             if (h->got_offset != (bfd_vma) -1)
+             if (h->got.offset != (bfd_vma) -1)
                {
                  /* We have already allocated space in the .got.  */
                  break;
@@ -6258,7 +6311,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
                g->global_gotsym = h->dynindx;
 
              /* Make this symbol to be the global got symbol.  */
-             h->got_offset = 0;
+             h->got.offset = 0;
            }
 
          break;
@@ -6329,6 +6382,20 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
              sizeof (Elf32_External_crinfo);
          break;
 
+         /* This relocation describes the C++ object vtable hierarchy.
+            Reconstruct it for later use during GC.  */
+       case R_MIPS_GNU_VTINHERIT:
+         if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+           return false;
+         break;
+
+         /* This relocation describes which C++ vtable entries are actually
+            used.  Record for later use during GC.  */
+       case R_MIPS_GNU_VTENTRY:
+         if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+           return false;
+         break;
+
        default:
          break;
        }
@@ -6355,6 +6422,98 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
   return true;
 }
 
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  /* ??? Do mips16 stub sections need to be handled special?  */
+
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       case R_MIPS_GNU_VTINHERIT:
+       case R_MIPS_GNU_VTENTRY:
+         break;
+
+       default:
+         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;
+           }
+       }
+    }
+  else
+    {
+      if (!(elf_bad_symtab (abfd)
+           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+               && sym->st_shndx != SHN_COMMON))
+       {
+         return bfd_section_from_elf_index (abfd, sym->st_shndx);
+       }
+    }
+
+  return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed.  */
+
+static boolean
+mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+#if 0
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_MIPS_GOT16:
+      case R_MIPS_CALL16:
+      case R_MIPS_CALL_HI16:
+      case R_MIPS_CALL_LO16:
+      case R_MIPS_GOT_HI16:
+      case R_MIPS_GOT_LO16:
+       /* ??? It would seem that the existing MIPS code does no sort
+          of reference counting or whatnot on its GOT and PLT entries,
+          so it is not possible to garbage collect them at this time.  */
+        break;
+
+      default:
+       break;
+      }
+#endif
+
+  return true;
+}
+
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -6424,7 +6583,7 @@ mips_elf_adjust_dynamic_symbol (info, h)
          h->root.u.def.value = s->_raw_size;
 
          /* XXX Write this stub address somewhere.  */
-         h->plt_offset = s->_raw_size;
+         h->plt.offset = s->_raw_size;
 
          /* Make room for this stub code.  */
          s->_raw_size += MIPS_FUNCTION_STUB_SIZE;
@@ -6608,7 +6767,18 @@ mips_elf_size_dynamic_sections (output_bfd, info)
       if (strncmp (name, ".rel", 4) == 0)
        {
          if (s->_raw_size == 0)
-           strip = true;
+           {
+             /* We only strip the section if the output section name
+                 has the same name.  Otherwise, there might be several
+                 input sections for this output section.  FIXME: This
+                 code is probably not needed these days anyhow, since
+                 the linker now does not create empty output sections.  */
+             if (s->output_section != NULL
+                 && strcmp (name,
+                            bfd_get_section_name (s->output_section->owner,
+                                                  s->output_section)) == 0)
+               strip = true;
+           }
          else
            {
              const char *outname;
@@ -6917,7 +7087,7 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
   dynobj = elf_hash_table (info)->dynobj;
   gval = sym->st_value;
 
-  if (h->plt_offset != (bfd_vma) -1)
+  if (h->plt.offset != (bfd_vma) -1)
     {
       asection *s;
       bfd_byte *p;
@@ -6945,17 +7115,17 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       p += 4;
       bfd_put_32 (output_bfd, STUB_LI16 + h->dynindx, p);
 
-      BFD_ASSERT (h->plt_offset <= s->_raw_size);
-      memcpy (s->contents + h->plt_offset, stub, MIPS_FUNCTION_STUB_SIZE);
+      BFD_ASSERT (h->plt.offset <= s->_raw_size);
+      memcpy (s->contents + h->plt.offset, stub, MIPS_FUNCTION_STUB_SIZE);
 
-      /* Mark the symbol as undefined.  plt_offset != -1 occurs
+      /* Mark the symbol as undefined.  plt.offset != -1 occurs
         only for the referenced symbol.  */
       sym->st_shndx = SHN_UNDEF;
 
       /* The run-time linker uses the st_value field of the symbol
         to reset the global offset table entry for this external
         to its stub address when unlinking a shared object.  */
-      gval = s->output_section->vma + s->output_offset + h->plt_offset;
+      gval = s->output_section->vma + s->output_offset + h->plt.offset;
       sym->st_value = gval;
     }
 
@@ -6973,7 +7143,7 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       /* This symbol has an entry in the global offset table.  Set its
         value to the corresponding got entry, if needed.  */
-      if (h->got_offset == (bfd_vma) -1)
+      if (h->got.offset == (bfd_vma) -1)
        {
          offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
          BFD_ASSERT (g->local_gotno * 4 <= offset
@@ -7612,6 +7782,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
 
 #define elf_backend_collect            true
 #define elf_backend_type_change_ok     true
+#define elf_backend_can_gc_sections    true
 #define elf_info_to_howto              0
 #define elf_info_to_howto_rel          mips_info_to_howto_rel
 #define elf_backend_sym_is_global      mips_elf_sym_is_global
@@ -7658,5 +7829,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
                                        mips_elf_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_sections \
                                        mips_elf_finish_dynamic_sections
+#define elf_backend_gc_mark_hook       mips_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook      mips_elf_gc_sweep_hook
 
 #include "elf32-target.h"
index d711281..adc0a8f 100644 (file)
@@ -1459,12 +1459,12 @@ elf_link_add_object_symbols (abfd, info)
                      /* Copy over the global table offset entry.
                         This may have been already set up by a
                         check_relocs routine.  */
-                     if (ht->got_offset == (bfd_vma) -1)
+                     if (ht->got.offset == (bfd_vma) -1)
                        {
-                         ht->got_offset = hi->got_offset;
-                         hi->got_offset = (bfd_vma) -1;
+                         ht->got.offset = hi->got.offset;
+                         hi->got.offset = (bfd_vma) -1;
                        }
-                     BFD_ASSERT (hi->got_offset == (bfd_vma) -1);
+                     BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
 
                      if (ht->dynindx == -1)
                        {
@@ -1560,12 +1560,12 @@ elf_link_add_object_symbols (abfd, info)
                          /* Copy over the global table offset entry.
                              This may have been already set up by a
                              check_relocs routine.  */
-                         if (h->got_offset == (bfd_vma) -1)
+                         if (h->got.offset == (bfd_vma) -1)
                            {
-                             h->got_offset = hi->got_offset;
-                             hi->got_offset = (bfd_vma) -1;
+                             h->got.offset = hi->got.offset;
+                             hi->got.offset = (bfd_vma) -1;
                            }
-                         BFD_ASSERT (hi->got_offset == (bfd_vma) -1);
+                         BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
 
                          if (h->dynindx == -1)
                            {
@@ -4884,7 +4884,8 @@ elf_link_input_bfd (finfo, input_bfd)
       /* Write out the modified section contents.  */
       if (elf_section_data (o)->stab_info == NULL)
        {
-         if (! bfd_set_section_contents (output_bfd, o->output_section,
+         if (! (o->flags & SEC_EXCLUDE) &&
+             ! bfd_set_section_contents (output_bfd, o->output_section,
                                          contents, o->output_offset,
                                          (o->_cooked_size != 0
                                           ? o->_cooked_size
@@ -5298,3 +5299,546 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
      processing.  */
   return relocation - linker_section_ptr->addend;
 }
+\f
+/* Garbage collect unused sections.  */
+
+static boolean elf_gc_mark 
+  PARAMS ((struct bfd_link_info *info, asection *sec,
+          asection * (*gc_mark_hook)
+            PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+                     struct elf_link_hash_entry *, Elf_Internal_Sym *))));
+
+static boolean elf_gc_sweep
+  PARAMS ((struct bfd_link_info *info,
+          boolean (*gc_sweep_hook)
+            PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
+                     const Elf_Internal_Rela *relocs))));
+
+static boolean elf_gc_sweep_symbol
+  PARAMS ((struct elf_link_hash_entry *h, PTR idxptr));
+
+static boolean elf_gc_allocate_got_offsets
+  PARAMS ((struct elf_link_hash_entry *h, PTR offarg));
+
+static boolean elf_gc_propogate_vtable_entries_used
+  PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+
+static boolean elf_gc_smash_unused_vtentry_relocs
+  PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+
+/* The mark phase of garbage collection.  For a given section, mark
+   it, and all the sections which define symbols to which it refers.  */
+
+static boolean
+elf_gc_mark (info, sec, gc_mark_hook)
+     struct bfd_link_info *info;
+     asection *sec;
+     asection * (*gc_mark_hook)
+       PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+               struct elf_link_hash_entry *, Elf_Internal_Sym *));
+{
+  boolean ret = true;
+  
+  sec->gc_mark = 1;
+
+  /* Look through the section relocs.  */
+
+  if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
+    {
+      Elf_Internal_Rela *relstart, *rel, *relend;
+      Elf_Internal_Shdr *symtab_hdr;
+      struct elf_link_hash_entry **sym_hashes;
+      size_t nlocsyms;
+      size_t extsymoff;
+      Elf_External_Sym *locsyms, *freesyms = NULL;
+      bfd *input_bfd = sec->owner;
+
+      /* GCFIXME: how to arrange so that relocs and symbols are not
+        reread continually?  */
+
+      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+      sym_hashes = elf_sym_hashes (input_bfd);
+
+      /* Read the local symbols.  */
+      if (elf_bad_symtab (input_bfd))
+       {
+         nlocsyms = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+          extsymoff = 0;
+       }
+      else
+       extsymoff = nlocsyms = symtab_hdr->sh_info;
+      if (symtab_hdr->contents)
+       locsyms = (Elf_External_Sym *) symtab_hdr->contents;
+      else if (nlocsyms == 0)
+       locsyms = NULL;
+      else
+       {
+         locsyms = freesyms =
+           bfd_malloc (nlocsyms * sizeof (Elf_External_Sym));
+         if (freesyms == NULL
+             || bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+             || (bfd_read (locsyms, sizeof (Elf_External_Sym),
+                           nlocsyms, input_bfd)
+                 != nlocsyms * sizeof (Elf_External_Sym)))
+           {
+             ret = false;
+             goto out1;
+           }
+       }
+
+      /* Read the relocations.  */
+      relstart = (NAME(_bfd_elf,link_read_relocs)
+                 (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL,
+                  info->keep_memory));
+      if (relstart == NULL)
+       {
+         ret = false;
+         goto out1;
+       }
+      relend = relstart + sec->reloc_count;
+
+      for (rel = relstart; rel < relend; rel++)
+       {
+         unsigned long r_symndx;
+         asection *rsec;
+         struct elf_link_hash_entry *h;
+         Elf_Internal_Sym s;
+
+         r_symndx = ELF_R_SYM (rel->r_info);
+         if (r_symndx == 0)
+           continue;
+
+         if (elf_bad_symtab (sec->owner))
+           {
+             elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
+             if (ELF_ST_BIND (s.st_info) == STB_LOCAL)
+               rsec = (*gc_mark_hook)(sec->owner, info, rel, NULL, &s);
+             else
+               {
+                 h = sym_hashes[r_symndx - extsymoff];
+                 rsec = (*gc_mark_hook)(sec->owner, info, rel, h, NULL);
+               }
+           }
+         else if (r_symndx >= nlocsyms)
+           {
+             h = sym_hashes[r_symndx - extsymoff];
+             rsec = (*gc_mark_hook)(sec->owner, info, rel, h, NULL);
+           }
+         else
+           {
+             elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
+             rsec = (*gc_mark_hook)(sec->owner, info, rel, NULL, &s);
+           }
+
+         if (rsec && !rsec->gc_mark)
+           if (!elf_gc_mark (info, rsec, gc_mark_hook))
+             {
+               ret = false;
+               goto out2;
+             }
+       }
+
+    out2:
+      if (!info->keep_memory)
+       free (relstart);
+    out1:
+      if (freesyms)
+       free (freesyms);
+    }
+
+  return ret;
+}
+
+/* The sweep phase of garbage collection.  Remove all garbage sections.  */
+
+static boolean
+elf_gc_sweep (info, gc_sweep_hook)
+     struct bfd_link_info *info;
+     boolean (*gc_sweep_hook)
+       PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
+               const Elf_Internal_Rela *relocs));
+{
+  bfd *sub;
+
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *o;
+
+      for (o = sub->sections; o != NULL; o = o->next)
+       {
+         /* Keep special sections.  Keep .debug sections.  */
+         if ((o->flags & SEC_LINKER_CREATED)
+             || (o->flags & SEC_DEBUGGING))
+           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;
+
+         /* But we also have to update some of the relocation
+            info we collected before.  */
+         if (gc_sweep_hook
+             && (o->flags & SEC_RELOC) && o->reloc_count > 0)
+           {
+             Elf_Internal_Rela *internal_relocs;
+             boolean r;
+
+             internal_relocs = (NAME(_bfd_elf,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 (!info->keep_memory)
+               free (internal_relocs);
+
+             if (!r)
+               return false;
+           }
+       }
+    }
+
+  /* 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?  */
+  {
+    int i = 0;
+
+    elf_link_hash_traverse (elf_hash_table (info),
+                           elf_gc_sweep_symbol,
+                           (PTR) &i);
+
+    elf_hash_table (info)->dynsymcount = i;
+  }
+}
+
+/* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
+
+static boolean
+elf_gc_sweep_symbol (h, idxptr)
+     struct elf_link_hash_entry *h;
+     PTR idxptr;
+{
+  int *idx = (int *) idxptr;
+
+  if (h->dynindx != -1
+      && ((h->root.type != bfd_link_hash_defined
+          && h->root.type != bfd_link_hash_defweak)
+         || h->root.u.def.section->gc_mark))
+    h->dynindx = (*idx)++;
+
+  return true;
+}
+
+/* Propogate collected vtable information.  This is called through
+   elf_link_hash_traverse.  */
+
+static boolean
+elf_gc_propogate_vtable_entries_used (h, okp)
+     struct elf_link_hash_entry *h;
+     PTR okp;
+{
+  /* Those that are not vtables. */
+  if (h->vtable_parent == NULL)
+    return true;
+
+  /* Those vtables that do not have parents, we cannot merge.  */
+  if (h->vtable_parent == (struct elf_link_hash_entry *) -1)
+    return true;
+
+  /* If we've already been done, exit.  */
+  if (h->vtable_entries_used && h->vtable_entries_used[-1])
+    return true;
+
+  /* Make sure the parent's table is up to date.  */
+  elf_gc_propogate_vtable_entries_used (h->vtable_parent, okp);
+
+  if (h->vtable_entries_used == NULL)
+    {
+      /* None of this table's entries were referenced.  Re-use the
+        parent's table.  */
+      h->vtable_entries_used = h->vtable_parent->vtable_entries_used;
+    }
+  else
+    {
+      size_t n;
+      boolean *cu, *pu;
+
+      /* Or the parent's entries into ours.  */
+      cu = h->vtable_entries_used;
+      cu[-1] = true;
+      pu = h->vtable_parent->vtable_entries_used;
+      if (pu != NULL)
+       {
+         n = h->vtable_parent->size / FILE_ALIGN;
+         while (--n != 0)
+           {
+             if (*pu) *cu = true;
+             pu++, cu++;
+           }
+       }
+    }
+
+  return true;
+}
+
+static boolean
+elf_gc_smash_unused_vtentry_relocs (h, okp)
+     struct elf_link_hash_entry *h;
+     PTR okp;
+{
+  asection *sec;
+  bfd_vma hstart, hend;
+  Elf_Internal_Rela *relstart, *relend, *rel;
+
+  /* Take care of both those symbols that do not describe vtables as
+     well as those that are not loaded.  */
+  if (h->vtable_parent == NULL)
+    return true;
+
+  BFD_ASSERT (h->root.type == bfd_link_hash_defined 
+             || h->root.type == bfd_link_hash_defweak);
+
+  sec = h->root.u.def.section;
+  hstart = h->root.u.def.value;
+  hend = hstart + h->size;
+
+  relstart = (NAME(_bfd_elf,link_read_relocs)
+             (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true));
+  if (!relstart)
+    return *(boolean *)okp = false;
+  relend = relstart + sec->reloc_count;
+
+  for (rel = relstart; rel < relend; ++rel)
+    if (rel->r_offset >= hstart && rel->r_offset < hend)
+      {
+       /* If the entry is in use, do nothing.  */
+       if (h->vtable_entries_used)
+         {
+           bfd_vma entry = (rel->r_offset - hstart) / FILE_ALIGN;
+           if (h->vtable_entries_used[entry])
+             continue;
+         }
+       /* Otherwise, kill it.  */
+       rel->r_offset = rel->r_info = rel->r_addend = 0;
+      }
+
+  return true;
+}
+
+/* Do mark and sweep of unused sections.  */
+
+boolean
+elf_gc_sections (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  boolean ok = true;
+  bfd *sub;
+  asection * (*gc_mark_hook)
+    PARAMS ((bfd *abfd, struct bfd_link_info *, Elf_Internal_Rela *,
+             struct elf_link_hash_entry *h, Elf_Internal_Sym *));
+
+  if (!get_elf_backend_data (abfd)->can_gc_sections
+      || info->relocateable)
+    return true;
+
+  /* Apply transitive closure to the vtable entry usage info.  */
+  elf_link_hash_traverse (elf_hash_table (info),
+                         elf_gc_propogate_vtable_entries_used,
+                         (PTR) &ok);
+  if (!ok)
+    return false;
+
+  /* Kill the vtable relocations that were not used.  */
+  elf_link_hash_traverse (elf_hash_table (info),
+                         elf_gc_smash_unused_vtentry_relocs,
+                         (PTR) &ok);
+  if (!ok)
+    return false;
+
+  /* Grovel through relocs to find out who stays ...  */
+
+  gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *o;
+      for (o = sub->sections; o != NULL; o = o->next)
+       {
+         if (o->flags & SEC_KEEP)
+           if (!elf_gc_mark (info, o, gc_mark_hook))
+             return false;
+       }
+    }
+
+  /* ... and mark SEC_EXCLUDE for those that go.  */
+  if (!elf_gc_sweep(info, get_elf_backend_data (abfd)->gc_sweep_hook))
+    return false;
+
+  return true;
+}
+\f
+/* Called from check_relocs to record the existance of a VTINHERIT reloc.  */
+
+boolean
+elf_gc_record_vtinherit (abfd, sec, h, offset)
+     bfd *abfd;
+     asection *sec;
+     struct elf_link_hash_entry *h;
+     bfd_vma offset;
+{
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  struct elf_link_hash_entry **search, *child;
+  bfd_size_type extsymcount;
+
+  /* The sh_info field of the symtab header tells us where the
+     external symbols start.  We don't care about the local symbols at
+     this point.  */
+  extsymcount = elf_tdata (abfd)->symtab_hdr.sh_size/sizeof (Elf_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    extsymcount -= elf_tdata (abfd)->symtab_hdr.sh_info;
+
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + extsymcount;
+
+  /* Hunt down the child symbol, which is in this section at the same
+     offset as the relocation.  */
+  for (search = sym_hashes; search != sym_hashes_end; ++search)
+    {
+      if ((child = *search) != NULL
+         && (child->root.type == bfd_link_hash_defined
+             || child->root.type == bfd_link_hash_defweak)
+         && child->root.u.def.section == sec
+         && child->root.u.def.value == offset)
+       goto win;
+    }
+
+  (*_bfd_error_handler) ("%s: %s+%lu: No symbol found for INHERIT",
+                        bfd_get_filename (abfd), sec->name,
+                        (unsigned long)offset);
+  bfd_set_error (bfd_error_invalid_operation);
+  return false;
+
+win:
+  if (!h)
+    {
+      /* This *should* only be the absolute section.  It could potentially
+        be that someone has defined a non-global vtable though, which
+        would be bad.  It isn't worth paging in the local symbols to be
+        sure though; that case should simply be handled by the assembler.  */
+
+      child->vtable_parent = (struct elf_link_hash_entry *) -1;
+    }
+  else
+    child->vtable_parent = h;
+
+  return true;
+}
+
+/* Called from check_relocs to record the existance of a VTENTRY reloc.  */
+
+boolean
+elf_gc_record_vtentry (abfd, sec, h, addend)
+     bfd *abfd;
+     asection *sec;
+     struct elf_link_hash_entry *h;
+     bfd_vma addend;
+{
+  if (h->vtable_entries_used == NULL)
+    {
+      /* Allocate one extra entry for use as a "done" flag for the
+        consolidation pass.  */
+      size_t size = (h->size / FILE_ALIGN + 1) * sizeof(boolean);
+      h->vtable_entries_used = (boolean *) bfd_alloc (abfd, size);
+      if (h->vtable_entries_used == NULL)
+       return false;
+
+      /* And arrange for that done flag to be at index -1.  */
+      memset (h->vtable_entries_used++, 0, size);
+    }
+  h->vtable_entries_used[addend / FILE_ALIGN] = true;
+
+  return true;
+}
+
+/* And an accompanying bit to work out final got entry offsets once 
+   we're done.  Should be called from final_link.  */
+
+boolean
+elf_gc_common_finalize_got_offsets (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      bfd *i;
+      bfd_vma off[2], gotoff = 0;
+
+      /* Do the local .got entries first.  */
+      for (i = info->input_bfds; i; i = i->link_next)
+       {
+         bfd_signed_vma *local_got = elf_local_got_refcounts (i);
+         bfd_size_type j, locsymcount;
+         Elf_Internal_Shdr *symtab_hdr;
+
+         if (!local_got)
+           continue;
+
+         symtab_hdr = &elf_tdata (i)->symtab_hdr;
+         if (elf_bad_symtab (i))
+           locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+         else
+           locsymcount = symtab_hdr->sh_info;
+
+         for (j = 0; j < locsymcount; ++j)
+           local_got[j] = (local_got[j] > 0 ? gotoff++ : (bfd_vma) - 1);
+       }
+
+      /* Then the global .got and .plt entries.  */
+      off[0] = gotoff;
+      off[1] = 0;
+      elf_link_hash_traverse (elf_hash_table (info),
+                             elf_gc_allocate_got_offsets,
+                             (PTR) off);
+    }
+
+  return true;
+}
+
+/* We need a special top-level link routine to convert got reference counts
+   to real got offsets.  */
+
+static boolean
+elf_gc_allocate_got_offsets (h, offarg)
+     struct elf_link_hash_entry *h;
+     PTR offarg;
+{
+  bfd_vma *off = (bfd_vma *) offarg;
+
+  h->got.offset = (h->got.refcount > 0 ? off[0]++ : (bfd_vma) - 1);
+
+  return true;
+}
+
+/* Many folk need no more in the way of final link than this, once
+   got entry reference counting is enabled.  */
+
+boolean
+elf_gc_common_final_link (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  if (!elf_gc_common_finalize_got_offsets (abfd, info))
+    return false;
+
+  /* Invoke the regular ELF backend linker to do all the work.  */
+  return elf_bfd_final_link (abfd, info);
+}
index 578e603..48bde0c 100644 (file)
@@ -105,6 +105,8 @@ static bfd_byte *evax_bfd_get_relocated_section_contents
 static boolean evax_bfd_relax_section
   PARAMS ((bfd *abfd, asection *section, struct bfd_link_info *link_info,
           boolean *again));
+static boolean evax_bfd_gc_sections
+  PARAMS ((bfd *abfd, struct bfd_link_info *link_info));
 static struct bfd_link_hash_table *evax_bfd_link_hash_table_create
   PARAMS ((bfd *abfd));
 static boolean evax_bfd_link_add_symbols
@@ -1657,6 +1659,18 @@ evax_bfd_relax_section (abfd, section, link_info, again)
   return true;
 }
 
+static boolean
+evax_bfd_gc_sections (abfd, link_info)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+     const char *entry;
+{
+#if EVAX_DEBUG
+  evax_debug (1, "evax_bfd_gc_sections(%p, %p)\n", abfd, link_info);
+#endif
+  return true;
+}
+
 
 /* Create a hash table for the linker.  Different backends store
    different information in this table.  */
index 66db403..c2a022b 100644 (file)
@@ -1,5 +1,7 @@
 /* BFD back-end for ieee-695 objects.
-   Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+   Free Software Foundation, Inc.
+
    Written by Steve Chamberlain of Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -30,6 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "ieee.h"
 #include "libieee.h"
 
+#include <ctype.h>
+
 static boolean ieee_write_byte PARAMS ((bfd *, int));
 static boolean ieee_write_2bytes PARAMS ((bfd *, int));
 static boolean ieee_write_int PARAMS ((bfd *, bfd_vma));
@@ -160,7 +164,7 @@ ieee_write_id (abfd, id)
   else
     {
       (*_bfd_error_handler)
-       ("%s: string too long (%d chars, max 65535)",
+       (_("%s: string too long (%d chars, max 65535)"),
         bfd_get_filename (abfd), length);
       bfd_set_error (bfd_error_invalid_operation);
       return false;
@@ -290,7 +294,7 @@ ieee_write_expression (abfd, value, symbol, pcrel, index)
       else
        {
          (*_bfd_error_handler)
-           ("%s: unrecognized symbol `%s' flags 0x%x",
+           (_("%s: unrecognized symbol `%s' flags 0x%x"),
             bfd_get_filename (abfd), bfd_asymbol_name (symbol),
             symbol->flags);
          bfd_set_error (bfd_error_invalid_operation);
@@ -786,7 +790,7 @@ ieee_slurp_external_symbols (abfd)
                    break;
                  default:
                    (*_bfd_error_handler)
-                     ("%s: unimplemented ATI record  %u for symbol %u",
+                     (_("%s: unimplemented ATI record  %u for symbol %u"),
                       bfd_get_filename (abfd), symbol_attribute_def,
                       symbol_name_index);
                    bfd_set_error (bfd_error_bad_value);
@@ -1239,15 +1243,18 @@ ieee_archive_p (abfd)
      bfd *abfd;
 {
   char *library;
-  boolean loop;
   unsigned int i;
   unsigned char buffer[512];
   file_ptr buffer_offset = 0;
   ieee_ar_data_type *save = abfd->tdata.ieee_ar_data;
   ieee_ar_data_type *ieee;
-  abfd->tdata.ieee_ar_data = (ieee_ar_data_type *) bfd_alloc (abfd, sizeof (ieee_ar_data_type));
+  unsigned int alc_elts;
+  ieee_ar_obstack_type *elts = NULL;
+
+  abfd->tdata.ieee_ar_data =
+    (ieee_ar_data_type *) bfd_alloc (abfd, sizeof (ieee_ar_data_type));
   if (!abfd->tdata.ieee_ar_data)
-    return NULL;
+    goto error_return;
   ieee = IEEE_AR_DATA (abfd);
 
   /* FIXME: Check return value.  I'm not sure whether it needs to read
@@ -1262,7 +1269,7 @@ ieee_archive_p (abfd)
   if (this_byte (&(ieee->h)) != Module_Beginning)
     {
       abfd->tdata.ieee_ar_data = save;
-      return (const bfd_target *) NULL;
+      goto error_return;
     }
 
   next_byte (&(ieee->h));
@@ -1271,7 +1278,7 @@ ieee_archive_p (abfd)
     {
       bfd_release (abfd, ieee);
       abfd->tdata.ieee_ar_data = save;
-      return (const bfd_target *) NULL;
+      goto error_return;
     }
   /* Throw away the filename */
   read_id (&(ieee->h));
@@ -1283,43 +1290,65 @@ ieee_archive_p (abfd)
   must_parse_int (&(ieee->h)); /* And the two dummy numbers */
   must_parse_int (&(ieee->h));
 
-  loop = true;
+  alc_elts = 10;
+  elts = (ieee_ar_obstack_type *) bfd_malloc (alc_elts * sizeof *elts);
+  if (elts == NULL)
+    goto error_return;
+
   /* Read the index of the BB table */
-  while (loop)
+  while (1)
     {
-      ieee_ar_obstack_type t;
-      int rec = read_2bytes (&(ieee->h));
-      if (rec == (int) ieee_assign_value_to_variable_enum)
+      int rec;
+      ieee_ar_obstack_type *t;
+
+      rec = read_2bytes (&(ieee->h));
+      if (rec != (int) ieee_assign_value_to_variable_enum)
+       break;
+
+      if (ieee->element_count >= alc_elts)
        {
-         must_parse_int (&(ieee->h));
-         t.file_offset = must_parse_int (&(ieee->h));
-         t.abfd = (bfd *) NULL;
-         ieee->element_count++;
+         ieee_ar_obstack_type *n;
+
+         alc_elts *= 2;
+         n = ((ieee_ar_obstack_type *)
+              bfd_realloc (elts, alc_elts * sizeof *elts));
+         if (n == NULL)
+           goto error_return;
+         elts = n;
+       }
 
-         bfd_alloc_grow (abfd, (PTR) &t, sizeof t);
+      t = &elts[ieee->element_count];
+      ieee->element_count++;
 
-         /* Make sure that we don't go over the end of the buffer */
+      must_parse_int (&(ieee->h));
+      t->file_offset = must_parse_int (&(ieee->h));
+      t->abfd = (bfd *) NULL;
 
-         if ((size_t) ieee_pos (abfd) > sizeof (buffer) / 2)
-           {
-             /* Past half way, reseek and reprime */
-             buffer_offset += ieee_pos (abfd);
-             if (bfd_seek (abfd, buffer_offset, SEEK_SET) != 0)
-               return NULL;
-             /* FIXME: Check return value.  I'm not sure whether it
-                needs to read the entire buffer or not.  */
-             bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
-             ieee->h.first_byte = buffer;
-             ieee->h.input_p = buffer;
-           }
+      /* Make sure that we don't go over the end of the buffer */
+
+      if ((size_t) ieee_pos (abfd) > sizeof (buffer) / 2)
+       {
+         /* Past half way, reseek and reprime */
+         buffer_offset += ieee_pos (abfd);
+         if (bfd_seek (abfd, buffer_offset, SEEK_SET) != 0)
+           goto error_return;
+         /* FIXME: Check return value.  I'm not sure whether it needs
+            to read the entire buffer or not.  */
+         bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
+         ieee->h.first_byte = buffer;
+         ieee->h.input_p = buffer;
        }
-      else
-       loop = false;
     }
 
-  ieee->elements = (ieee_ar_obstack_type *) bfd_alloc_finish (abfd);
-  if (!ieee->elements)
-    return (const bfd_target *) NULL;
+  ieee->elements = ((ieee_ar_obstack_type *)
+                   bfd_alloc (abfd,
+                              ieee->element_count * sizeof *ieee->elements));
+  if (ieee->elements == NULL)
+    goto error_return;
+  memcpy (ieee->elements, elts,
+         ieee->element_count * sizeof *ieee->elements);
+  free (elts);
+  elts = NULL;
 
   /* Now scan the area again, and replace BB offsets with file */
   /* offsets */
@@ -1327,7 +1356,7 @@ ieee_archive_p (abfd)
   for (i = 2; i < ieee->element_count; i++)
     {
       if (bfd_seek (abfd, ieee->elements[i].file_offset, SEEK_SET) != 0)
-       return NULL;
+       goto error_return;
       /* FIXME: Check return value.  I'm not sure whether it needs to
         read the entire buffer or not.  */
       bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
@@ -1348,8 +1377,14 @@ ieee_archive_p (abfd)
        }
     }
 
-/*  abfd->has_armap = ;*/
+  /*  abfd->has_armap = ;*/
+
   return abfd->xvec;
+
+ error_return:
+  if (elts != NULL)
+    free (elts);
+  return NULL;
 }
 
 static boolean
@@ -1407,7 +1442,70 @@ ieee_object_p (abfd)
   /* Determine the architecture and machine type of the object file.
      */
   {
-    const bfd_arch_info_type *arch = bfd_scan_arch (processor);
+    const bfd_arch_info_type *arch;
+    char family[10];
+
+    /* IEEE does not specify the format of the processor identificaton
+       string, so the compiler is free to put in it whatever it wants.
+       We try here to recognize different processors belonging to the
+       m68k family.  Code for other processors can be added here.  */
+    if ((processor[0] == '6') && (processor[1] == '8'))
+      {
+       if (processor[2] == '3')            /* 683xx integrated processors */
+         {
+           switch (processor[3])
+             {
+             case '0':                     /* 68302, 68306, 68307 */
+             case '2':                     /* 68322, 68328 */
+             case '5':                     /* 68356 */
+               strcpy (family, "68000");   /* MC68000-based controllers */
+               break;
+
+             case '3':                     /* 68330, 68331, 68332, 68333,
+                                              68334, 68335, 68336, 68338 */
+             case '6':                     /* 68360 */
+             case '7':                     /* 68376 */
+               strcpy (family, "68332");   /* CPU32 and CPU32+ */
+               break;
+
+             case '4':
+               if (processor[4] == '9')    /* 68349 */
+                 strcpy (family, "68030"); /* CPU030 */
+               else                        /* 68340, 68341 */
+                 strcpy (family, "68332"); /* CPU32 and CPU32+ */
+               break;
+
+             default:                      /* Does not exist yet */
+               strcpy (family, "68332");   /* Guess it will be CPU32 */
+             }
+         }
+       else if (toupper (processor[3]) == 'F')   /* 68F333 */
+         strcpy (family, "68332");               /* CPU32 */
+       else if ((toupper (processor[3]) == 'C')  /* Embedded controllers */
+                && ((toupper (processor[2]) == 'E')
+                    || (toupper (processor[2]) == 'H')
+                    || (toupper (processor[2]) == 'L')))
+         {
+           strcpy (family, "68");
+           strncat (family, processor + 4, 7);
+           family[9] = '\0';
+         }
+       else                             /* "Regular" processors */
+         {
+           strncpy (family, processor, 9);
+           family[9] = '\0';
+         }
+      }
+    else if ((strncmp (processor, "cpu32", 5) == 0) /* CPU32 and CPU32+ */
+            || (strncmp (processor, "CPU32", 5) == 0))
+      strcpy (family, "68332");
+    else
+      {
+       strncpy (family, processor, 9);
+       family[9] = '\0';
+      }
+
+    arch = bfd_scan_arch (family);
     if (arch == 0)
       goto got_wrong_format;
     abfd->arch_info = arch;
@@ -1613,10 +1711,8 @@ do_one (ieee, current_map, location_ptr, s, iterations)
                  s->flags |= SEC_RELOC;
                  s->owner->flags |= HAS_RELOC;
                  s->reloc_count++;
-                 if (r->relent.sym_ptr_ptr == 0)
-                   {
-                     r->relent.sym_ptr_ptr = section->symbol_ptr_ptr;
-                   }
+                 if (r->relent.sym_ptr_ptr == NULL && section != NULL)
+                   r->relent.sym_ptr_ptr = section->symbol_ptr_ptr;
 
                  if (this_byte (&(ieee->h)) == (int) ieee_comma)
                    {
@@ -1954,8 +2050,9 @@ ieee_canonicalize_reloc (abfd, section, relptr, symbols)
            symbols + src->symbol.index + ieee->external_reference_base_offset;
          break;
        case 0:
-         src->relent.sym_ptr_ptr =
-           src->relent.sym_ptr_ptr[0]->section->symbol_ptr_ptr;
+         if (src->relent.sym_ptr_ptr != NULL)
+           src->relent.sym_ptr_ptr =
+             src->relent.sym_ptr_ptr[0]->section->symbol_ptr_ptr;
          break;
        default:
 
@@ -3609,9 +3706,11 @@ ieee_generic_stat_arch_elt (abfd, buf)
      bfd *abfd;
      struct stat *buf;
 {
-  ieee_ar_data_type *ar = abfd->my_archive->tdata.ieee_ar_data;
+  ieee_ar_data_type *ar = (ieee_ar_data_type *) NULL;
   ieee_data_type *ieee;
 
+  if (abfd->my_archive != NULL)
+    ar = abfd->my_archive->tdata.ieee_ar_data;
   if (ar == (ieee_ar_data_type *) NULL)
     {
       bfd_set_error (bfd_error_invalid_operation);
@@ -3724,7 +3823,7 @@ ieee_bfd_debug_info_accumulate (abfd, section)
 #define ieee_update_armap_timestamp bfd_true
 #define ieee_get_elt_at_index _bfd_generic_get_elt_at_index
 
-#define ieee_bfd_is_local_label bfd_generic_is_local_label
+#define ieee_bfd_is_local_label_name bfd_generic_is_local_label_name
 #define ieee_get_lineno _bfd_nosymbols_get_lineno
 #define ieee_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
 #define ieee_read_minisymbols _bfd_generic_read_minisymbols
@@ -3739,6 +3838,7 @@ ieee_bfd_debug_info_accumulate (abfd, section)
 #define ieee_bfd_get_relocated_section_contents \
   bfd_generic_get_relocated_section_contents
 #define ieee_bfd_relax_section bfd_generic_relax_section
+#define ieee_bfd_gc_sections bfd_generic_gc_sections
 #define ieee_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
 #define ieee_bfd_link_add_symbols _bfd_generic_link_add_symbols
 #define ieee_bfd_final_link _bfd_generic_final_link
index 8b4504c..277f4c4 100644 (file)
@@ -23,31 +23,6 @@ You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#ifdef ENABLE_NLS
-#include <libintl.h>
-/*  FIXME: We might want to use dgettext instead, in some cases.
-    This is still under investigation.  */
-#define _(String) gettext (String)
-#ifdef gettext_noop
-#define N_(String) gettext_noop (String)
-#else
-#define N_(String) (String)
-#endif
-#else
-/* Stubs that do something close enough.  */
-#define textdomain(String) (String)
-#define gettext(String) (String)
-#define dgettext(Domain,Message) (Message)
-#define dcgettext(Domain,Message,Type) (Message)
-#define bindtextdomain(Domain,Directory) (Domain)
-#define _(String) (String)
-#define N_(String) (String)
-/* In this case we don't care about the value.  */
-#ifndef LC_MESSAGES
-#define LC_MESSAGES 0
-#endif
-#endif
-
 /* Align an address upward to a boundary, expressed as a number of bytes.
    E.g. align to an 8-byte boundary with argument of 8.  Take care never
    to wrap around if the address is within boundary-1 of the end of the
@@ -342,6 +317,10 @@ extern boolean _bfd_generic_set_section_contents
   ((boolean (*) \
     PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *))) \
    bfd_false)
+#define _bfd_nolink_bfd_gc_sections \
+  ((boolean (*) \
+    PARAMS ((struct bfd_link_info *))) \
+   bfd_false)
 #define _bfd_nolink_bfd_link_hash_table_create \
   ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr)
 #define _bfd_nolink_bfd_link_add_symbols \
@@ -670,6 +649,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_SPARC_M44",
   "BFD_RELOC_SPARC_L44",
   "BFD_RELOC_SPARC_REGISTER",
+  "BFD_RELOC_SPARC_32LE",
   "BFD_RELOC_ALPHA_GPDISP_HI16",
   "BFD_RELOC_ALPHA_GPDISP_LO16",
   "BFD_RELOC_ALPHA_GPDISP",
@@ -842,6 +822,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MN10300_32_PCREL",
   "BFD_RELOC_MN10300_16_PCREL",
   "BFD_RELOC_TIC30_LDP",
+  "BFD_RELOC_VTABLE_INHERIT",
+  "BFD_RELOC_VTABLE_ENTRY",
  "@@overflow: BFD_RELOC_UNUSED@@",
 };
 #endif
@@ -857,6 +839,10 @@ bfd_generic_relax_section
     struct bfd_link_info *,
     boolean *));
 
+boolean 
+bfd_generic_gc_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+
 bfd_byte *
 
 bfd_generic_get_relocated_section_contents  PARAMS ((bfd *abfd,
index 1bdf307..39a3214 100644 (file)
@@ -1869,6 +1869,11 @@ ENUMDOC
   SPARC64 relocations
 
 ENUM
+  BFD_RELOC_SPARC_32LE
+ENUMDOC
+  SPARC little endian relocation
+
+ENUM
   BFD_RELOC_ALPHA_GPDISP_HI16
 ENUMDOC
   Alpha ECOFF and ELF relocations.  Some of these treat the symbol or
@@ -2477,6 +2482,29 @@ ENUMDOC
   significant 8 bits of a 24 bit word are placed into the least
   significant 8 bits of the opcode.
 
+ENUM
+  BFD_RELOC_VTABLE_INHERIT
+ENUMX
+  BFD_RELOC_VTABLE_ENTRY
+ENUMDOC
+  These two relocations are used by the linker to determine which of 
+  the entries in a C++ virtual function table are actually used.  When
+  the --gc-sections option is given, the linker will zero out the entries
+  that are not used, so that the code for those functions need not be
+  included in the output.
+
+  VTABLE_INHERIT is a zero-space relocation used to describe to the
+  linker the inheritence tree of a C++ virtual function table.  The
+  relocation's symbol should be the parent class' vtable, and the
+  relocation should be located at the child vtable.
+
+  VTABLE_ENTRY is a zero-space relocation that describes the use of a
+  virtual function table entry.  The reloc's symbol should refer to the
+  table of the class mentioned in the code.  Off of that base, an offset
+  describes the entry that is being used.  For Rela hosts, this offset 
+  is stored in the reloc's addend.  For Rel hosts, we are forced to put
+  this offset in the reloc's section offset.
+
 ENDSENUM
   BFD_RELOC_UNUSED
 CODE_FRAGMENT
@@ -2605,6 +2633,28 @@ bfd_generic_relax_section (abfd, section, link_info, again)
 
 /*
 INTERNAL_FUNCTION
+       bfd_generic_gc_sections
+
+SYNOPSIS
+       boolean bfd_generic_gc_sections
+        (bfd *, struct bfd_link_info *);
+
+DESCRIPTION
+       Provides default handling for relaxing for back ends which
+       don't do section gc -- i.e., does nothing.
+*/
+
+/*ARGSUSED*/
+boolean
+bfd_generic_gc_sections (abfd, link_info)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+{
+  return true;
+}
+
+/*
+INTERNAL_FUNCTION
        bfd_generic_get_relocated_section_contents
 
 SYNOPSIS
index 564a51e..55a09f9 100644 (file)
@@ -1,5 +1,6 @@
 /* Object file "section" support for the BFD library.
-   Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 1997
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -214,7 +215,7 @@ CODE_FRAGMENT
 .           standard data. *}
 .#define SEC_CONSTRUCTOR 0x100
 .
-.        {* The section is a constuctor, and should be placed at the
+.        {* The section is a constructor, and should be placed at the
 .          end of the text, data, or bss section(?). *}
 .#define SEC_CONSTRUCTOR_TEXT 0x1100
 .#define SEC_CONSTRUCTOR_DATA 0x2100
@@ -303,6 +304,9 @@ CODE_FRAGMENT
 .         else up the line will take care of it later.  *}
 .#define SEC_LINKER_CREATED 0x800000
 .
+.      {* This section should not be subject to garbage collection.  *}
+.#define SEC_KEEP 0x1000000
+.
 .      {*  End of section flags.  *}
 .
 .      {* Some internal packed boolean fields.  *}
@@ -316,6 +320,9 @@ CODE_FRAGMENT
 .      {* A mark flag used by some of the linker backends.  *}
 .      unsigned int linker_mark : 1;
 .
+.      {* A mark flag used by some linker backends for garbage collection.  *}
+.      unsigned int gc_mark : 1;
+.
 .      {* End of internal packed boolean fields.  *}
 .
 .       {*  The virtual memory address of the section - where it will be
@@ -558,7 +565,7 @@ DESCRIPTION
        o <<bfd_error_invalid_operation>> -
        If output has already started for this BFD.
        o <<bfd_error_no_memory>> -
-       If obstack alloc fails.
+       If memory allocation fails.
 
 */
 
@@ -590,7 +597,7 @@ DESCRIPTION
 
    Return <<NULL>> and set <<bfd_error>> on error; possible errors are:
    o <<bfd_error_invalid_operation>> - If output has already started for @var{abfd}.
-   o <<bfd_error_no_memory>> - If obstack alloc fails.
+   o <<bfd_error_no_memory>> - If memory allocation fails.
 */
 
 sec_ptr
index 65a2165..e0ba35a 100644 (file)
@@ -1,5 +1,6 @@
 /* Generic target-file-type support for the BFD library.
-   Copyright 1990, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -412,7 +413,8 @@ The general target vector.
 .CAT(NAME,_bfd_link_hash_table_create),\
 .CAT(NAME,_bfd_link_add_symbols),\
 .CAT(NAME,_bfd_final_link),\
-.CAT(NAME,_bfd_link_split_section)
+.CAT(NAME,_bfd_link_split_section),\
+.CAT(NAME,_bfd_gc_sections)
 .  int        (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean));
 .  bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *,
 .                    struct bfd_link_info *, struct bfd_link_order *,
@@ -436,7 +438,10 @@ The general target vector.
 .  {* Should this section be split up into smaller pieces during linking.  *}
 .  boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *));
 .
-. {* Routines to handle dynamic symbols and relocs.  *}
+.  {* Remove sections that are not referenced from the output.  *}
+.  boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *));
+.
+.  {* Routines to handle dynamic symbols and relocs.  *}
 .#define BFD_JUMP_TABLE_DYNAMIC(NAME)\
 .CAT(NAME,_get_dynamic_symtab_upper_bound),\
 .CAT(NAME,_canonicalize_dynamic_symtab),\
@@ -588,6 +593,7 @@ extern const bfd_target tic30_coff_vec;
 /* start-sanitize-tic80 */
 extern const bfd_target tic80coff_vec;
 /* end-sanitize-tic80 */
+extern const bfd_target vaxnetbsd_vec;
 extern const bfd_target versados_vec;
 extern const bfd_target we32kcoff_vec;
 extern const bfd_target w65_vec;
@@ -674,6 +680,7 @@ const bfd_target * const bfd_target_vector[] = {
        &bfd_elf32_m88k_vec,
        &bfd_elf32_sparc_vec,
        &bfd_elf32_powerpc_vec,
+       &bfd_elf32_powerpcle_vec,
        &bfd_elf32_v850_vec,
 #ifdef BFD64                   /* No one seems to use this.  */
        &bfd_elf64_big_generic_vec,
@@ -803,8 +810,9 @@ const bfd_target * const bfd_target_vector[] = {
 /* start-sanitize-tic80 */
        &tic80coff_vec,
 /* end-sanitize-tic80 */
-       &we32kcoff_vec,
+       &vaxnetbsd_vec,
        &versados_vec,
+       &we32kcoff_vec,
        &z8kcoff_vec,
 
 #endif /* not SELECT_VECS */
@@ -833,6 +841,9 @@ const bfd_target * const bfd_target_vector[] = {
 #ifdef IRIX_CORE
        &irix_core_vec,
 #endif
+#ifdef NETBSD_CORE
+       &netbsd_core_vec,
+#endif
 #ifdef OSF_CORE
        &osf_core_vec,
 #endif