2006-04-08 H.J. Lu <hongjiu.lu@intel.com>
authorH.J. Lu <hjl.tools@gmail.com>
Sat, 8 Apr 2006 22:57:22 +0000 (22:57 +0000)
committerH.J. Lu <hjl.tools@gmail.com>
Sat, 8 Apr 2006 22:57:22 +0000 (22:57 +0000)
PR ld/2513
* elf32-i386.c (GOT_TLS_MASK): New macro for tls_type.
(GOT_TLS_IE_IE): Likewise.
(GOT_TLS_IE_GD): Likewise.
(GOT_TLS_IE_MASK): Likewise.
(elf_i386_check_relocs): For global symbols, set GOT_TLS_IE_GD
and GOT_TLS_IE_IE for R_386_TLS_GD and R_386_TLS_IE
respectively.
(allocate_dynrelocs): If both GOT_TLS_IE_IE and GOT_TLS_IE_GD
are set, treat tls_type as GOT_TLS_IE_BOTH.
(elf_i386_relocate_section): Likewise.

bfd/ChangeLog
bfd/elf32-i386.c

index 67e9fd27da4db56eb1dc464c7c0262daf95afb23..661bda424163d692a59d09d6cf294aef9b870a04 100644 (file)
@@ -1,3 +1,17 @@
+2006-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/2513
+       * elf32-i386.c (GOT_TLS_MASK): New macro for tls_type.
+       (GOT_TLS_IE_IE): Likewise.
+       (GOT_TLS_IE_GD): Likewise.
+       (GOT_TLS_IE_MASK): Likewise.
+       (elf_i386_check_relocs): For global symbols, set GOT_TLS_IE_GD
+       and GOT_TLS_IE_IE for R_386_TLS_GD and R_386_TLS_IE
+       respectively.
+       (allocate_dynrelocs): If both GOT_TLS_IE_IE and GOT_TLS_IE_GD
+       are set, treat tls_type as GOT_TLS_IE_BOTH.
+       (elf_i386_relocate_section): Likewise.
+
 2006-04-07  Randolph Chung  <tausq@debian.org>
 
        * elf64-hppa.c (elf64_hppa_grok_prstatus): New function.
index bc44cba972ccc163aff6fa48cd1905af4f2d09a7..754aa52254d5509d8b13a296884c54fc7f860ced 100644 (file)
@@ -582,6 +582,10 @@ struct elf_i386_link_hash_entry
 #define GOT_TLS_IE_NEG 6
 #define GOT_TLS_IE_BOTH 7
 #define GOT_TLS_GDESC  8
+#define GOT_TLS_MASK   0x0f
+#define GOT_TLS_IE_IE  0x10
+#define GOT_TLS_IE_GD  0x20
+#define GOT_TLS_IE_MASK        0x30
 #define GOT_TLS_GD_BOTH_P(type)                                                \
   ((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
 #define GOT_TLS_GD_P(type)                                             \
@@ -1007,12 +1011,25 @@ elf_i386_check_relocs (bfd *abfd,
              case R_386_TLS_IE_32:
                if (ELF32_R_TYPE (rel->r_info) == r_type)
                  tls_type = GOT_TLS_IE_NEG;
+               else if (h
+                        && ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
+                 /* If this is a GD->IE transition, we may use either
+                    of R_386_TLS_TPOFF and R_386_TLS_TPOFF32.  But if
+                    we may have both R_386_TLS_IE and R_386_TLS_GD,
+                    we can't share the same R_386_TLS_TPOFF since
+                    they require different offsets. So we remember
+                    it comes from R_386_TLS_GD.  */
+                 tls_type = GOT_TLS_IE | GOT_TLS_IE_GD;
                else
-                 /* If this is a GD->IE transition, we may use either of
-                    R_386_TLS_TPOFF and R_386_TLS_TPOFF32.  */
                  tls_type = GOT_TLS_IE;
                break;
              case R_386_TLS_IE:
+               if (h)
+                 {
+                   /* We remember it comes from R_386_TLS_IE.  */
+                   tls_type = GOT_TLS_IE_POS | GOT_TLS_IE_IE;
+                   break;
+                 }
              case R_386_TLS_GOTIE:
                tls_type = GOT_TLS_IE_POS; break;
              }
@@ -1052,7 +1069,8 @@ elf_i386_check_relocs (bfd *abfd,
              tls_type |= old_tls_type;
            /* If a TLS symbol is accessed using IE at least once,
               there is no point to use dynamic model for it.  */
-           else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+           else if (old_tls_type != tls_type
+                    && old_tls_type != GOT_UNKNOWN
                     && (! GOT_TLS_GD_ANY_P (old_tls_type)
                         || (tls_type & GOT_TLS_IE) == 0))
              {
@@ -1682,6 +1700,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       asection *s;
       bfd_boolean dyn;
       int tls_type = elf_i386_hash_entry(h)->tls_type;
+      
+      /* If we have both R_386_TLS_IE and R_386_TLS_GD, GOT_TLS_IE_BOTH
+        should be used.  */
+      if ((tls_type & GOT_TLS_IE_MASK)
+         == (GOT_TLS_IE_IE | GOT_TLS_IE_GD))
+       tls_type = GOT_TLS_IE_BOTH;
+      else
+       tls_type &= GOT_TLS_MASK;
 
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -2685,6 +2711,13 @@ elf_i386_relocate_section (bfd *output_bfd,
          else if (h != NULL)
            {
              tls_type = elf_i386_hash_entry(h)->tls_type;
+             /* If we have both R_386_TLS_IE and R_386_TLS_GD,
+                GOT_TLS_IE_BOTH should be used.  */
+             if ((tls_type & GOT_TLS_IE_MASK)
+                 == (GOT_TLS_IE_IE | GOT_TLS_IE_GD))
+               tls_type = GOT_TLS_IE_BOTH;
+             else
+               tls_type &= GOT_TLS_MASK;
              if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
                r_type = R_386_TLS_LE_32;
            }