From 6a9adeca2c38bef2ae6554ecf954babda5dc6522 Mon Sep 17 00:00:00 2001
From: Bernd Schmidt <bernds@codesourcery.com>
Date: Tue, 11 Aug 2009 11:41:17 +0000
Subject: 	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.

---
 bfd/ChangeLog    |  22 ++-
 bfd/elf32-bfin.c | 465 ++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 345 insertions(+), 142 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index be52aa6..335731e 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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,
diff --git a/bfd/elf32-bfin.c b/bfd/elf32-bfin.c
index 3752d52..3eb7499 100644
--- a/bfd/elf32-bfin.c
+++ b/bfd/elf32-bfin.c
@@ -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
-- 
cgit v1.1