This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
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