include/elf/
authorAlan Modra <amodra@gmail.com>
Wed, 4 Mar 2009 05:50:50 +0000 (05:50 +0000)
committerAlan Modra <amodra@gmail.com>
Wed, 4 Mar 2009 05:50:50 +0000 (05:50 +0000)
* ppc.h (R_PPC_TLSGD, R_PPC_TLSLD): Add new relocs.
* ppc64.h (R_PPC64_TLSGD, R_PPC64_TLSLD): Add new relocs.
bfd/
* reloc.c (BFD_RELOC_PPC_TLSGD, BFD_RELOC_PPC_TLSLD): New.
* section.c (struct bfd_section): Add has_tls_get_addr_call.
(BFD_FAKE_SECTION): Init new flag.
* ecoff.c (bfd_debug_section): Likewise.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* elf32-ppc.c (ppc_elf_howto_raw): Add R_PPC_TLSGD and R_PPC_TLSLD.
(ppc_elf_reloc_type_lookup): Handle new relocs.
(ppc_elf_check_relocs): Set has_tls_get_addr_call on finding such
without marker relocs.
(ppc_elf_tls_optimize): Allow out-of-order __tls_get_addr relocs
if section has no old-style calls.
(ppc_elf_relocate_section): Set tls_mask for non-tls relocs too.
Don't try to optimize new-style __tls_get_addr call when handling
arg setup relocs.  Instead do so for R_PPC_TLSGD and R_PPC_TLSLD
relocs.
* elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_TLSGD, R_PPC64_TLSLD.
(ppc64_elf_reloc_type_lookup): Handle new relocs.
(ppc64_elf_check_relocs): Set has_tls_get_addr_call on finding such
without marker relocs.
(ppc64_elf_tls_optimize): Allow out-of-order __tls_get_addr relocs
if section has no old-style calls.  Set toc_ref for new relocs as
appropriate.
(ppc64_elf_relocate_section): Set tls_mask for non-tls relocs too.
Don't try to optimize new-style __tls_get_addr call when handling
arg setup relocs.  Instead do so for R_PPC_TLSGD and R_PPC_TLSLD
relocs.
gas/
* config/tc-ppc.c (ppc_elf_suffix): Error if ppc32 tls got relocs
have non-zero addend.
(md_assemble): Parse args of __tls_get_addr calls.
(md_apply_fix): Handle BFD_RELOC_PPC_TLSGD and BFD_RELOC_PPC_TLSLD.
ld/testsuite/
* ld-powerpc/tlsmark.s, * ld-powerpc/tlsmark.d: New test.
* ld-powerpc/tlsmark32.s, * ld-powerpc/tlsmark32.d: New test.
* ld-powerpc/powerpc.exp: Run them.

19 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/ecoff.c
bfd/elf32-ppc.c
bfd/elf64-ppc.c
bfd/libbfd.h
bfd/reloc.c
bfd/section.c
gas/ChangeLog
gas/config/tc-ppc.c
include/elf/ChangeLog
include/elf/ppc.h
include/elf/ppc64.h
ld/testsuite/ChangeLog
ld/testsuite/ld-powerpc/powerpc.exp
ld/testsuite/ld-powerpc/tlsmark.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/tlsmark.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/tlsmark32.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/tlsmark32.s [new file with mode: 0644]

index 817726f14b20f039e90bc9039ab79854151caca3..444d13e40c9af2a991bb7c04c0accae7c37f58cf 100644 (file)
@@ -1,3 +1,33 @@
+2009-03-04  Alan Modra  <amodra@bigpond.net.au>
+
+       * reloc.c (BFD_RELOC_PPC_TLSGD, BFD_RELOC_PPC_TLSLD): New.
+       * section.c (struct bfd_section): Add has_tls_get_addr_call.
+       (BFD_FAKE_SECTION): Init new flag.
+       * ecoff.c (bfd_debug_section): Likewise.
+       * bfd-in2.h: Regenerate.
+       * libbfd.h: Regenerate.
+       * elf32-ppc.c (ppc_elf_howto_raw): Add R_PPC_TLSGD and R_PPC_TLSLD.
+       (ppc_elf_reloc_type_lookup): Handle new relocs.
+       (ppc_elf_check_relocs): Set has_tls_get_addr_call on finding such
+       without marker relocs.
+       (ppc_elf_tls_optimize): Allow out-of-order __tls_get_addr relocs
+       if section has no old-style calls.
+       (ppc_elf_relocate_section): Set tls_mask for non-tls relocs too.
+       Don't try to optimize new-style __tls_get_addr call when handling
+       arg setup relocs.  Instead do so for R_PPC_TLSGD and R_PPC_TLSLD
+       relocs.
+       * elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_TLSGD, R_PPC64_TLSLD.
+       (ppc64_elf_reloc_type_lookup): Handle new relocs.
+       (ppc64_elf_check_relocs): Set has_tls_get_addr_call on finding such
+       without marker relocs.
+       (ppc64_elf_tls_optimize): Allow out-of-order __tls_get_addr relocs
+       if section has no old-style calls.  Set toc_ref for new relocs as
+       appropriate.
+       (ppc64_elf_relocate_section): Set tls_mask for non-tls relocs too.
+       Don't try to optimize new-style __tls_get_addr call when handling
+       arg setup relocs.  Instead do so for R_PPC_TLSGD and R_PPC_TLSLD
+       relocs.
+
 2009-03-04  Alan Modra  <amodra@bigpond.net.au>
 
        PR 6768
index be35ac4db63562e6be641b1c15cbb93c3b5c23ed..e7942c3942d3066f3efc5ed4e301d5a25b689fe2 100644 (file)
@@ -1343,6 +1343,9 @@ typedef struct bfd_section
   /* Nonzero if this section has TLS related relocations.  */
   unsigned int has_tls_reloc:1;
 
+  /* Nonzero if this section has a call to __tls_get_addr.  */
+  unsigned int has_tls_get_addr_call:1;
+
   /* Nonzero if this section has a gp reloc.  */
   unsigned int has_gp_reloc:1;
 
@@ -1603,11 +1606,11 @@ extern asection bfd_ind_section;
   /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc,       */  \
      0,            0,             0,          0,                       \
                                                                        \
-  /* has_gp_reloc, need_finalize_relax, reloc_done,                */  \
-     0,            0,                   0,                             \
+  /* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax,     */  \
+     0,                     0,            0,                           \
                                                                        \
-  /* vma, lma, size, rawsize                                       */  \
-     0,   0,   0,    0,                                                \
+  /* reloc_done, vma, lma, size, rawsize                           */  \
+     0,          0,   0,   0,    0,                                    \
                                                                        \
   /* output_offset, output_section,              alignment_power,  */  \
      0,             (struct bfd_section *) &SEC, 0,                    \
@@ -2928,6 +2931,8 @@ relaxation.  */
 
 /* PowerPC and PowerPC64 thread-local storage relocations.  */
   BFD_RELOC_PPC_TLS,
+  BFD_RELOC_PPC_TLSGD,
+  BFD_RELOC_PPC_TLSLD,
   BFD_RELOC_PPC_DTPMOD,
   BFD_RELOC_PPC_TPREL16,
   BFD_RELOC_PPC_TPREL16_LO,
index a78273e1b964883f8cdf1202f720757cefc90799..4d277405c64c38815957c2420cc891ce4131411b 100644 (file)
@@ -1,6 +1,7 @@
 /* Generic ECOFF (Extended-COFF) routines.
    Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Original version by Per Bothner.
    Full support added by Ian Lance Taylor, ian@cygnus.com.
 
@@ -59,10 +60,10 @@ static asection bfd_debug_section =
      0,           0,                1,
   /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc,       */
      0,            0,             0,          0,
-  /* has_gp_reloc, need_finalize_relax, reloc_done,                */
-     0,            0,                   0,
-  /* vma, lma, size, rawsize,                                      */
-     0,   0,   0,    0,
+  /* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax,     */
+     0,                     0,            0,
+  /* reloc_done, vma, lma, size, rawsize,                          */
+     0,          0,   0,   0,    0,
   /* output_offset, output_section, alignment_power,               */
      0,             NULL,           0,
   /* relocation, orelocation, reloc_count, filepos, rel_filepos,   */
index ac416baebcd14d3aace274de7d13f106958a1a8c..5db64b0fa651d8b33822237eb454932f5bad007b 100644 (file)
@@ -753,7 +753,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC_TLS,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -768,6 +768,34 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC_TLSGD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_TLSGD",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC_TLSLD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_TLSLD",         /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC_DTPMOD32,
@@ -1531,6 +1559,8 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_CTOR:               r = R_PPC_ADDR32;               break;
     case BFD_RELOC_PPC_TOC16:          r = R_PPC_TOC16;                break;
     case BFD_RELOC_PPC_TLS:            r = R_PPC_TLS;                  break;
+    case BFD_RELOC_PPC_TLSGD:          r = R_PPC_TLSGD;                break;
+    case BFD_RELOC_PPC_TLSLD:          r = R_PPC_TLSLD;                break;
     case BFD_RELOC_PPC_DTPMOD:         r = R_PPC_DTPMOD32;             break;
     case BFD_RELOC_PPC_TPREL16:                r = R_PPC_TPREL16;              break;
     case BFD_RELOC_PPC_TPREL16_LO:     r = R_PPC_TPREL16_LO;           break;
@@ -3288,6 +3318,7 @@ ppc_elf_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *got2, *sreloc;
+  struct elf_link_hash_entry *tga;
 
   if (info->relocatable)
     return TRUE;
@@ -3313,6 +3344,8 @@ ppc_elf_check_relocs (bfd *abfd,
     ppc_elf_howto_init ();
 
   htab = ppc_elf_hash_table (info);
+  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                             FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   got2 = bfd_get_section_by_name (abfd, ".got2");
@@ -3324,7 +3357,7 @@ ppc_elf_check_relocs (bfd *abfd,
       unsigned long r_symndx;
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
-      int tls_type = 0;
+      int tls_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3351,9 +3384,44 @@ ppc_elf_check_relocs (bfd *abfd,
          BFD_ASSERT (h == htab->elf.hgot);
        }
 
+      tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      if (h != NULL && h == tga)
+       switch (r_type)
+         {
+         default:
+           break;
+
+         case R_PPC_PLTREL24:
+         case R_PPC_LOCAL24PC:
+         case R_PPC_REL24:
+         case R_PPC_REL14:
+         case R_PPC_REL14_BRTAKEN:
+         case R_PPC_REL14_BRNTAKEN:
+         case R_PPC_ADDR24:
+         case R_PPC_ADDR14:
+         case R_PPC_ADDR14_BRTAKEN:
+         case R_PPC_ADDR14_BRNTAKEN:
+           if (rel != relocs
+               && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
+                   || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
+             /* We have a new-style __tls_get_addr call with a marker
+                reloc.  */
+             ;
+           else
+             /* Mark this section as having an old-style call.  */
+             sec->has_tls_get_addr_call = 1;
+           break;
+         }
+
       switch (r_type)
        {
+       case R_PPC_TLSGD:
+       case R_PPC_TLSLD:
+         /* These special tls relocs tie a call to __tls_get_addr with
+            its parameter symbol.  */
+         break;
+
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_HI:
@@ -3607,7 +3675,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* This refers only to functions defined in the shared library.  */
        case R_PPC_LOCAL24PC:
-         if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
+         if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
            {
              htab->plt_type = PLT_OLD;
              htab->old_bfd = abfd;
@@ -4484,7 +4552,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
 
                  if (pass == 0)
                    {
-                     if (!expecting_tls_get_addr)
+                     if (!expecting_tls_get_addr
+                         || !sec->has_tls_get_addr_call)
                        continue;
 
                      if (rel + 1 < relend
@@ -6234,16 +6303,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
         for the final instruction stream.  */
       tls_mask = 0;
       tls_gd = 0;
-      if (IS_PPC_TLS_RELOC (r_type))
+      if (h != NULL)
+       tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
+      else if (local_got_offsets != NULL)
        {
-         if (h != NULL)
-           tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
-         else if (local_got_offsets != NULL)
-           {
-             char *lgot_masks;
-             lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
-             tls_mask = lgot_masks[r_symndx];
-           }
+         char *lgot_masks;
+         lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
+         tls_mask = lgot_masks[r_symndx];
        }
 
       /* Ensure reloc mapping code below stays sane.  */
@@ -6361,7 +6427,17 @@ ppc_elf_relocate_section (bfd *output_bfd,
              bfd_vma offset;
 
            tls_ldgd_opt:
-             offset = rel[1].r_offset;
+             offset = (bfd_vma) -1;
+             /* If not using the newer R_PPC_TLSGD/LD to mark
+                __tls_get_addr calls, we must trust that the call
+                stays with its arg setup insns, ie. that the next
+                reloc is the __tls_get_addr call associated with
+                the current reloc.  Edit both insns.  */
+             if (input_section->has_tls_get_addr_call
+                 && rel + 1 < relend
+                 && branch_reloc_hash_match (input_bfd, rel + 1,
+                                             htab->tls_get_addr))
+               offset = rel[1].r_offset;
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
@@ -6369,9 +6445,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                      contents + rel->r_offset - d_offset);
                  insn1 &= (1 << 26) - 1;
                  insn1 |= 32 << 26;    /* lwz */
-                 insn2 = 0x7c631214;   /* add 3,3,2 */
-                 rel[1].r_info
-                   = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE);
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info
+                       = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+                                       R_PPC_NONE);
+                     insn2 = 0x7c631214;       /* add 3,3,2 */
+                     bfd_put_32 (output_bfd, insn2, contents + offset);
+                   }
                  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                            + R_PPC_GOT_TPREL16);
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -6380,7 +6461,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                {
                  /* LE */
                  insn1 = 0x3c620000;   /* addis 3,2,0 */
-                 insn2 = 0x38630000;   /* addi 3,3,0 */
                  if (tls_gd == 0)
                    {
                      /* Was an LD reloc.  */
@@ -6399,14 +6479,17 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    }
                  r_type = R_PPC_TPREL16_HA;
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
-                 rel[1].r_info = ELF32_R_INFO (r_symndx,
-                                               R_PPC_TPREL16_LO);
-                 rel[1].r_offset += d_offset;
-                 rel[1].r_addend = rel->r_addend;
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
+                     rel[1].r_offset = offset + d_offset;
+                     rel[1].r_addend = rel->r_addend;
+                     insn2 = 0x38630000;       /* addi 3,3,0 */
+                     bfd_put_32 (output_bfd, insn2, contents + offset);
+                   }
                }
              bfd_put_32 (output_bfd, insn1,
                          contents + rel->r_offset - d_offset);
-             bfd_put_32 (output_bfd, insn2, contents + offset);
              if (tls_gd == 0)
                {
                  /* We changed the symbol on an LD reloc.  Start over
@@ -6416,6 +6499,66 @@ ppc_elf_relocate_section (bfd *output_bfd,
                }
            }
          break;
+
+       case R_PPC_TLSGD:
+         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+           {
+             unsigned int insn2;
+             bfd_vma offset = rel->r_offset;
+
+             if ((tls_mask & TLS_TPRELGD) != 0)
+               {
+                 /* IE */
+                 r_type = R_PPC_NONE;
+                 insn2 = 0x7c631214;   /* add 3,3,2 */
+               }
+             else
+               {
+                 /* LE */
+                 r_type = R_PPC_TPREL16_LO;
+                 rel->r_offset += d_offset;
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+               }
+             rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+             bfd_put_32 (output_bfd, insn2, contents + offset);
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+                                           R_PPC_NONE);
+           }
+         break;
+
+       case R_PPC_TLSLD:
+         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+           {
+             unsigned int insn2;
+
+             for (r_symndx = 0;
+                  r_symndx < symtab_hdr->sh_info;
+                  r_symndx++)
+               if (local_sections[r_symndx] == sec)
+                 break;
+             if (r_symndx >= symtab_hdr->sh_info)
+               r_symndx = 0;
+             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+             if (r_symndx != 0)
+               rel->r_addend -= (local_syms[r_symndx].st_value
+                                 + sec->output_offset
+                                 + sec->output_section->vma);
+
+             rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
+             rel->r_offset += d_offset;
+             insn2 = 0x38630000;       /* addi 3,3,0 */
+             bfd_put_32 (output_bfd, insn2,
+                         contents + rel->r_offset - d_offset);
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
+             rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+                                           R_PPC_NONE);
+             rel--;
+             continue;
+           }
+         break;
        }
 
       /* Handle other relocations that tweak non-addend part of insn.  */
@@ -6468,6 +6611,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_NONE:
        case R_PPC_TLS:
+       case R_PPC_TLSGD:
+       case R_PPC_TLSLD:
        case R_PPC_EMB_MRKREF:
        case R_PPC_GNU_VTINHERIT:
        case R_PPC_GNU_VTENTRY:
@@ -6509,6 +6654,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_GOT16_LO:
        case R_PPC_GOT16_HI:
        case R_PPC_GOT16_HA:
+         tls_mask = 0;
        dogot:
          {
            /* Relocation is to the entry for this symbol in the global
index 703a2b34cbabd160b615d421954b7825f05b0457..1873728f38e83588ae067952172b664249b79740 100644 (file)
@@ -1235,7 +1235,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xfffc,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC64_TLS,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -1250,6 +1250,34 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC64_TLSGD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_TLSGD",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC64_TLSLD,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_TLSLD",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC64_DTPMOD64,
@@ -2031,6 +2059,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC_TLS:                    r = R_PPC64_TLS;
       break;
+    case BFD_RELOC_PPC_TLSGD:                  r = R_PPC64_TLSGD;
+      break;
+    case BFD_RELOC_PPC_TLSLD:                  r = R_PPC64_TLSLD;
+      break;
     case BFD_RELOC_PPC_DTPMOD:                 r = R_PPC64_DTPMOD64;
       break;
     case BFD_RELOC_PPC_TPREL16:                        r = R_PPC64_TPREL16;
@@ -4644,7 +4676,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       enum elf_ppc64_reloc_type r_type;
-      int tls_type = 0;
+      int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -4658,9 +4690,42 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      tls_type = 0;
       r_type = ELF64_R_TYPE (rel->r_info);
+      if (h != NULL && (h == tga || h == dottga))
+       switch (r_type)
+         {
+         default:
+           break;
+
+         case R_PPC64_REL24:
+         case R_PPC64_REL14:
+         case R_PPC64_REL14_BRTAKEN:
+         case R_PPC64_REL14_BRNTAKEN:
+         case R_PPC64_ADDR24:
+         case R_PPC64_ADDR14:
+         case R_PPC64_ADDR14_BRTAKEN:
+         case R_PPC64_ADDR14_BRNTAKEN:
+           if (rel != relocs
+               && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+                   || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+             /* We have a new-style __tls_get_addr call with a marker
+                reloc.  */
+             ;
+           else
+             /* Mark this section as having an old-style call.  */
+             sec->has_tls_get_addr_call = 1;
+           break;
+         }
+
       switch (r_type)
        {
+       case R_PPC64_TLSGD:
+       case R_PPC64_TLSLD:
+         /* These special tls relocs tie a call to __tls_get_addr with
+            its parameter symbol.  */
+         break;
+
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_HI:
@@ -7072,6 +7137,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                    case R_PPC64_TOC16:
                    case R_PPC64_TOC16_LO:
                    case R_PPC64_TLS:
+                   case R_PPC64_TLSGD:
+                   case R_PPC64_TLSLD:
                      if (sym_sec == NULL || sym_sec != toc)
                        continue;
 
@@ -7092,7 +7159,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      value += rel->r_addend;
                      BFD_ASSERT (value < toc->size && value % 8 == 0);
                      toc_ref_index = value / 8;
-                     if (r_type == R_PPC64_TLS)
+                     if (r_type == R_PPC64_TLS
+                         || r_type == R_PPC64_TLSGD
+                         || r_type == R_PPC64_TLSLD)
                        {
                          toc_ref[toc_ref_index] = 1;
                          continue;
@@ -7157,7 +7226,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
 
                  if (pass == 0)
                    {
-                     if (!expecting_tls_get_addr)
+                     if (!expecting_tls_get_addr
+                         || !sec->has_tls_get_addr_call)
                        continue;
 
                      if (rel + 1 < relend
@@ -7276,18 +7346,18 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                free (relstart);
            }
 
-       if (toc_ref != NULL)
-         free (toc_ref);
+      if (toc_ref != NULL)
+       free (toc_ref);
 
-       if (locsyms != NULL
-           && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
-         {
-           if (!info->keep_memory)
-             free (locsyms);
-           else
-             elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
-         }
-      }
+      if (locsyms != NULL
+         && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
+       {
+         if (!info->keep_memory)
+           free (locsyms);
+         else
+           elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
+       }
+    }
   return TRUE;
 }
 
@@ -10288,28 +10358,28 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       tls_mask = 0;
       tls_gd = 0;
       toc_symndx = 0;
-      if (IS_PPC64_TLS_RELOC (r_type))
+      if (h != NULL)
+       tls_mask = h->tls_mask;
+      else if (local_got_ents != NULL)
        {
-         if (h != NULL)
-           tls_mask = h->tls_mask;
-         else if (local_got_ents != NULL)
-           {
-             char *lgot_masks;
-             lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
-             tls_mask = lgot_masks[r_symndx];
-           }
-         if (tls_mask == 0 && r_type == R_PPC64_TLS)
-           {
-             /* Check for toc tls entries.  */
-             char *toc_tls;
+         char *lgot_masks;
+         lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
+         tls_mask = lgot_masks[r_symndx];
+       }
+      if (tls_mask == 0
+         && (r_type == R_PPC64_TLS
+             || r_type == R_PPC64_TLSGD
+             || r_type == R_PPC64_TLSLD))
+       {
+         /* Check for toc tls entries.  */
+         char *toc_tls;
 
-             if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
-                                &local_syms, rel, input_bfd))
-               return FALSE;
+         if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+                            &local_syms, rel, input_bfd))
+           return FALSE;
 
-             if (toc_tls)
-               tls_mask = *toc_tls;
-           }
+         if (toc_tls)
+           tls_mask = *toc_tls;
        }
 
       /* Check that tls relocs are used with tls syms, and non-tls
@@ -10324,7 +10394,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  || (sym_type == STT_SECTION
                      && (sec->flags & SEC_THREAD_LOCAL) != 0))))
        {
-         if (r_type == R_PPC64_TLS && tls_mask != 0)
+         if (tls_mask != 0
+             && (r_type == R_PPC64_TLS
+                 || r_type == R_PPC64_TLSGD
+                 || r_type == R_PPC64_TLSLD))
            /* R_PPC64_TLS is OK against a symbol in the TOC.  */
            ;
          else
@@ -10520,9 +10593,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              bfd_vma offset;
 
            tls_ldgd_opt:
-             /* We know that the next reloc is on a tls_get_addr
-                call, since ppc64_elf_tls_optimize checks this.  */
-             offset = rel[1].r_offset;
+             offset = (bfd_vma) -1;
+             /* If not using the newer R_PPC64_TLSGD/LD to mark
+                __tls_get_addr calls, we must trust that the call
+                stays with its arg setup insns, ie. that the next
+                reloc is the __tls_get_addr call associated with
+                the current reloc.  Edit both insns.  */
+             if (input_section->has_tls_get_addr_call
+                 && rel + 1 < relend
+                 && branch_reloc_hash_match (input_bfd, rel + 1,
+                                             htab->tls_get_addr,
+                                             htab->tls_get_addr_fd))
+               offset = rel[1].r_offset;
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
@@ -10531,8 +10613,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  insn1 &= (1 << 26) - (1 << 2);
                  insn1 |= 58 << 26;    /* ld */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
-                 rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
-                                               R_PPC64_NONE);
+                 if (offset != (bfd_vma) -1)
+                   rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+                                                 R_PPC64_NONE);
                  if ((tls_mask & TLS_EXPLICIT) == 0)
                    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
                              + R_PPC64_GOT_TPREL16_DS);
@@ -10570,34 +10653,131 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    }
                  r_type = R_PPC64_TPREL16_HA;
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-                 rel[1].r_info = ELF64_R_INFO (r_symndx,
-                                               R_PPC64_TPREL16_LO);
-                 rel[1].r_offset += d_offset;
-                 rel[1].r_addend = rel->r_addend;
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info = ELF64_R_INFO (r_symndx,
+                                                   R_PPC64_TPREL16_LO);
+                     rel[1].r_offset = offset + d_offset;
+                     rel[1].r_addend = rel->r_addend;
+                   }
                }
              bfd_put_32 (output_bfd, insn1,
                          contents + rel->r_offset - d_offset);
+             if (offset != (bfd_vma) -1)
+               {
+                 insn3 = bfd_get_32 (output_bfd,
+                                     contents + offset + 4);
+                 if (insn3 == NOP
+                     || insn3 == CROR_151515 || insn3 == CROR_313131)
+                   {
+                     rel[1].r_offset += 4;
+                     bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                     insn2 = NOP;
+                   }
+                 bfd_put_32 (output_bfd, insn2, contents + offset);
+               }
+             if ((tls_mask & tls_gd) == 0
+                 && (tls_gd == 0 || toc_symndx != 0))
+               {
+                 /* We changed the symbol.  Start over in order
+                    to get h, sym, sec etc. right.  */
+                 rel--;
+                 continue;
+               }
+           }
+         break;
+
+       case R_PPC64_TLSGD:
+         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+           {
+             unsigned int insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             if ((tls_mask & TLS_TPRELGD) != 0)
+               {
+                 /* IE */
+                 r_type = R_PPC64_NONE;
+                 insn2 = 0x7c636a14;   /* add 3,3,13 */
+               }
+             else
+               {
+                 /* LE */
+                 if (toc_symndx != 0)
+                   {
+                     r_symndx = toc_symndx;
+                     rel->r_addend = toc_addend;
+                   }
+                 r_type = R_PPC64_TPREL16_LO;
+                 rel->r_offset = offset + d_offset;
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+               }
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+                                           R_PPC64_NONE);
              insn3 = bfd_get_32 (output_bfd,
                                  contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
-                 rel[1].r_offset += 4;
+                 rel->r_offset += 4;
                  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
                  insn2 = NOP;
                }
              bfd_put_32 (output_bfd, insn2, contents + offset);
-             if ((tls_mask & tls_gd) == 0
-                 && (tls_gd == 0 || toc_symndx != 0))
+             if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
                {
-                 /* We changed the symbol.  Start over in order
-                    to get h, sym, sec etc. right.  */
                  rel--;
                  continue;
                }
            }
          break;
 
+       case R_PPC64_TLSLD:
+         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+           {
+             unsigned int insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             if (toc_symndx)
+               sec = local_sections[toc_symndx];
+             for (r_symndx = 0;
+                  r_symndx < symtab_hdr->sh_info;
+                  r_symndx++)
+               if (local_sections[r_symndx] == sec)
+                 break;
+             if (r_symndx >= symtab_hdr->sh_info)
+               r_symndx = 0;
+             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+             if (r_symndx != 0)
+               rel->r_addend -= (local_syms[r_symndx].st_value
+                                 + sec->output_offset
+                                 + sec->output_section->vma);
+
+             r_type = R_PPC64_TPREL16_LO;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             rel->r_offset = offset + d_offset;
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+                                           R_PPC64_NONE);
+             insn2 = 0x38630000;       /* addi 3,3,0 */
+             insn3 = bfd_get_32 (output_bfd,
+                                 contents + offset + 4);
+             if (insn3 == NOP
+                 || insn3 == CROR_151515 || insn3 == CROR_313131)
+               {
+                 rel->r_offset += 4;
+                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                 insn2 = NOP;
+               }
+             bfd_put_32 (output_bfd, insn2, contents + offset);
+             rel--;
+             continue;
+           }
+         break;
+
        case R_PPC64_DTPMOD64:
          if (rel + 1 < relend
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
@@ -10851,6 +11031,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_NONE:
        case R_PPC64_TLS:
+       case R_PPC64_TLSGD:
+       case R_PPC64_TLSLD:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
          continue;
index 5814863f9d8432d71ea0b8429feb9b5b426dbf1c..9d83209d35980b5456a98cc100e78609b316963d 100644 (file)
@@ -1201,6 +1201,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_PPC64_PLTGOT16_DS",
   "BFD_RELOC_PPC64_PLTGOT16_LO_DS",
   "BFD_RELOC_PPC_TLS",
+  "BFD_RELOC_PPC_TLSGD",
+  "BFD_RELOC_PPC_TLSLD",
   "BFD_RELOC_PPC_DTPMOD",
   "BFD_RELOC_PPC_TPREL16",
   "BFD_RELOC_PPC_TPREL16_LO",
index 9e610255b1fb4d9e32bd06243f81518b43e23087..5e10e7ed7084b71b73a352a8d93f9c5ffb924cdf 100644 (file)
@@ -2710,6 +2710,10 @@ ENUMDOC
 
 ENUM
   BFD_RELOC_PPC_TLS
+ENUMX
+  BFD_RELOC_PPC_TLSGD
+ENUMX
+  BFD_RELOC_PPC_TLSLD
 ENUMX
   BFD_RELOC_PPC_DTPMOD
 ENUMX
index cadba6b6d67c42a90d6048a5c99aabc9097109e5..d804dd614b7a0c6d2d5f1008e85a62d25e725807 100644 (file)
@@ -1,6 +1,6 @@
 /* Object file "section" support for the BFD library.
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Written by Cygnus Support.
 
@@ -382,6 +382,9 @@ CODE_FRAGMENT
 .  {* Nonzero if this section has TLS related relocations.  *}
 .  unsigned int has_tls_reloc:1;
 .
+.  {* Nonzero if this section has a call to __tls_get_addr.  *}
+.  unsigned int has_tls_get_addr_call:1;
+.
 .  {* Nonzero if this section has a gp reloc.  *}
 .  unsigned int has_gp_reloc:1;
 .
@@ -642,11 +645,11 @@ CODE_FRAGMENT
 .  {* segment_mark, sec_info_type, use_rela_p, has_tls_reloc,       *} \
 .     0,            0,             0,          0,                      \
 .                                                                      \
-.  {* has_gp_reloc, need_finalize_relax, reloc_done,                *} \
-.     0,            0,                   0,                            \
+.  {* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax,     *} \
+.     0,                     0,            0,                          \
 .                                                                      \
-.  {* vma, lma, size, rawsize                                       *} \
-.     0,   0,   0,    0,                                               \
+.  {* reloc_done, vma, lma, size, rawsize                           *} \
+.     0,          0,   0,   0,    0,                                   \
 .                                                                      \
 .  {* output_offset, output_section,              alignment_power,  *} \
 .     0,             (struct bfd_section *) &SEC, 0,                   \
index 92e922f6214ce0f0cc5bb06bae811ffb4fcf3c15..1bb757f6313e72947ec95d342872cbf0e88033b8 100644 (file)
@@ -1,3 +1,10 @@
+2009-03-04  Alan Modra  <amodra@bigpond.net.au>
+
+       * config/tc-ppc.c (ppc_elf_suffix): Error if ppc32 tls got relocs
+       have non-zero addend.
+       (md_assemble): Parse args of __tls_get_addr calls.
+       (md_apply_fix): Handle BFD_RELOC_PPC_TLSGD and BFD_RELOC_PPC_TLSLD.
+
 2009-03-03  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        binutils/3807
index c80dd188e1e3896e1ad181ce66833091cbf97f22..8b5c662984a01109a06ee5083633449840ddcdd9 100644 (file)
@@ -1974,13 +1974,38 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
       {
        int reloc = ptr->reloc;
 
-       if (!ppc_obj64)
-         if (exp_p->X_add_number != 0
-             && (reloc == (int) BFD_RELOC_16_GOTOFF
-                 || reloc == (int) BFD_RELOC_LO16_GOTOFF
-                 || reloc == (int) BFD_RELOC_HI16_GOTOFF
-                 || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-           as_warn (_("identifier+constant@got means identifier@got+constant"));
+       if (!ppc_obj64 && exp_p->X_add_number != 0)
+         {
+           switch (reloc)
+             {
+             case BFD_RELOC_16_GOTOFF:
+             case BFD_RELOC_LO16_GOTOFF:
+             case BFD_RELOC_HI16_GOTOFF:
+             case BFD_RELOC_HI16_S_GOTOFF:
+               as_warn (_("identifier+constant@got means "
+                          "identifier@got+constant"));
+               break;
+
+             case BFD_RELOC_PPC_GOT_TLSGD16:
+             case BFD_RELOC_PPC_GOT_TLSGD16_LO:
+             case BFD_RELOC_PPC_GOT_TLSGD16_HI:
+             case BFD_RELOC_PPC_GOT_TLSGD16_HA:
+             case BFD_RELOC_PPC_GOT_TLSLD16:
+             case BFD_RELOC_PPC_GOT_TLSLD16_LO:
+             case BFD_RELOC_PPC_GOT_TLSLD16_HI:
+             case BFD_RELOC_PPC_GOT_TLSLD16_HA:
+             case BFD_RELOC_PPC_GOT_DTPREL16:
+             case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+             case BFD_RELOC_PPC_GOT_DTPREL16_HI:
+             case BFD_RELOC_PPC_GOT_DTPREL16_HA:
+             case BFD_RELOC_PPC_GOT_TPREL16:
+             case BFD_RELOC_PPC_GOT_TPREL16_LO:
+             case BFD_RELOC_PPC_GOT_TPREL16_HI:
+             case BFD_RELOC_PPC_GOT_TPREL16_HA:
+               as_bad (_("symbol+offset not supported for got tls"));
+               break;
+             }
+         }
 
        /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
@@ -2797,121 +2822,168 @@ md_assemble (char *str)
                                     ppc_cpu, (char *) NULL, 0);
        }
 #ifdef OBJ_ELF
-      else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+      else
        {
-         /* Some TLS tweaks.  */
-         switch (reloc)
+         if (ex.X_op == O_symbol && str[0] == '(')
            {
-           default:
-             break;
-           case BFD_RELOC_PPC_TLS:
-             insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
-                                        ppc_cpu, (char *) NULL, 0);
-             break;
-         /* We'll only use the 32 (or 64) bit form of these relocations
-            in constants.  Instructions get the 16 bit form.  */
-           case BFD_RELOC_PPC_DTPREL:
-             reloc = BFD_RELOC_PPC_DTPREL16;
-             break;
-           case BFD_RELOC_PPC_TPREL:
-             reloc = BFD_RELOC_PPC_TPREL16;
-             break;
-           }
+             const char *sym_name = S_GET_NAME (ex.X_add_symbol);
+             if (sym_name[0] == '.')
+               ++sym_name;
 
-         /* For the absolute forms of branches, convert the PC
-            relative form back into the absolute.  */
-         if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
-           {
-             switch (reloc)
+             if (strcasecmp (sym_name, "__tls_get_addr") == 0)
                {
-               case BFD_RELOC_PPC_B26:
-                 reloc = BFD_RELOC_PPC_BA26;
-                 break;
-               case BFD_RELOC_PPC_B16:
-                 reloc = BFD_RELOC_PPC_BA16;
-                 break;
-               case BFD_RELOC_PPC_B16_BRTAKEN:
-                 reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
-                 break;
-               case BFD_RELOC_PPC_B16_BRNTAKEN:
-                 reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
-                 break;
-               default:
-                 break;
+                 expressionS tls_exp;
+
+                 hold = input_line_pointer;
+                 input_line_pointer = str + 1;
+                 expression (&tls_exp);
+                 if (tls_exp.X_op == O_symbol)
+                   {
+                     reloc = BFD_RELOC_UNUSED;
+                     if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
+                       {
+                         reloc = BFD_RELOC_PPC_TLSGD;
+                         input_line_pointer += 7;
+                       }
+                     else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0)
+                       {
+                         reloc = BFD_RELOC_PPC_TLSLD;
+                         input_line_pointer += 7;
+                       }
+                     if (reloc != BFD_RELOC_UNUSED)
+                       {
+                         SKIP_WHITESPACE ();
+                         str = input_line_pointer;
+
+                         if (fc >= MAX_INSN_FIXUPS)
+                           as_fatal (_("too many fixups"));
+                         fixups[fc].exp = tls_exp;
+                         fixups[fc].opindex = *opindex_ptr;
+                         fixups[fc].reloc = reloc;
+                         ++fc;
+                       }
+                   }
+                 input_line_pointer = hold;
                }
            }
 
-         if (ppc_obj64
-             && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
+         if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
            {
+             /* Some TLS tweaks.  */
              switch (reloc)
                {
-               case BFD_RELOC_16:
-                 reloc = BFD_RELOC_PPC64_ADDR16_DS;
-                 break;
-               case BFD_RELOC_LO16:
-                 reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
-                 break;
-               case BFD_RELOC_16_GOTOFF:
-                 reloc = BFD_RELOC_PPC64_GOT16_DS;
-                 break;
-               case BFD_RELOC_LO16_GOTOFF:
-                 reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
-                 break;
-               case BFD_RELOC_LO16_PLTOFF:
-                 reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
-                 break;
-               case BFD_RELOC_16_BASEREL:
-                 reloc = BFD_RELOC_PPC64_SECTOFF_DS;
-                 break;
-               case BFD_RELOC_LO16_BASEREL:
-                 reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_TOC16:
-                 reloc = BFD_RELOC_PPC64_TOC16_DS;
-                 break;
-               case BFD_RELOC_PPC64_TOC16_LO:
-                 reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC64_PLTGOT16:
-                 reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
-                 break;
-               case BFD_RELOC_PPC64_PLTGOT16_LO:
-                 reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_DTPREL16:
-                 reloc = BFD_RELOC_PPC64_DTPREL16_DS;
-                 break;
-               case BFD_RELOC_PPC_DTPREL16_LO:
-                 reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_TPREL16:
-                 reloc = BFD_RELOC_PPC64_TPREL16_DS;
+               default:
                  break;
-               case BFD_RELOC_PPC_TPREL16_LO:
-                 reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+
+               case BFD_RELOC_PPC_TLS:
+                 insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
+                                            ppc_cpu, (char *) NULL, 0);
                  break;
-               case BFD_RELOC_PPC_GOT_DTPREL16:
-               case BFD_RELOC_PPC_GOT_DTPREL16_LO:
-               case BFD_RELOC_PPC_GOT_TPREL16:
-               case BFD_RELOC_PPC_GOT_TPREL16_LO:
+
+                 /* We'll only use the 32 (or 64) bit form of these relocations
+                    in constants.  Instructions get the 16 bit form.  */
+               case BFD_RELOC_PPC_DTPREL:
+                 reloc = BFD_RELOC_PPC_DTPREL16;
                  break;
-               default:
-                 as_bad (_("unsupported relocation for DS offset field"));
+               case BFD_RELOC_PPC_TPREL:
+                 reloc = BFD_RELOC_PPC_TPREL16;
                  break;
                }
+
+             /* For the absolute forms of branches, convert the PC
+                relative form back into the absolute.  */
+             if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+               {
+                 switch (reloc)
+                   {
+                   case BFD_RELOC_PPC_B26:
+                     reloc = BFD_RELOC_PPC_BA26;
+                     break;
+                   case BFD_RELOC_PPC_B16:
+                     reloc = BFD_RELOC_PPC_BA16;
+                     break;
+                   case BFD_RELOC_PPC_B16_BRTAKEN:
+                     reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
+                     break;
+                   case BFD_RELOC_PPC_B16_BRNTAKEN:
+                     reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
+                     break;
+                   default:
+                     break;
+                   }
+               }
+
+             if (ppc_obj64
+                 && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
+               {
+                 switch (reloc)
+                   {
+                   case BFD_RELOC_16:
+                     reloc = BFD_RELOC_PPC64_ADDR16_DS;
+                     break;
+                   case BFD_RELOC_LO16:
+                     reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
+                     break;
+                   case BFD_RELOC_16_GOTOFF:
+                     reloc = BFD_RELOC_PPC64_GOT16_DS;
+                     break;
+                   case BFD_RELOC_LO16_GOTOFF:
+                     reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
+                     break;
+                   case BFD_RELOC_LO16_PLTOFF:
+                     reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
+                     break;
+                   case BFD_RELOC_16_BASEREL:
+                     reloc = BFD_RELOC_PPC64_SECTOFF_DS;
+                     break;
+                   case BFD_RELOC_LO16_BASEREL:
+                     reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_TOC16:
+                     reloc = BFD_RELOC_PPC64_TOC16_DS;
+                     break;
+                   case BFD_RELOC_PPC64_TOC16_LO:
+                     reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC64_PLTGOT16:
+                     reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
+                     break;
+                   case BFD_RELOC_PPC64_PLTGOT16_LO:
+                     reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_DTPREL16:
+                     reloc = BFD_RELOC_PPC64_DTPREL16_DS;
+                     break;
+                   case BFD_RELOC_PPC_DTPREL16_LO:
+                     reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_TPREL16:
+                     reloc = BFD_RELOC_PPC64_TPREL16_DS;
+                     break;
+                   case BFD_RELOC_PPC_TPREL16_LO:
+                     reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_GOT_DTPREL16:
+                   case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+                   case BFD_RELOC_PPC_GOT_TPREL16:
+                   case BFD_RELOC_PPC_GOT_TPREL16_LO:
+                     break;
+                   default:
+                     as_bad (_("unsupported relocation for DS offset field"));
+                     break;
+                   }
+               }
            }
 
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
            as_fatal (_("too many fixups"));
          fixups[fc].exp = ex;
-         fixups[fc].opindex = 0;
+         fixups[fc].opindex = *opindex_ptr;
          fixups[fc].reloc = reloc;
          ++fc;
        }
-#endif /* OBJ_ELF */
-
+#else /* OBJ_ELF */
       else
        {
          /* We need to generate a fixup for this expression.  */
@@ -2922,6 +2994,7 @@ md_assemble (char *str)
          fixups[fc].reloc = BFD_RELOC_UNUSED;
          ++fc;
        }
+#endif /* OBJ_ELF */
 
       if (need_paren)
        {
@@ -3006,9 +3079,6 @@ md_assemble (char *str)
      md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
-      const struct powerpc_operand *operand;
-
-      operand = &powerpc_operands[fixups[i].opindex];
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
        {
          reloc_howto_type *reloc_howto;
@@ -3055,13 +3125,18 @@ md_assemble (char *str)
            }
        }
       else
-       fix_new_exp (frag_now,
-                    f - frag_now->fr_literal,
-                    4,
-                    &fixups[i].exp,
-                    (operand->flags & PPC_OPERAND_RELATIVE) != 0,
-                    ((bfd_reloc_code_real_type)
-                     (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+       {
+         const struct powerpc_operand *operand;
+
+         operand = &powerpc_operands[fixups[i].opindex];
+         fix_new_exp (frag_now,
+                      f - frag_now->fr_literal,
+                      4,
+                      &fixups[i].exp,
+                      (operand->flags & PPC_OPERAND_RELATIVE) != 0,
+                      ((bfd_reloc_code_real_type)
+                       (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+       }
     }
 }
 
@@ -6155,6 +6230,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          break;
 
        case BFD_RELOC_PPC_TLS:
+       case BFD_RELOC_PPC_TLSGD:
+       case BFD_RELOC_PPC_TLSLD:
          break;
 
        case BFD_RELOC_PPC_DTPMOD:
index 606a170f61f8d752d95798ab7a98aca8db645769..354fd61091077293f37d87647de66bb118479057 100644 (file)
@@ -1,3 +1,8 @@
+2009-03-04  Alan Modra  <amodra@bigpond.net.au>
+
+       * ppc.h (R_PPC_TLSGD, R_PPC_TLSLD): Add new relocs.
+       * ppc64.h (R_PPC64_TLSGD, R_PPC64_TLSLD): Add new relocs.
+
 2009-03-02  Qinwei  <qinwei@sunnorth.com.cn>
 
        * score.h (RELOC_NUMBER): Add R_SCORE_IMM32.
index a0c16f1a7c843acdeb2e6c1953add7ef7d7129f2..06df6303e441b6622b82ca8e0ebcb659c799e06f 100644 (file)
@@ -1,6 +1,6 @@
 /* PPC ELF support for BFD.
-   Copyright 1995, 1996, 1998, 2000, 2001, 2002, 2003, 2005, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1998, 2000, 2001, 2002, 2003, 2005, 2007, 2008,
+   2009 Free Software Foundation, Inc.
 
    By Michael Meissner, Cygnus Support, <meissner@cygnus.com>, from information
    in the System V Application Binary Interface, PowerPC Processor Supplement
@@ -100,6 +100,8 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
   RELOC_NUMBER (R_PPC_GOT_DTPREL16_LO,  92)
   RELOC_NUMBER (R_PPC_GOT_DTPREL16_HI,  93)
   RELOC_NUMBER (R_PPC_GOT_DTPREL16_HA,  94)
+  RELOC_NUMBER (R_PPC_TLSGD,            95)
+  RELOC_NUMBER (R_PPC_TLSLD,            96)
 
 /* The remaining relocs are from the Embedded ELF ABI, and are not
    in the SVR4 ELF ABI.  */
index 4aab2ec9446a0d82d69369057dc7a402dcd535d2..c768180b467d362949aaa4675235124bfc20e63a 100644 (file)
@@ -1,5 +1,5 @@
 /* PPC64 ELF support for BFD.
-   Copyright 2003 Free Software Foundation, Inc.
+   Copyright 2003, 2005, 2009 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -136,6 +136,8 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
   RELOC_NUMBER (R_PPC64_DTPREL16_HIGHERA,  104)
   RELOC_NUMBER (R_PPC64_DTPREL16_HIGHEST,  105)
   RELOC_NUMBER (R_PPC64_DTPREL16_HIGHESTA, 106)
+  RELOC_NUMBER (R_PPC64_TLSGD,            107)
+  RELOC_NUMBER (R_PPC64_TLSLD,            108)
 
   /* These are GNU extensions to enable C++ vtable garbage collection.  */
   RELOC_NUMBER (R_PPC64_GNU_VTINHERIT,    253)
index c338bb48d4617f2962caaec24975dd5fa90da98b..60465f7e7906da87ef61493bb50e73926b1d038d 100644 (file)
@@ -1,3 +1,9 @@
+2009-03-04  Alan Modra  <amodra@bigpond.net.au>
+
+       * ld-powerpc/tlsmark.s, * ld-powerpc/tlsmark.d: New test.
+       * ld-powerpc/tlsmark32.s, * ld-powerpc/tlsmark32.d: New test.
+       * ld-powerpc/powerpc.exp: Run them.
+
 2009-03-02  Sebastian Huber  <sebastian.huber@embedded-brains.de>
 
        * ld-scripts/regions-alias-1.t: New file.
index 1630cd71d74f93caf41fc8e4be7eba5b3d815d01..2ed41f27127ab26203fe89fdd9ff4822a720e53d 100644 (file)
@@ -1,5 +1,5 @@
 # Expect script for ld-powerpc tests
-#   Copyright 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation
+#   Copyright 2002, 2003, 2005, 2006, 2007, 2008, 2009 Free Software Foundation
 #
 # This file is part of the GNU Binutils.
 #
@@ -112,6 +112,9 @@ set ppcelftests {
      {{readelf -WSsrl tlsso32.r} {objdump -dr tlsso32.d}
       {objdump -sj.got tlsso32.g} {objdump -sj.tdata tlsso32.t}}
       "tls32.so"}
+    {"TLS32 markers" "-melf32ppc" "-a32"  {tlsmark32.s tlslib32.s}
+     {{objdump -dr tlsmark32.d}}
+      "tlsmark32"}
     {"Shared library with global symbol" "-shared -melf32ppc" "-a32" {sdalib.s}
      {} "sdalib.so"}
     {"Dynamic application with SDA" "-melf32ppc tmpdir/sdalib.so" "-a32" {sdadyn.s}
@@ -145,6 +148,9 @@ set ppc64elftests {
      {{readelf -WSsrl tlstocso.r} {objdump -dr tlstocso.d}
       {objdump -sj.got tlstocso.g} {objdump -sj.tdata tlstocso.t}}
       "tlstoc.so"}
+    {"TLS markers" "-melf64ppc" "-a64"  {tlsmark.s tlslib.s}
+     {{objdump -dr tlsmark.d}}
+      "tlsmark"}
     {"sym@tocbase" "-shared -melf64ppc" "-a64" {symtocbase-1.s symtocbase-2.s}
        {{objdump -dj.data symtocbase.d}} "symtocbase.so"}
 }
diff --git a/ld/testsuite/ld-powerpc/tlsmark.d b/ld/testsuite/ld-powerpc/tlsmark.d
new file mode 100644 (file)
index 0000000..8ba350e
--- /dev/null
@@ -0,0 +1,42 @@
+#source: tlsmark.s
+#source: tlslib.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+100000e8 <_start>:
+    100000e8:  48 00 00 18     b       10000100 <_start\+0x18>
+    100000ec:  60 00 00 00     nop
+    100000f0:  38 63 90 00     addi    r3,r3,-28672
+    100000f4:  e8 83 00 00     ld      r4,0\(r3\)
+    100000f8:  3c 6d 00 00     addis   r3,r13,0
+    100000fc:  48 00 00 0c     b       10000108 <_start\+0x20>
+    10000100:  3c 6d 00 00     addis   r3,r13,0
+    10000104:  4b ff ff e8     b       100000ec <_start\+0x4>
+    10000108:  60 00 00 00     nop
+    1000010c:  38 63 10 00     addi    r3,r3,4096
+    10000110:  e8 83 80 00     ld      r4,-32768\(r3\)
+    10000114:  3c 6d 00 00     addis   r3,r13,0
+    10000118:  48 00 00 0c     b       10000124 <_start\+0x3c>
+    1000011c:  3c 6d 00 00     addis   r3,r13,0
+    10000120:  48 00 00 14     b       10000134 <_start\+0x4c>
+    10000124:  60 00 00 00     nop
+    10000128:  38 63 90 04     addi    r3,r3,-28668
+    1000012c:  e8 a3 00 00     ld      r5,0\(r3\)
+    10000130:  4b ff ff ec     b       1000011c <_start\+0x34>
+    10000134:  60 00 00 00     nop
+    10000138:  38 63 10 00     addi    r3,r3,4096
+    1000013c:  e8 a3 80 04     ld      r5,-32764\(r3\)
+    10000140:  38 62 80 28     addi    r3,r2,-32728
+    10000144:  3f a0 10 01     lis     r29,4097
+    10000148:  3b bd 01 68     addi    r29,r29,360
+    1000014c:  48 00 00 09     bl      10000154 <\.__tls_get_addr>
+    10000150:  60 00 00 00     nop
+
+0+10000154 <\.__tls_get_addr>:
+    10000154:  4e 80 00 20     blr
diff --git a/ld/testsuite/ld-powerpc/tlsmark.s b/ld/testsuite/ld-powerpc/tlsmark.s
new file mode 100644 (file)
index 0000000..dc42327
--- /dev/null
@@ -0,0 +1,55 @@
+       .section ".tdata","awT",@progbits
+x:     .int 1
+y:     .int 2
+
+       .section ".toc","aw",@progbits
+       .p2align 3
+.LC0:
+       .quad y@dtpmod
+       .quad y@dtprel
+.LC1:
+       .quad y@dtpmod
+       .quad 0
+
+       .text
+       .global _start
+_start:
+       b .L2
+
+.L1:
+       bl __tls_get_addr(x@tlsgd)
+       nop
+       ld 4,0(3)
+       addi 3,2,x@got@tlsld
+       b .L3
+.L2:
+       addi 3,2,x@got@tlsgd
+       b .L1
+.L3:
+       bl __tls_get_addr(x@tlsld)
+       nop
+       ld 4,x@dtprel(3)
+
+       addi 3,2,.LC0@toc
+       b .L5
+.L4:
+       addi 3,2,.LC1@toc
+       b .L6
+.L5:
+       bl .__tls_get_addr(.LC0@tlsgd)
+       nop
+       ld 5,0(3)
+       b .L4
+.L6:
+       bl .__tls_get_addr(.LC1@tlsld)
+       nop
+       ld 5,y@dtprel(3)
+
+
+       .section ".text.no","ax",@progbits
+       .p2align 2
+       addi 3,2,gd@got@tlsgd
+       lis 29,__tls_get_addr@ha
+       addi 29,29,__tls_get_addr@l
+       bl __tls_get_addr
+       nop
diff --git a/ld/testsuite/ld-powerpc/tlsmark32.d b/ld/testsuite/ld-powerpc/tlsmark32.d
new file mode 100644 (file)
index 0000000..74b74e3
--- /dev/null
@@ -0,0 +1,29 @@
+#source: tlsmark32.s
+#source: tlslib32.s
+#as: -a32
+#ld: -melf32ppc
+#objdump: -dr
+#target: powerpc*-*-*
+
+.*:     file format elf32-powerpc
+
+Disassembly of section \.text:
+
+0+1800094 <_start>:
+ 1800094:      48 00 00 14     b       18000a8 <_start\+0x14>
+ 1800098:      38 63 90 00     addi    r3,r3,-28672
+ 180009c:      80 83 00 00     lwz     r4,0\(r3\)
+ 18000a0:      3c 62 00 00     addis   r3,r2,0
+ 18000a4:      48 00 00 0c     b       18000b0 <_start\+0x1c>
+ 18000a8:      3c 62 00 00     addis   r3,r2,0
+ 18000ac:      4b ff ff ec     b       1800098 <_start\+0x4>
+ 18000b0:      38 63 10 00     addi    r3,r3,4096
+ 18000b4:      80 83 80 00     lwz     r4,-32768\(r3\)
+ 18000b8:      38 7f ff f4     addi    r3,r31,-12
+ 18000bc:      3f a0 01 80     lis     r29,384
+ 18000c0:      3b bd 00 c8     addi    r29,r29,200
+ 18000c4:      48 00 00 05     bl      18000c8 <__tls_get_addr>
+
+0+18000c8 <__tls_get_addr>:
+ 18000c8:      4e 80 00 20     blr
+#pass
\ No newline at end of file
diff --git a/ld/testsuite/ld-powerpc/tlsmark32.s b/ld/testsuite/ld-powerpc/tlsmark32.s
new file mode 100644 (file)
index 0000000..2fa48ae
--- /dev/null
@@ -0,0 +1,27 @@
+       .section ".tdata","awT",@progbits
+x:     .int 1
+
+       .text
+       .global _start
+_start:
+       b .L2
+
+.L1:
+       bl __tls_get_addr(x@tlsgd)
+       lwz 4,0(3)
+       addi 3,31,x@got@tlsld
+       b .L3
+.L2:
+       addi 3,31,x@got@tlsgd
+       b .L1
+.L3:
+       bl __tls_get_addr(x@tlsld)
+       lwz 4,x@dtprel(3)
+
+
+       .section ".text.no","ax",@progbits
+       .p2align 2
+       addi 3,31,gd@got@tlsgd
+       lis 29,__tls_get_addr@ha
+       addi 29,29,__tls_get_addr@l
+       bl __tls_get_addr