Merge some FRV FDPIC changes into the Blackfin code.
authorBernd Schmidt <bernds@codesourcery.com>
Tue, 11 Aug 2009 11:41:17 +0000 (11:41 +0000)
committerBernd Schmidt <bernds@codesourcery.com>
Tue, 11 Aug 2009 11:41:17 +0000 (11:41 +0000)
* elf32-bfin.c (struct bfinfdpic_elf_link_hash_table): Add pointer to
summary reloc information.
(bfinfdpic_dynamic_got_plt_info): New.
(_bfin_create_got_section): Create the PLT section here.
(elf32_bfinfdpic_create_dynamic_sections): Not here.
(_bfinfdpic_count_nontls_entries): Move out of...
(_bfinfdpic_count_got_plt_entries): ... here.
(_bfinfdpic_count_relocs_fixups): Likewise.
(_bfinfdpic_reset_got_plt_entries): New.
(_bfinfdpic_size_got_plt): Move out of...
(elf32_bfinfdpic_size_dynamic_sections): ... here.
(bfinfdpic_relocate_section): Be careful not to call
_bfinfdpic_add_rofixup or _bfinfdpic_add_dyn_reloc for deleted relocs.
(bfinfdpic_check_discarded_relocs, bfinfdpic_elf_discard_info):
New functions.
(elf_backend_discard_info): Define for FD-PIC.

bfd/ChangeLog
bfd/elf32-bfin.c

index be52aa6..335731e 100644 (file)
@@ -1,3 +1,23 @@
+2009-08-11  Bernd Schmidt  <bernd.schmidt@analog.com>
+
+       Merge some FRV FDPIC changes into the Blackfin code.
+       * elf32-bfin.c (struct bfinfdpic_elf_link_hash_table): Add pointer to
+       summary reloc information.
+       (bfinfdpic_dynamic_got_plt_info): New.
+       (_bfin_create_got_section): Create the PLT section here.
+       (elf32_bfinfdpic_create_dynamic_sections): Not here.
+       (_bfinfdpic_count_nontls_entries): Move out of...
+       (_bfinfdpic_count_got_plt_entries): ... here.
+       (_bfinfdpic_count_relocs_fixups): Likewise.
+       (_bfinfdpic_reset_got_plt_entries): New.
+       (_bfinfdpic_size_got_plt): Move out of...
+       (elf32_bfinfdpic_size_dynamic_sections): ... here.
+       (bfinfdpic_relocate_section): Be careful not to call
+       _bfinfdpic_add_rofixup or _bfinfdpic_add_dyn_reloc for deleted relocs.
+       (bfinfdpic_check_discarded_relocs, bfinfdpic_elf_discard_info):
+       New functions.
+       (elf_backend_discard_info): Define for FD-PIC.
+
 2009-08-11  Alan Modra  <amodra@bigpond.net.au>
 
        * elflink.c: Add FIXMEs for some places that require octets_per_byte
@@ -69,7 +89,7 @@
        (ppc_elf_size_dynamic_sections): Likewise.
        (ppc_elf_relocate_section): Likewise.
 
-2006-08-09  Bernd Schmidt  <bernd.schmidt@analog.com>
+2009-08-09  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        From Mike Frysinger <michael.frysinger@analog.com>
        * elf32-bfin.c (bfin_howto_table, bfin_reloc_map, bfin_check_relocs,
index 3752d52..3eb7499 100644 (file)
@@ -1740,6 +1740,9 @@ struct bfinfdpic_elf_link_hash_table
   /* A hash table holding information about which symbols were
      referenced with which PIC-related relocations.  */
   struct htab *relocs_info;
+  /* Summary reloc information collected by
+     _bfinfdpic_count_got_plt_entries.  */
+  struct _bfinfdpic_dynamic_got_info *g;
 };
 
 /* Get the Blackfin ELF linker hash table from a link_info structure.  */
@@ -1763,6 +1766,8 @@ struct bfinfdpic_elf_link_hash_table
   (bfinfdpic_hash_table (info)->got0)
 #define bfinfdpic_plt_initial_offset(info) \
   (bfinfdpic_hash_table (info)->plt0)
+#define bfinfdpic_dynamic_got_plt_info(info) \
+  (bfinfdpic_hash_table (info)->g)
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -2149,7 +2154,8 @@ _bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
        dynindx = entry->d.h->dynindx;
       else
        {
-         if (sec->output_section
+         if (sec
+             && sec->output_section
              && ! bfd_is_abs_section (sec->output_section)
              && ! bfd_is_und_section (sec->output_section))
            dynindx = elf_section_data (sec->output_section)->dynindx;
@@ -2417,8 +2423,9 @@ _bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
             of the section.  For a non-local function, it's
             disregarded.  */
          lowword = ad;
-         if (entry->symndx == -1 && entry->d.h->dynindx != -1
-             && entry->d.h->dynindx == idx)
+         if (sec == NULL
+             || (entry->symndx == -1 && entry->d.h->dynindx != -1
+                 && entry->d.h->dynindx == idx))
            highword = 0;
          else
            highword = _bfinfdpic_osec_to_segment
@@ -2843,6 +2850,8 @@ bfinfdpic_relocate_section (bfd * output_bfd,
                if (info->executable && !info->pie
                    && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
                  {
+                   bfd_vma offset;
+
                    addend += bfinfdpic_got_section (info)->output_section->vma;
                    if ((bfd_get_section_flags (output_bfd,
                                                input_section->output_section)
@@ -2858,16 +2867,19 @@ bfinfdpic_relocate_section (bfd * output_bfd,
                               name, input_bfd, input_section, rel->r_offset);
                            return FALSE;
                          }
-                       _bfinfdpic_add_rofixup (output_bfd,
-                                              bfinfdpic_gotfixup_section
-                                              (info),
-                                              _bfd_elf_section_offset
-                                              (output_bfd, info,
-                                               input_section, rel->r_offset)
-                                              + input_section
-                                              ->output_section->vma
-                                              + input_section->output_offset,
-                                              picrel);
+
+                       offset = _bfd_elf_section_offset
+                         (output_bfd, info,
+                          input_section, rel->r_offset);
+
+                       if (offset != (bfd_vma)-1)
+                         _bfinfdpic_add_rofixup (output_bfd,
+                                                 bfinfdpic_gotfixup_section
+                                                 (info),
+                                                 offset + input_section
+                                                 ->output_section->vma
+                                                 + input_section->output_offset,
+                                                 picrel);
                      }
                  }
                else if ((bfd_get_section_flags (output_bfd,
@@ -2888,14 +2900,8 @@ bfinfdpic_relocate_section (bfd * output_bfd,
                      }
                    offset = _bfd_elf_section_offset (output_bfd, info,
                                                      input_section, rel->r_offset);
-                   /* Only output a reloc for a not deleted entry.  */
-                   if (offset >= (bfd_vma) -2)
-                     _bfinfdpic_add_dyn_reloc (output_bfd,
-                                               bfinfdpic_gotrel_section (info),
-                                               0,
-                                               R_BFIN_UNUSED0,
-                                               dynindx, addend, picrel);
-                   else
+
+                   if (offset != (bfd_vma)-1)
                      _bfinfdpic_add_dyn_reloc (output_bfd,
                                                bfinfdpic_gotrel_section (info),
                                                offset + input_section
@@ -2986,28 +2992,17 @@ bfinfdpic_relocate_section (bfd * output_bfd,
                      }
                    if (!h || h->root.type != bfd_link_hash_undefweak)
                      {
-                       /* Only output a reloc for a not deleted entry.  */
-                       if (offset >= (bfd_vma)-2)
-                         _bfinfdpic_add_rofixup (output_bfd,
-                                                 bfinfdpic_gotfixup_section
-                                                 (info), -1, picrel);
-                       else
-                         _bfinfdpic_add_rofixup (output_bfd,
-                                                 bfinfdpic_gotfixup_section
-                                                 (info),
-                                                 offset + input_section
-                                                 ->output_section->vma
-                                                 + input_section->output_offset,
-                                                 picrel);
-
-                       if (r_type == R_BFIN_FUNCDESC_VALUE)
+                       if (offset != (bfd_vma)-1)
                          {
-                           if (offset >= (bfd_vma)-2)
-                             _bfinfdpic_add_rofixup
-                               (output_bfd,
-                                bfinfdpic_gotfixup_section (info),
-                                -1, picrel);
-                           else
+                           _bfinfdpic_add_rofixup (output_bfd,
+                                                   bfinfdpic_gotfixup_section
+                                                   (info),
+                                                   offset + input_section
+                                                   ->output_section->vma
+                                                   + input_section->output_offset,
+                                                   picrel);
+
+                           if (r_type == R_BFIN_FUNCDESC_VALUE)
                              _bfinfdpic_add_rofixup
                                (output_bfd,
                                 bfinfdpic_gotfixup_section (info),
@@ -3033,17 +3028,12 @@ bfinfdpic_relocate_section (bfd * output_bfd,
                           name, input_bfd, input_section, rel->r_offset);
                        return FALSE;
                      }
-                   /* Only output a reloc for a not deleted entry.  */
-                   if (offset >= (bfd_vma)-2)
-                     _bfinfdpic_add_dyn_reloc (output_bfd,
-                                               bfinfdpic_gotrel_section (info),
-                                               0, R_BFIN_UNUSED0, dynindx, addend, picrel);
-                   else
+
+                   if (offset != (bfd_vma)-1)
                      _bfinfdpic_add_dyn_reloc (output_bfd,
                                                bfinfdpic_gotrel_section (info),
                                                offset
-                                               + input_section
-                                               ->output_section->vma
+                                               + input_section->output_section->vma
                                                + input_section->output_offset,
                                                r_type, dynindx, addend, picrel);
                  }
@@ -3055,7 +3045,7 @@ bfinfdpic_relocate_section (bfd * output_bfd,
                relocation = addend - rel->r_addend;
              }
 
-           if (r_type == R_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2)
+           if (r_type == R_BFIN_FUNCDESC_VALUE)
              {
                /* If we've omitted the dynamic relocation, just emit
                   the fixed addresses of the symbol and of the local
@@ -3469,28 +3459,7 @@ _bfin_create_got_section (bfd *abfd, struct bfd_link_info *info)
       flags = BSF_GLOBAL | BSF_WEAK;
     }
 
-  return TRUE;
-}
-
-/* Make sure the got and plt sections exist, and that our pointers in
-   the link hash table point to them.  */
-
-static bfd_boolean
-elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
-{
-  /* This is mostly copied from
-     elflink.c:_bfd_elf_create_dynamic_sections().  */
-  flagword flags, pltflags;
-  asection *s;
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-
-  /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
-     .rel[a].bss sections.  */
-
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-          | SEC_LINKER_CREATED);
-
-  pltflags = flags;
+  flags = pltflags;
   pltflags |= SEC_CODE;
   if (bed->plt_not_loaded)
     pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
@@ -3532,6 +3501,27 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   /* Blackfin-specific: remember it.  */
   bfinfdpic_pltrel_section (info) = s;
 
+  return TRUE;
+}
+
+/* Make sure the got and plt sections exist, and that our pointers in
+   the link hash table point to them.  */
+
+static bfd_boolean
+elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+{
+  /* This is mostly copied from
+     elflink.c:_bfd_elf_create_dynamic_sections().  */
+  flagword flags;
+  asection *s;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
+
+  /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
+     .rel[a].bss sections.  */
+
   /* Blackfin-specific: we want to create the GOT in the Blackfin way.  */
   if (! _bfin_create_got_section (abfd, info))
     return FALSE;
@@ -3586,13 +3576,10 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
    the symbol, an entry pointing to its function descriptor, and a
    private function descriptors taking two words.  */
 
-static int
-_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
+static void
+_bfinfdpic_count_nontls_entries (struct bfinfdpic_relocs_info *entry,
+                                struct _bfinfdpic_dynamic_got_info *dinfo)
 {
-  struct bfinfdpic_relocs_info *entry = *entryp;
-  struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_;
-  unsigned relocs = 0, fixups = 0;
-
   /* Allocate space for a GOT entry pointing to the symbol.  */
   if (entry->got17m4)
     dinfo->got17m4 += 4;
@@ -3640,6 +3627,18 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
 
   if (entry->lazyplt)
     dinfo->lzplt += LZPLT_NORMAL_SIZE;
+}
+
+/* Compute the number of dynamic relocations and fixups that a symbol
+   requires, and add (or subtract) from the grand and per-symbol
+   totals.  */
+
+static void
+_bfinfdpic_count_relocs_fixups (struct bfinfdpic_relocs_info *entry,
+                               struct _bfinfdpic_dynamic_got_info *dinfo,
+                               bfd_boolean subtract)
+{
+  bfd_vma relocs = 0, fixups = 0;
 
   if (!dinfo->info->executable || dinfo->info->pie)
     relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
@@ -3665,10 +3664,32 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
        relocs += entry->relocsfd;
     }
 
+  if (subtract)
+    {
+      relocs = - relocs;
+      fixups = - fixups;
+    }
+
   entry->dynrelocs += relocs;
   entry->fixups += fixups;
   dinfo->relocs += relocs;
   dinfo->fixups += fixups;
+}
+
+/* Compute the total GOT and PLT size required by each symbol in each range. *
+   Symbols may require up to 4 words in the GOT: an entry pointing to
+   the symbol, an entry pointing to its function descriptor, and a
+   private function descriptors taking two words.  */
+
+static int
+_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
+{
+  struct bfinfdpic_relocs_info *entry = *entryp;
+  struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_;
+
+  _bfinfdpic_count_nontls_entries (entry, dinfo);
+
+  _bfinfdpic_count_relocs_fixups (entry, dinfo, FALSE);
 
   return 1;
 }
@@ -3964,6 +3985,23 @@ _bfinfdpic_assign_plt_entries (void **entryp, void *info_)
   return 1;
 }
 
+/* Cancel out any effects of calling _bfinfdpic_assign_got_entries and
+   _bfinfdpic_assign_plt_entries.  */
+
+static int
+_bfinfdpic_reset_got_plt_entries (void **entryp, void *ignore ATTRIBUTE_UNUSED)
+{
+  struct bfinfdpic_relocs_info *entry = *entryp;
+
+  entry->got_entry = 0;
+  entry->fdgot_entry = 0;
+  entry->fd_entry = 0;
+  entry->plt_entry = (bfd_vma)-1;
+  entry->lzplt_entry = (bfd_vma)-1;
+
+  return 1;
+}
+
 /* Follow indirect and warning hash entries so that each got entry
    points to the final symbol definition.  P must point to a pointer
    to the hash table we're traversing.  Since this traversal may
@@ -4020,89 +4058,62 @@ _bfinfdpic_resolve_final_relocs_info (void **entryp, void *p)
   return 1;
 }
 
-/* Set the sizes of the dynamic sections.  */
+/* Compute the total size of the GOT, the PLT, the dynamic relocations
+   section and the rofixup section.  Assign locations for GOT and PLT
+   entries.  */
 
 static bfd_boolean
-elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
-                                     struct bfd_link_info *info)
+_bfinfdpic_size_got_plt (bfd *output_bfd,
+                        struct _bfinfdpic_dynamic_got_plt_info *gpinfop)
 {
-  bfd *dynobj;
-  asection *s;
-  struct _bfinfdpic_dynamic_got_plt_info gpinfo;
   bfd_signed_vma odd;
   bfd_vma limit;
+  struct bfd_link_info *info = gpinfop->g.info;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
 
-  dynobj = elf_hash_table (info)->dynobj;
-  BFD_ASSERT (dynobj != NULL);
-
-  if (elf_hash_table (info)->dynamic_sections_created)
-    {
-      /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
-       {
-         s = bfd_get_section_by_name (dynobj, ".interp");
-         BFD_ASSERT (s != NULL);
-         s->size = sizeof ELF_DYNAMIC_INTERPRETER;
-         s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
-       }
-    }
-
-  memset (&gpinfo, 0, sizeof (gpinfo));
-  gpinfo.g.info = info;
-
-  for (;;)
-    {
-      htab_t relocs = bfinfdpic_relocs_info (info);
-
-      htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs);
-
-      if (relocs == bfinfdpic_relocs_info (info))
-       break;
-    }
-
-  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries,
-                &gpinfo.g);
+  memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g,
+         sizeof (gpinfop->g));
 
   odd = 12;
   /* Compute the total size taken by entries in the 18-bit range,
      to tell how many PLT function descriptors we can bring into it
      without causing it to overflow.  */
-  limit = odd + gpinfo.g.got17m4 + gpinfo.g.fd17m4;
+  limit = odd + gpinfop->g.got17m4 + gpinfop->g.fd17m4;
   if (limit < (bfd_vma)1 << 18)
     limit = ((bfd_vma)1 << 18) - limit;
   else
     limit = 0;
-  if (gpinfo.g.fdplt < limit)
-    limit = gpinfo.g.fdplt;
+  if (gpinfop->g.fdplt < limit)
+    limit = gpinfop->g.fdplt;
 
   /* Determine the ranges of GOT offsets that we can use for each
      range of addressing modes.  */
-  odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.got17m4,
+  odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4,
                                          0,
                                          odd,
                                          16,
-                                         gpinfo.g.got17m4,
-                                         gpinfo.g.fd17m4,
+                                         gpinfop->g.got17m4,
+                                         gpinfop->g.fd17m4,
                                          limit,
                                          (bfd_vma)1 << (18-1));
-  odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.gothilo,
-                                         gpinfo.got17m4.min,
+  odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo,
+                                         gpinfop->got17m4.min,
                                          odd,
-                                         gpinfo.got17m4.max,
-                                         gpinfo.g.gothilo,
-                                         gpinfo.g.fdhilo,
-                                         gpinfo.g.fdplt - gpinfo.got17m4.fdplt,
+                                         gpinfop->got17m4.max,
+                                         gpinfop->g.gothilo,
+                                         gpinfop->g.fdhilo,
+                                         gpinfop->g.fdplt - gpinfop->got17m4.fdplt,
                                          (bfd_vma)1 << (32-1));
 
   /* Now assign (most) GOT offsets.  */
   htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
-                &gpinfo);
+                gpinfop);
 
-  bfinfdpic_got_section (info)->size = gpinfo.gothilo.max
-    - gpinfo.gothilo.min
+  bfinfdpic_got_section (info)->size = gpinfop->gothilo.max
+    - gpinfop->gothilo.min
     /* If an odd word is the last word of the GOT, we don't need this
        word to be part of the GOT.  */
-    - (odd + 4 == gpinfo.gothilo.max ? 4 : 0);
+    - (odd + 4 == gpinfop->gothilo.max ? 4 : 0);
   if (bfinfdpic_got_section (info)->size == 0)
     bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
   else if (bfinfdpic_got_section (info)->size == 12
@@ -4124,10 +4135,10 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
     /* Subtract the number of lzplt entries, since those will generate
        relocations in the pltrel section.  */
     bfinfdpic_gotrel_section (info)->size =
-      (gpinfo.g.relocs - gpinfo.g.lzplt / LZPLT_NORMAL_SIZE)
+      (gpinfop->g.relocs - gpinfop->g.lzplt / LZPLT_NORMAL_SIZE)
       * get_elf_backend_data (output_bfd)->s->sizeof_rel;
   else
-    BFD_ASSERT (gpinfo.g.relocs == 0);
+    BFD_ASSERT (gpinfop->g.relocs == 0);
   if (bfinfdpic_gotrel_section (info)->size == 0)
     bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
   else
@@ -4139,7 +4150,7 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
        return FALSE;
     }
 
-  bfinfdpic_gotfixup_section (info)->size = (gpinfo.g.fixups + 1) * 4;
+  bfinfdpic_gotfixup_section (info)->size = (gpinfop->g.fixups + 1) * 4;
   if (bfinfdpic_gotfixup_section (info)->size == 0)
     bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
   else
@@ -4154,7 +4165,7 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       bfinfdpic_pltrel_section (info)->size =
-       gpinfo.g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
+       gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
       if (bfinfdpic_pltrel_section (info)->size == 0)
        bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
       else
@@ -4174,29 +4185,29 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
      block size.  */
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      bfinfdpic_plt_section (info)->size = gpinfo.g.lzplt
-       + ((gpinfo.g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
+      bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt
+       + ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
           / (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
     }
 
   /* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
      actually assign lazy PLT entries addresses.  */
-  gpinfo.g.lzplt = 0;
+  gpinfop->g.lzplt = 0;
 
   /* Save information that we're going to need to generate GOT and PLT
      entries.  */
-  bfinfdpic_got_initial_offset (info) = -gpinfo.gothilo.min;
+  bfinfdpic_got_initial_offset (info) = -gpinfop->gothilo.min;
 
   if (get_elf_backend_data (output_bfd)->want_got_sym)
     elf_hash_table (info)->hgot->root.u.def.value
-      += bfinfdpic_got_initial_offset (info);
+      = bfinfdpic_got_initial_offset (info);
 
   if (elf_hash_table (info)->dynamic_sections_created)
     bfinfdpic_plt_initial_offset (info) =
       bfinfdpic_plt_section (info)->size;
 
   htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
-                &gpinfo);
+                gpinfop);
 
   /* Allocate the PLT section contents only after
      _bfinfdpic_assign_plt_entries has a chance to add the size of the
@@ -4215,6 +4226,59 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
        }
     }
 
+  return TRUE;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+static bfd_boolean
+elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
+                                     struct bfd_link_info *info)
+{
+  struct elf_link_hash_table *htab;
+  bfd *dynobj;
+  asection *s;
+  struct _bfinfdpic_dynamic_got_plt_info gpinfo;
+
+  htab = elf_hash_table (info);
+  dynobj = htab->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (htab->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (info->executable)
+       {
+         s = bfd_get_section_by_name (dynobj, ".interp");
+         BFD_ASSERT (s != NULL);
+         s->size = sizeof ELF_DYNAMIC_INTERPRETER;
+         s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
+       }
+    }
+
+  memset (&gpinfo, 0, sizeof (gpinfo));
+  gpinfo.g.info = info;
+
+  for (;;)
+    {
+      htab_t relocs = bfinfdpic_relocs_info (info);
+
+      htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs);
+
+      if (relocs == bfinfdpic_relocs_info (info))
+       break;
+    }
+
+  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries,
+                &gpinfo.g);
+
+  /* Allocate space to save the summary information, we're going to
+     use it if we're doing relaxations.  */
+  bfinfdpic_dynamic_got_plt_info (info) = bfd_alloc (dynobj, sizeof (gpinfo.g));
+
+  if (!_bfinfdpic_size_got_plt (output_bfd, &gpinfo))
+      return FALSE;
+
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       if (bfinfdpic_got_section (info)->size)
@@ -4275,6 +4339,122 @@ elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
   return TRUE;
 }
 
+/* Check whether any of the relocations was optimized away, and
+   subtract it from the relocation or fixup count.  */
+static bfd_boolean
+_bfinfdpic_check_discarded_relocs (bfd *abfd, asection *sec,
+                                 struct bfd_link_info *info,
+                                 
+                                 bfd_boolean *changed)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  Elf_Internal_Rela *rel, *erel;
+
+  if ((sec->flags & SEC_RELOC) == 0
+      || sec->reloc_count == 0)
+    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 = elf_section_data (sec)->relocs;
+
+  /* Now examine each relocation.  */
+  for (erel = rel + sec->reloc_count; rel < erel; rel++)
+    {
+      struct elf_link_hash_entry *h;
+      unsigned long r_symndx;
+      struct bfinfdpic_relocs_info *picrel;
+      struct _bfinfdpic_dynamic_got_info *dinfo;
+
+      if (ELF32_R_TYPE (rel->r_info) != R_BFIN_BYTE4_DATA
+         && ELF32_R_TYPE (rel->r_info) != R_BFIN_FUNCDESC)
+       continue;
+
+      if (_bfd_elf_section_offset (sec->output_section->owner,
+                                  info, sec, rel->r_offset)
+         != (bfd_vma)-1)
+       continue;
+
+      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];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *)h->root.u.i.link;
+       }
+
+      if (h != NULL)
+       picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info),
+                                                 abfd, h,
+                                                 rel->r_addend, NO_INSERT);
+      else
+       picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info (info),
+                                                abfd, r_symndx,
+                                                rel->r_addend, NO_INSERT);
+
+      if (! picrel)
+       return FALSE;
+
+      *changed = TRUE;
+      dinfo = bfinfdpic_dynamic_got_plt_info (info);
+
+      _bfinfdpic_count_relocs_fixups (picrel, dinfo, TRUE);
+      if (ELF32_R_TYPE (rel->r_info) == R_BFIN_BYTE4_DATA)
+       picrel->relocs32--;
+      else /* we know (ELF32_R_TYPE (rel->r_info) == R_BFIN_FUNCDESC) */
+       picrel->relocsfd--;
+      _bfinfdpic_count_relocs_fixups (picrel, dinfo, FALSE);
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
+bfinfdpic_elf_discard_info (bfd *ibfd,
+                          struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED,
+                          struct bfd_link_info *info)
+{
+  bfd_boolean changed = FALSE;
+  asection *s;
+  bfd *obfd = NULL;
+
+  /* Account for relaxation of .eh_frame section.  */
+  for (s = ibfd->sections; s; s = s->next)
+    if (s->sec_info_type == ELF_INFO_TYPE_EH_FRAME)
+      {
+       if (!_bfinfdpic_check_discarded_relocs (ibfd, s, info, &changed))
+         return FALSE;
+       obfd = s->output_section->owner;
+      }
+
+  if (changed)
+    {
+      struct _bfinfdpic_dynamic_got_plt_info gpinfo;
+
+      memset (&gpinfo, 0, sizeof (gpinfo));
+      memcpy (&gpinfo.g, bfinfdpic_dynamic_got_plt_info (info),
+             sizeof (gpinfo.g));
+
+      /* Clear GOT and PLT assignments.  */
+      htab_traverse (bfinfdpic_relocs_info (info),
+                    _bfinfdpic_reset_got_plt_entries,
+                    NULL);
+
+      if (!_bfinfdpic_size_got_plt (obfd, &gpinfo))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
 static bfd_boolean
 elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
                                        struct bfd_link_info *info)
@@ -5678,6 +5858,9 @@ struct bfd_elf_special_section const elf32_bfin_special_sections[] =
 #define elf_backend_finish_dynamic_sections \
                elf32_bfinfdpic_finish_dynamic_sections
 
+#undef elf_backend_discard_info
+#define elf_backend_discard_info \
+               bfinfdpic_elf_discard_info
 #undef elf_backend_can_make_relative_eh_frame
 #define elf_backend_can_make_relative_eh_frame \
                bfinfdpic_elf_use_relative_eh_frame