Blob Blame History Raw
*** ../binutils-2.21.53.0.1.orig/bfd/elf64-ppc.c	2011-08-05 12:43:25.596878997 +0100
--- bfd/elf64-ppc.c	2011-08-05 12:44:58.485878988 +0100
***************
*** 34,39 ****
--- 34,40 ----
  #include "elf-bfd.h"
  #include "elf/ppc64.h"
  #include "elf64-ppc.h"
+ #include "dwarf2.h"
  
  static bfd_reloc_status_type ppc64_elf_ha_reloc
    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
*************** struct ppc_link_hash_table
*** 3720,3725 ****
--- 3721,3727 ----
    asection *sfpr;
    asection *brlt;
    asection *relbrlt;
+   asection *glink_eh_frame;
  
    /* Shortcut to .__tls_get_addr and __tls_get_addr.  */
    struct ppc_link_hash_entry *tls_get_addr;
*************** create_linkage_sections (bfd *dynobj, st
*** 4170,4175 ****
--- 4172,4189 ----
        || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
      return FALSE;
  
+   if (!info->no_ld_generated_unwind_info)
+     {
+       flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+ 	       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+       htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
+ 								 ".eh_frame",
+ 								 flags);
+       if (htab->glink_eh_frame == NULL
+ 	  || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2))
+ 	return FALSE;
+     }
+ 
    flags = SEC_ALLOC | SEC_LINKER_CREATED;
    htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
    if (htab->iplt == NULL
*************** ppc64_elf_size_dynamic_sections (bfd *ou
*** 9025,9030 ****
--- 9039,9050 ----
  	  /* Strip this section if we don't need it; see the
  	     comment below.  */
  	}
+       else if (s == htab->glink_eh_frame)
+ 	{
+ 	  if (!bfd_is_abs_section (s->output_section))
+ 	    /* Not sized yet.  */
+ 	    continue;
+ 	}
        else if (CONST_STRNEQ (s->name, ".rela"))
  	{
  	  if (s->size != 0)
*************** build_plt_stub (bfd *obfd, bfd_byte *p, 
*** 9271,9277 ****
  	  r[1].r_offset = r[0].r_offset + 8;
  	  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
  	  r[1].r_addend = r[0].r_addend;
! 	  if (PPC_HA (offset + 16) != PPC_HA (offset))
  	    {
  	      r[2].r_offset = r[1].r_offset + 4;
  	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
--- 9291,9297 ----
  	  r[1].r_offset = r[0].r_offset + 8;
  	  r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
  	  r[1].r_addend = r[0].r_addend;
! 	  if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
  	    {
  	      r[2].r_offset = r[1].r_offset + 4;
  	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
*************** build_plt_stub (bfd *obfd, bfd_byte *p, 
*** 9282,9290 ****
  	      r[2].r_offset = r[1].r_offset + 8;
  	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
  	      r[2].r_addend = r[0].r_addend + 8;
! 	      r[3].r_offset = r[2].r_offset + 4;
! 	      r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
! 	      r[3].r_addend = r[0].r_addend + 16;
  	    }
  	}
        bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),	p += 4;
--- 9302,9313 ----
  	      r[2].r_offset = r[1].r_offset + 8;
  	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
  	      r[2].r_addend = r[0].r_addend + 8;
! 	      if (plt_static_chain)
! 		{
! 		  r[3].r_offset = r[2].r_offset + 4;
! 		  r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
! 		  r[3].r_addend = r[0].r_addend + 16;
! 		}
  	    }
  	}
        bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),	p += 4;
*************** build_plt_stub (bfd *obfd, bfd_byte *p, 
*** 9307,9313 ****
  	{
  	  r[0].r_offset += 4;
  	  r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! 	  if (PPC_HA (offset + 16) != PPC_HA (offset))
  	    {
  	      r[1].r_offset = r[0].r_offset + 4;
  	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
--- 9330,9336 ----
  	{
  	  r[0].r_offset += 4;
  	  r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! 	  if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
  	    {
  	      r[1].r_offset = r[0].r_offset + 4;
  	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
*************** build_plt_stub (bfd *obfd, bfd_byte *p, 
*** 9317,9326 ****
  	    {
  	      r[1].r_offset = r[0].r_offset + 8;
  	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! 	      r[1].r_addend = r[0].r_addend + 16;
! 	      r[2].r_offset = r[1].r_offset + 4;
! 	      r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! 	      r[2].r_addend = r[0].r_addend + 8;
  	    }
  	}
        bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
--- 9340,9352 ----
  	    {
  	      r[1].r_offset = r[0].r_offset + 8;
  	      r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! 	      r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
! 	      if (plt_static_chain)
! 		{
! 		  r[2].r_offset = r[1].r_offset + 4;
! 		  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! 		  r[2].r_addend = r[0].r_addend + 8;
! 		}
  	    }
  	}
        bfd_put_32 (obfd, STD_R2_40R1, p),			p += 4;
*************** ppc_build_one_stub (struct bfd_hash_entr
*** 9788,9795 ****
        if (info->emitrelocations)
  	{
  	  r = get_relocs (stub_entry->stub_sec,
! 			  (2 + (PPC_HA (off) != 0)
! 			   + (PPC_HA (off + 16) == PPC_HA (off))));
  	  if (r == NULL)
  	    return FALSE;
  	  r[0].r_offset = loc - stub_entry->stub_sec->contents;
--- 9814,9823 ----
        if (info->emitrelocations)
  	{
  	  r = get_relocs (stub_entry->stub_sec,
! 			  (2
! 			   + (PPC_HA (off) != 0)
! 			   + (htab->plt_static_chain
! 			      && PPC_HA (off + 16) == PPC_HA (off))));
  	  if (r == NULL)
  	    return FALSE;
  	  r[0].r_offset = loc - stub_entry->stub_sec->contents;
*************** ppc_size_one_stub (struct bfd_hash_entry
*** 9896,9902 ****
  	size -= 4;
        if (PPC_HA (off) == 0)
  	size -= 4;
!       if (PPC_HA (off + 16) != PPC_HA (off))
  	size += 4;
        if (stub_entry->h != NULL
  	  && (stub_entry->h == htab->tls_get_addr_fd
--- 9924,9930 ----
  	size -= 4;
        if (PPC_HA (off) == 0)
  	size -= 4;
!       if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
  	size += 4;
        if (stub_entry->h != NULL
  	  && (stub_entry->h == htab->tls_get_addr_fd
*************** ppc_size_one_stub (struct bfd_hash_entry
*** 9906,9912 ****
        if (info->emitrelocations)
  	{
  	  stub_entry->stub_sec->reloc_count
! 	    += 2 + (PPC_HA (off) != 0) + (PPC_HA (off + 16) == PPC_HA (off));
  	  stub_entry->stub_sec->flags |= SEC_RELOC;
  	}
      }
--- 9934,9943 ----
        if (info->emitrelocations)
  	{
  	  stub_entry->stub_sec->reloc_count
! 	    += (2
! 		+ (PPC_HA (off) != 0)
! 		+ (htab->plt_static_chain
! 		   && PPC_HA (off + 16) == PPC_HA (off)));
  	  stub_entry->stub_sec->flags |= SEC_RELOC;
  	}
      }
*************** group_sections (struct ppc_link_hash_tab
*** 10826,10831 ****
--- 10857,10896 ----
  #undef PREV_SEC
  }
  
+ static const unsigned char glink_eh_frame_cie[] =
+ {
+   0, 0, 0, 16,				/* length.  */
+   0, 0, 0, 0,				/* id.  */
+   1,					/* CIE version.  */
+   'z', 'R', 0,				/* Augmentation string.  */
+   4,					/* Code alignment.  */
+   0x78,					/* Data alignment.  */
+   65,					/* RA reg.  */
+   1,					/* Augmentation size.  */
+   DW_EH_PE_pcrel | DW_EH_PE_sdata4,	/* FDE encoding.  */
+   DW_CFA_def_cfa, 1, 0			/* def_cfa: r1 offset 0.  */
+ };
+ 
+ /* Stripping output sections is normally done before dynamic section
+    symbols have been allocated.  This function is called later, and
+    handles cases like htab->brlt which is mapped to its own output
+    section.  */
+ 
+ static void
+ maybe_strip_output (struct bfd_link_info *info, asection *isec)
+ {
+   if (isec->size == 0
+       && isec->output_section->size == 0
+       && !bfd_section_removed_from_list (info->output_bfd,
+ 					 isec->output_section)
+       && elf_section_data (isec->output_section)->dynindx == 0)
+     {
+       isec->output_section->flags |= SEC_EXCLUDE;
+       bfd_section_list_remove (info->output_bfd, isec->output_section);
+       info->output_bfd->section_count--;
+     }
+ }
+ 
  /* Determine and set the size of the stub section for a final link.
  
     The basic idea here is to examine all the relocations looking for
*************** ppc64_elf_size_stubs (struct bfd_link_in
*** 11169,11174 ****
--- 11234,11258 ----
  	  htab->glink->flags |= SEC_RELOC;
  	}
  
+       if (htab->glink_eh_frame != NULL
+ 	  && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
+ 	  && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0)
+ 	{
+ 	  bfd_size_type size = 0;
+ 
+ 	  for (stub_sec = htab->stub_bfd->sections;
+ 	       stub_sec != NULL;
+ 	       stub_sec = stub_sec->next)
+ 	    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ 	      size += 20;
+ 	  if (htab->glink != NULL && htab->glink->size != 0)
+ 	    size += 24;
+ 	  if (size != 0)
+ 	    size += sizeof (glink_eh_frame_cie);
+ 	  htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+ 	  htab->glink_eh_frame->size = size;
+ 	}
+ 
        for (stub_sec = htab->stub_bfd->sections;
  	   stub_sec != NULL;
  	   stub_sec = stub_sec->next)
*************** ppc64_elf_size_stubs (struct bfd_link_in
*** 11178,11194 ****
  
        /* Exit from this loop when no stubs have been added, and no stubs
  	 have changed size.  */
!       if (stub_sec == NULL)
  	break;
  
        /* Ask the linker to do its stuff.  */
        (*htab->layout_sections_again) ();
      }
  
!   /* It would be nice to strip htab->brlt from the output if the
!      section is empty, but it's too late.  If we strip sections here,
!      the dynamic symbol table is corrupted since the section symbol
!      for the stripped section isn't written.  */
  
    return TRUE;
  }
--- 11262,11279 ----
  
        /* Exit from this loop when no stubs have been added, and no stubs
  	 have changed size.  */
!       if (stub_sec == NULL
! 	  && (htab->glink_eh_frame == NULL
! 	      || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
  	break;
  
        /* Ask the linker to do its stuff.  */
        (*htab->layout_sections_again) ();
      }
  
!   maybe_strip_output (info, htab->brlt);
!   if (htab->glink_eh_frame != NULL)
!     maybe_strip_output (info, htab->glink_eh_frame);
  
    return TRUE;
  }
*************** ppc64_elf_build_stubs (bfd_boolean emit_
*** 11393,11398 ****
--- 11478,11577 ----
  	return FALSE;
      }
  
+   if (htab->glink_eh_frame != NULL
+       && htab->glink_eh_frame->size != 0)
+     {
+       bfd_vma val;
+ 
+       p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
+       if (p == NULL)
+ 	return FALSE;
+       htab->glink_eh_frame->contents = p;
+ 
+       htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+ 
+       memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
+       /* CIE length (rewrite in case little-endian).  */
+       bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p);
+       p += sizeof (glink_eh_frame_cie);
+ 
+       for (stub_sec = htab->stub_bfd->sections;
+ 	   stub_sec != NULL;
+ 	   stub_sec = stub_sec->next)
+ 	if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ 	  {
+ 	    /* FDE length.  */
+ 	    bfd_put_32 (htab->elf.dynobj, 16, p);
+ 	    p += 4;
+ 	    /* CIE pointer.  */
+ 	    val = p - htab->glink_eh_frame->contents;
+ 	    bfd_put_32 (htab->elf.dynobj, val, p);
+ 	    p += 4;
+ 	    /* Offset to stub section.  */
+ 	    val = (stub_sec->output_section->vma
+ 		   + stub_sec->output_offset);
+ 	    val -= (htab->glink_eh_frame->output_section->vma
+ 		    + htab->glink_eh_frame->output_offset);
+ 	    val -= p - htab->glink_eh_frame->contents;
+ 	    if (val + 0x80000000 > 0xffffffff)
+ 	      {
+ 		info->callbacks->einfo
+ 		  (_("%s offset too large for .eh_frame sdata4 encoding"),
+ 		   stub_sec->name);
+ 		return FALSE;
+ 	      }
+ 	    bfd_put_32 (htab->elf.dynobj, val, p);
+ 	    p += 4;
+ 	    /* stub section size.  */
+ 	    bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p);
+ 	    p += 4;
+ 	    /* Augmentation.  */
+ 	    p += 1;
+ 	    /* Pad.  */
+ 	    p += 3;
+ 	  }
+       if (htab->glink != NULL && htab->glink->size != 0)
+ 	{
+ 	  /* FDE length.  */
+ 	  bfd_put_32 (htab->elf.dynobj, 20, p);
+ 	  p += 4;
+ 	  /* CIE pointer.  */
+ 	  val = p - htab->glink_eh_frame->contents;
+ 	  bfd_put_32 (htab->elf.dynobj, val, p);
+ 	  p += 4;
+ 	  /* Offset to .glink.  */
+ 	  val = (htab->glink->output_section->vma
+ 		 + htab->glink->output_offset
+ 		 + 8);
+ 	  val -= (htab->glink_eh_frame->output_section->vma
+ 		  + htab->glink_eh_frame->output_offset);
+ 	  val -= p - htab->glink_eh_frame->contents;
+ 	  if (val + 0x80000000 > 0xffffffff)
+ 	    {
+ 	      info->callbacks->einfo
+ 		(_("%s offset too large for .eh_frame sdata4 encoding"),
+ 		 htab->glink->name);
+ 	      return FALSE;
+ 	    }
+ 	  bfd_put_32 (htab->elf.dynobj, val, p);
+ 	  p += 4;
+ 	  /* .glink size.  */
+ 	  bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p);
+ 	  p += 4;
+ 	  /* Augmentation.  */
+ 	  p += 1;
+ 
+ 	  *p++ = DW_CFA_advance_loc + 1;
+ 	  *p++ = DW_CFA_register;
+ 	  *p++ = 65;
+ 	  *p++ = 12;
+ 	  *p++ = DW_CFA_advance_loc + 4;
+ 	  *p++ = DW_CFA_restore_extended;
+ 	  *p++ = 65;
+ 	}
+       htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents;
+     }
+ 
    /* Build the stubs as directed by the stub hash table.  */
    bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
  
*************** ppc64_elf_build_stubs (bfd_boolean emit_
*** 11410,11416 ****
        }
  
    if (stub_sec != NULL
!       || htab->glink->rawsize != htab->glink->size)
      {
        htab->stub_error = TRUE;
        info->callbacks->einfo (_("stubs don't match calculated size\n"));
--- 11589,11597 ----
        }
  
    if (stub_sec != NULL
!       || htab->glink->rawsize != htab->glink->size
!       || (htab->glink_eh_frame != NULL
! 	  && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
      {
        htab->stub_error = TRUE;
        info->callbacks->einfo (_("stubs don't match calculated size\n"));
*************** ppc64_elf_relocate_section (bfd *output_
*** 12842,12853 ****
  	      else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
  		       && !is_opd
  		       && r_type != R_PPC64_TOC)
! 		{
! 		  outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
! 		  if (h->elf.dynindx == -1
! 		      && h->elf.root.type == bfd_link_hash_undefweak)
! 		    memset (&outrel, 0, sizeof outrel);
! 		}
  	      else
  		{
  		  /* This symbol is local, or marked to become local,
--- 13021,13027 ----
  	      else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
  		       && !is_opd
  		       && r_type != R_PPC64_TOC)
! 		outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
  	      else
  		{
  		  /* This symbol is local, or marked to become local,
*************** ppc64_elf_finish_dynamic_sections (bfd *
*** 13566,13571 ****
--- 13740,13753 ----
  				       NULL))
      return FALSE;
  
+ 
+   if (htab->glink_eh_frame != NULL
+       && htab->glink_eh_frame->sec_info_type == ELF_INFO_TYPE_EH_FRAME
+       && !_bfd_elf_write_section_eh_frame (output_bfd, info,
+ 					   htab->glink_eh_frame,
+ 					   htab->glink_eh_frame->contents))
+     return FALSE;
+ 
    /* We need to handle writing out multiple GOT sections ourselves,
       since we didn't add them to DYNOBJ.  We know dynobj is the first
       bfd.  */