This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: powerpc TLS support


GOT trouble.  Multiple GOT entries per sym mean we need to init them
all in one go, and adjust offsets too.

	* elf32-ppc.c (allocate_dynrelocs): LD and GD relocs against the
	same sym need separate GOT entries.
	(ppc_elf_relocate_section): Correct GOT handling for multiple GOT
	entries per symbol.

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.67
diff -c -p -r1.67 elf32-ppc.c
*** bfd/elf32-ppc.c	19 Feb 2003 11:26:50 -0000	1.67
--- bfd/elf32-ppc.c	20 Feb 2003 08:19:24 -0000
*************** allocate_dynrelocs (h, inf)
*** 2737,2743 ****
  	  eh->elf.got.offset = htab->got->_raw_size;
  	  if ((eh->tls_mask & TLS_TLS) != 0)
  	    {
! 	      if ((eh->tls_mask & (TLS_GD | TLS_LD)) != 0)
  		htab->got->_raw_size += 8;
  	      if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
  		htab->got->_raw_size += 4;
--- 2737,2745 ----
  	  eh->elf.got.offset = htab->got->_raw_size;
  	  if ((eh->tls_mask & TLS_TLS) != 0)
  	    {
! 	      if ((eh->tls_mask & TLS_LD) != 0)
! 		htab->got->_raw_size += 8;
! 	      if ((eh->tls_mask & TLS_GD) != 0)
  		htab->got->_raw_size += 8;
  	      if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
  		htab->got->_raw_size += 4;
*************** ppc_elf_relocate_section (output_bfd, in
*** 4723,4797 ****
  	      off &= ~1;
  	    else
  	      {
! 		*offp = off | 1;
! 
! 		/* Generate relocs for the dynamic linker, except in
! 		   the case of TLSLD where we'll use one entry per
! 		   module.  */
! 		if (info->shared || indx != 0)
  		  {
! 		    outrel.r_offset = (htab->got->output_section->vma
! 				       + htab->got->output_offset
! 				       + off);
! 		    if (tls_type & (TLS_LD | TLS_GD))
  		      {
! 			outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
! 			outrel.r_addend = 0;
! 			if (tls_type == (TLS_TLS | TLS_GD))
! 			  {
! 			    loc = htab->relgot->contents;
! 			    loc += (htab->relgot->reloc_count++
! 				    * sizeof (Elf32_External_Rela));
! 			    bfd_elf32_swap_reloca_out (output_bfd,
! 						       &outrel, loc);
! 			    outrel.r_info
! 			      = ELF32_R_INFO (indx, R_PPC_DTPREL32);
! 			    outrel.r_offset += 4;
! 			  }
  		      }
- 		    else if (tls_type == (TLS_TLS | TLS_DTPREL))
- 		      outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32);
- 		    else if (tls_type == (TLS_TLS | TLS_TPREL))
- 		      outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32);
- 		    else if (indx == 0)
- 		      outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
- 		    else
- 		      outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
- 		    outrel.r_addend = 0;
- 		    if (indx == 0)
- 		      outrel.r_addend += relocation;
- 		    loc = htab->relgot->contents;
- 		    loc += (htab->relgot->reloc_count++
- 			    * sizeof (Elf32_External_Rela));
- 		    bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
- 		  }
  
! 		/* Init the .got section contents if we're not
! 		   emitting a reloc.  */
! 		else
! 		  {
! 		    if (tls_type != 0)
  		      {
! 			relocation -= htab->tls_sec->vma + DTP_OFFSET;
! 			if ((tls_type & TLS_TPREL) != 0)
! 			  relocation += DTP_OFFSET - TP_OFFSET;
  		      }
  
! 		    if (tls_type == (TLS_TLS | TLS_GD))
  		      {
! 			bfd_put_32 (output_bfd, relocation,
! 				    htab->got->contents + off + 4);
! 			relocation = 1;
  		      }
! 		    else if (tls_type == (TLS_TLS | TLS_LD))
! 		      relocation = 1;
! 		    bfd_put_32 (output_bfd, relocation,
! 				htab->got->contents + off);
  		  }
  	      }
  
  	    if (off >= (bfd_vma) -2)
  	      abort ();
  
  	    relocation = htab->got->output_offset + off - 4;
  
--- 4725,4867 ----
  	      off &= ~1;
  	    else
  	      {
! 		unsigned int tls_m = (tls_mask
! 				      & (TLS_LD | TLS_GD | TLS_DTPREL
! 					 | TLS_TPREL | TLS_TPRELGD));
! 
! 		if (offp == &htab->tlsld_got.offset)
! 		  tls_m = TLS_LD;
! 		else if (h == NULL
! 			 || !(h->elf_link_hash_flags
! 			      & ELF_LINK_HASH_DEF_DYNAMIC))
! 		  tls_m &= ~TLS_LD;
! 
! 		/* We might have multiple got entries for this sym.
! 		   Initialize them all.  */
! 		do
  		  {
! 		    int tls_ty = 0;
! 
! 		    if ((tls_m & TLS_LD) != 0)
  		      {
! 			tls_ty = TLS_TLS | TLS_LD;
! 			tls_m &= ~TLS_LD;
! 		      }
! 		    else if ((tls_m & TLS_GD) != 0)
! 		      {
! 			tls_ty = TLS_TLS | TLS_GD;
! 			tls_m &= ~TLS_GD;
! 		      }
! 		    else if ((tls_m & TLS_DTPREL) != 0)
! 		      {
! 			tls_ty = TLS_TLS | TLS_DTPREL;
! 			tls_m &= ~TLS_DTPREL;
! 		      }
! 		    else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0)
! 		      {
! 			tls_ty = TLS_TLS | TLS_TPREL;
! 			tls_m = 0;
  		      }
  
! 		    /* Generate relocs for the dynamic linker.  */
! 		    if (info->shared || indx != 0)
  		      {
! 			outrel.r_offset = (htab->got->output_section->vma
! 					   + htab->got->output_offset
! 					   + off);
! 			if (tls_ty & (TLS_LD | TLS_GD))
! 			  {
! 			    outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
! 			    outrel.r_addend = 0;
! 			    if (tls_ty == (TLS_TLS | TLS_GD))
! 			      {
! 				loc = htab->relgot->contents;
! 				loc += (htab->relgot->reloc_count++
! 					* sizeof (Elf32_External_Rela));
! 				bfd_elf32_swap_reloca_out (output_bfd,
! 							   &outrel, loc);
! 				outrel.r_info
! 				  = ELF32_R_INFO (indx, R_PPC_DTPREL32);
! 				outrel.r_offset += 4;
! 			      }
! 			  }
! 			else if (tls_ty == (TLS_TLS | TLS_DTPREL))
! 			  outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32);
! 			else if (tls_ty == (TLS_TLS | TLS_TPREL))
! 			  outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32);
! 			else if (indx == 0)
! 			  outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
! 			else
! 			  outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
! 			outrel.r_addend = 0;
! 			if (indx == 0)
! 			  outrel.r_addend += relocation;
! 			loc = htab->relgot->contents;
! 			loc += (htab->relgot->reloc_count++
! 				* sizeof (Elf32_External_Rela));
! 			bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
  		      }
  
! 		    /* Init the .got section contents if we're not
! 		       emitting a reloc.  */
! 		    else
  		      {
! 			bfd_vma value = relocation;
! 
! 			if ((tls_ty & (TLS_GD | TLS_TPREL | TLS_DTPREL
! 				       | TLS_TPRELGD)) != 0)
! 			  {
! 			    value -= htab->tls_sec->vma + DTP_OFFSET;
! 			    if ((tls_ty & TLS_TPREL) != 0)
! 			      value += DTP_OFFSET - TP_OFFSET;
! 			  }
! 
! 			if (tls_ty == (TLS_TLS | TLS_GD))
! 			  {
! 			    bfd_put_32 (output_bfd, value,
! 					htab->got->contents + off + 4);
! 			    value = 1;
! 			  }
! 			else if (tls_ty == (TLS_TLS | TLS_LD))
! 			  value = 1;
! 			bfd_put_32 (output_bfd, value,
! 				    htab->got->contents + off);
  		      }
! 
! 		    off += 4;
! 		    if (tls_ty & (TLS_LD | TLS_GD))
! 		      off += 4;
  		  }
+ 		while (tls_m != 0);
+ 
+ 		off = *offp;
+ 		*offp = off | 1;
  	      }
  
  	    if (off >= (bfd_vma) -2)
  	      abort ();
+ 
+ 	    if ((tls_type & TLS_TLS) != 0)
+ 	      {
+ 		if (tls_type != (TLS_TLS | TLS_LD))
+ 		  {
+ 		    if ((tls_mask & TLS_LD) != 0
+ 			&& !(h == NULL
+ 			     || !(h->elf_link_hash_flags
+ 				  & ELF_LINK_HASH_DEF_DYNAMIC)))
+ 		      off += 8;
+ 		    if (tls_type != (TLS_TLS | TLS_GD))
+ 		      {
+ 			if ((tls_mask & TLS_GD) != 0)
+ 			  off += 8;
+ 			if (tls_type != (TLS_TLS | TLS_DTPREL))
+ 			  {
+ 			    if ((tls_mask & TLS_DTPREL) != 0)
+ 			      off += 4;
+ 			  }
+ 		      }
+ 		  }
+ 	      }
  
  	    relocation = htab->got->output_offset + off - 4;
  

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]