* elfxx-mips.c (mips_got_entry): Add more commentary.
authorRichard Sandiford <rdsandiford@googlemail.com>
Mon, 27 Mar 2006 11:30:54 +0000 (11:30 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Mon, 27 Mar 2006 11:30:54 +0000 (11:30 +0000)
(mips_elf_local_got_index): Use the hash table entry to record
the GOT index of forced-local symbols.
(mips_elf_initialize_tls_index): Rearrange code.  Store the index
in either the hash table entry or the mips_got_entry, not both.
Add more commentary.
(mips_elf_multi_got): Make sure the g->next is nonnull when calling
mips_elf_initialize_tls_index.

* ld-mips-elf/tls-hidden3a.s, ld-mips-elf/tls-hidden3b.s,
* ld-mips-elf/tls-hidden3.d, ld-mips-elf/tls-hidden3.got,
* ld-mips-elf/tls-hidden3.ld, ld-mips-elf/tls-hidden3.r,
* ld-mips-elf/tls-hidden4a.s, ld-mips-elf/tls-hidden4b.s,
* ld-mips-elf/tls-hidden4.got, ld-mips-elf/tls-hidden4.r: New tests.
* ld-mips-elf/mips-elf.exp: Run them.

14 files changed:
bfd/ChangeLog
bfd/elfxx-mips.c
ld/testsuite/ChangeLog
ld/testsuite/ld-mips-elf/mips-elf.exp
ld/testsuite/ld-mips-elf/tls-hidden3.d [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden3.got [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden3.ld [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden3.r [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden3a.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden3b.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden4.got [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden4.r [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden4a.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/tls-hidden4b.s [new file with mode: 0644]

index 08eb42d..47d19f7 100644 (file)
@@ -1,3 +1,14 @@
+2006-03-27  Richard Sandiford  <richard@codesourcery.com>
+
+       * elfxx-mips.c (mips_got_entry): Add more commentary.
+       (mips_elf_local_got_index): Use the hash table entry to record
+       the GOT index of forced-local symbols.
+       (mips_elf_initialize_tls_index): Rearrange code.  Store the index
+       in either the hash table entry or the mips_got_entry, not both.
+       Add more commentary.
+       (mips_elf_multi_got): Make sure the g->next is nonnull when calling
+       mips_elf_initialize_tls_index.
+
 2006-03-25  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * elf32-bfin.c (bfd_const_reloc, bfd_oper_reloc, bfin_push_reloc,
index c9862d4..4e27a53 100644 (file)
 
 #include "hashtab.h"
 
-/* This structure is used to hold .got entries while estimating got
-   sizes.  */
+/* This structure is used to hold information about one GOT entry.
+   There are three types of entry:
+
+      (1) absolute addresses
+           (abfd == NULL)
+      (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd
+           (abfd != NULL, symndx >= 0)
+      (3) global and forced-local symbols
+           (abfd != NULL, symndx == -1)
+
+   Type (3) entries are treated differently for different types of GOT.
+   In the "master" GOT -- i.e.  the one that describes every GOT
+   reference needed in the link -- the mips_got_entry is keyed on both
+   the symbol and the input bfd that references it.  If it turns out
+   that we need multiple GOTs, we can then use this information to
+   create separate GOTs for each input bfd.
+
+   However, we want each of these separate GOTs to have at most one
+   entry for a given symbol, so their type (3) entries are keyed only
+   on the symbol.  The input bfd given by the "abfd" field is somewhat
+   arbitrary in this case.
+
+   This means that when there are multiple GOTs, each GOT has a unique
+   mips_got_entry for every symbol within it.  We can therefore use the
+   mips_got_entry fields (tls_type and gotidx) to track the symbol's
+   GOT index.
+
+   However, if it turns out that we need only a single GOT, we continue
+   to use the master GOT to describe it.  There may therefore be several
+   mips_got_entries for the same symbol, each with a different input bfd.
+   We want to make sure that each symbol gets a unique GOT entry, so when
+   there's a single GOT, we use the symbol's hash entry, not the
+   mips_got_entry fields, to track a symbol's GOT index.  */
 struct mips_got_entry
 {
   /* The input bfd in which the symbol is defined.  */
@@ -2371,8 +2402,16 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
     return MINUS_ONE;
 
   if (TLS_RELOC_P (r_type))
-    return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type, r_type,
-                              info, h, value);
+    {
+      if (entry->symndx == -1 && g->next == NULL)
+       /* A type (3) entry in the single-GOT case.  We use the symbol's
+          hash table entry to track the index.  */
+       return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
+                                  r_type, info, h, value);
+      else
+       return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
+                                  r_type, info, h, value);
+    }
   else
     return entry->gotidx;
 }
@@ -3118,55 +3157,54 @@ mips_elf_merge_gots (void **bfd2got_, void *p)
   return 1;
 }
 
-/* Set the TLS GOT index for the GOT entry in ENTRYP.  */
+/* Set the TLS GOT index for the GOT entry in ENTRYP.  ENTRYP's NEXT field
+   is null iff there is just a single GOT.  */
 
 static int
 mips_elf_initialize_tls_index (void **entryp, void *p)
 {
   struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
   struct mips_got_info *g = p;
+  bfd_vma next_index;
 
   /* We're only interested in TLS symbols.  */
   if (entry->tls_type == 0)
     return 1;
 
-  if (entry->symndx == -1)
+  next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
+
+  if (entry->symndx == -1 && g->next == NULL)
     {
-      /* There may be multiple mips_got_entry structs for a global variable
-        if there is just one GOT.  Just do this once.  */
-      if (g->next == NULL)
+      /* A type (3) got entry in the single-GOT case.  We use the symbol's
+        hash table entry to track its index.  */
+      if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
+       return 1;
+      entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
+      entry->d.h->tls_got_offset = next_index;
+    }
+  else
+    {
+      if (entry->tls_type & GOT_TLS_LDM)
        {
-         if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
+         /* There are separate mips_got_entry objects for each input bfd
+            that requires an LDM entry.  Make sure that all LDM entries in
+            a GOT resolve to the same index.  */
+         if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
            {
-             entry->gotidx = entry->d.h->tls_got_offset;
+             entry->gotidx = g->tls_ldm_offset;
              return 1;
            }
-         entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
-       }
-    }
-  else if (entry->tls_type & GOT_TLS_LDM)
-    {
-      /* Similarly, there may be multiple structs for the LDM entry.  */
-      if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
-       {
-         entry->gotidx = g->tls_ldm_offset;
-         return 1;
+         g->tls_ldm_offset = next_index;
        }
+      entry->gotidx = next_index;
     }
 
-  /* Initialize the GOT offset.  */
-  entry->gotidx = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
-  if (g->next == NULL && entry->symndx == -1)
-    entry->d.h->tls_got_offset = entry->gotidx;
-
+  /* Account for the entries we've just allocated.  */
   if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
     g->tls_assigned_gotno += 2;
   if (entry->tls_type & GOT_TLS_IE)
     g->tls_assigned_gotno += 1;
 
-  if (entry->tls_type & GOT_TLS_LDM)
-    g->tls_ldm_offset = entry->gotidx;
-
   return 1;
 }
 
@@ -3492,16 +3530,19 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
       g->local_gotno += assign + pages;
       assign = g->local_gotno + g->global_gotno + g->tls_gotno;
 
+      /* Take g out of the direct list, and push it onto the reversed
+        list that gg points to.  g->next is guaranteed to be nonnull after
+        this operation, as required by mips_elf_initialize_tls_index. */
+      gn = g->next;
+      g->next = gg->next;
+      gg->next = g;
+
       /* Set up any TLS entries.  We always place the TLS entries after
         all non-TLS entries.  */
       g->tls_assigned_gotno = g->local_gotno + g->global_gotno;
       htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
 
-      /* Take g out of the direct list, and push it onto the reversed
-        list that gg points to.  */
-      gn = g->next;
-      g->next = gg->next;
-      gg->next = g;
+      /* Move onto the next GOT.  It will be a secondary GOT if nonull.  */
       g = gn;
 
       /* Mark global symbols in every non-primary GOT as ineligible for
index 4be03b8..7684e38 100644 (file)
@@ -1,3 +1,12 @@
+2006-03-27  Richard Sandiford  <richard@codesourcery.com>
+
+       * ld-mips-elf/tls-hidden3a.s, ld-mips-elf/tls-hidden3b.s,
+       * ld-mips-elf/tls-hidden3.d, ld-mips-elf/tls-hidden3.got,
+       * ld-mips-elf/tls-hidden3.ld, ld-mips-elf/tls-hidden3.r,
+       * ld-mips-elf/tls-hidden4a.s, ld-mips-elf/tls-hidden4b.s,
+       * ld-mips-elf/tls-hidden4.got, ld-mips-elf/tls-hidden4.r: New tests.
+       * ld-mips-elf/mips-elf.exp: Run them.
+
 2006-03-25  Richard Sandiford  <richard@codesourcery.com>
 
        * ld-m68k/merge-error-1a.s, ld-m68k/merge-error-1b.s,
index add2060..645b7e0 100644 (file)
@@ -199,6 +199,17 @@ set mips_tls_tests {
      "-EB -march=mips1 -32 -KPIC" {tls-hidden2a.s tls-hidden2b.s}
      {{objdump -drj.text tls-hidden2.d} {objdump -sj.got tls-hidden2-got.d}}
      "tls-hidden2.so"}
+    {"Shared library with TLS and hidden symbols (3)"
+     "-shared -melf32btsmip -T tls-hidden3.ld"
+     "-EB -march=mips2 -32 -KPIC" {tls-hidden3a.s tls-hidden3b.s}
+     {{objdump -dj.text tls-hidden3.d} {objdump -sj.got tls-hidden3.got}
+      {readelf --relocs tls-hidden3.r}}
+     "tls-hidden3.so"}
+    {"Shared library with TLS and hidden symbols (4)"
+     "-shared -melf32btsmip -T tls-hidden3.ld"
+     "-EB -march=mips2 -32 -KPIC" {tls-hidden4a.s tls-hidden4b.s}
+     {{objdump -sj.got tls-hidden4.got} {readelf --relocs tls-hidden4.r}}
+     "tls-hidden4.so"}
 }
 
 if {[istarget mips*-*-linux*]} {
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden3.d b/ld/testsuite/ld-mips-elf/tls-hidden3.d
new file mode 100644 (file)
index 0000000..6d58686
--- /dev/null
@@ -0,0 +1,24 @@
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+#
+# The TLS entries are ordered as follows:
+#
+#      foo0    (-0x7ff0 + 0x20)
+#      foo2    (-0x7ff0 + 0x24)
+#      foo3    (-0x7ff0 + 0x28)
+#      foo1    (-0x7ff0 + 0x2c)
+#
+# Any order would be acceptable, but it must match the .got dump.
+#
+00080c00 <\.text>:
+   80c00:      8f848030        lw      a0,-32720\(gp\)
+   80c04:      8f84803c        lw      a0,-32708\(gp\)
+   80c08:      8f848034        lw      a0,-32716\(gp\)
+   80c0c:      8f848038        lw      a0,-32712\(gp\)
+   80c10:      8f848030        lw      a0,-32720\(gp\)
+   80c14:      8f84803c        lw      a0,-32708\(gp\)
+   80c18:      8f848034        lw      a0,-32716\(gp\)
+   80c1c:      8f848038        lw      a0,-32712\(gp\)
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden3.got b/ld/testsuite/ld-mips-elf/tls-hidden3.got
new file mode 100644 (file)
index 0000000..8b9c87f
--- /dev/null
@@ -0,0 +1,24 @@
+
+.*:     file format .*
+
+#
+# The GOT layout is:
+#
+#      - 2 reserved entries
+#      - 5 local page entries
+#      - 1 global entry for "undef"
+#      - 4 TLS entries
+#
+# The order of the TLS entries is:
+#
+#      foo0    (offset 0x20)
+#      foo2    (offset 0x24)
+#      foo3    (offset 0x28)
+#      foo1    (offset 0x2c)
+#
+# Any order would be acceptable, but it must match the .d dump.
+#
+Contents of section \.got:
+ 90000 00000000 80000000 00000000 00000000  .*
+ 90010 00000000 00000000 00000000 00000000  .*
+ 90020 0000abc0 0000abc8 0000abcc 0000abc4  .*
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden3.ld b/ld/testsuite/ld-mips-elf/tls-hidden3.ld
new file mode 100644 (file)
index 0000000..b3d0584
--- /dev/null
@@ -0,0 +1,31 @@
+SECTIONS
+{
+  . = 0x80000;
+  .interp : { *(.interp) }
+  .hash : { *(.hash) }
+  .dynsym : { *(.dynsym) }
+  .dynstr : { *(.dynstr) }
+
+  . = ALIGN (0x400);
+  .rel.dyn : { *(.rel.dyn) }
+
+  . = ALIGN (0x400);
+  .MIPS.stubs : { *(.MIPS.stubs) }
+
+  . = ALIGN (0x400);
+  .text : { *(.text) }
+
+  . = ALIGN (0x10000);
+  _gp = . + 0x7ff0;
+  .got : { *(.got) }
+
+  . = ALIGN (0x400);
+  .tdata : { *(.tdata) }
+
+  /DISCARD/ : { *(.reginfo) }
+}
+
+VERSION
+{
+  { local: *; };
+}
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden3.r b/ld/testsuite/ld-mips-elf/tls-hidden3.r
new file mode 100644 (file)
index 0000000..500e7b1
--- /dev/null
@@ -0,0 +1,13 @@
+
+Relocation section '\.rel\.dyn' at offset .* contains 6 entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name
+00000000  00000000 R_MIPS_NONE      
+#
+# The order of the next four entries doesn't matter.  The important thing
+# is that there is exactly one entry per GOT TLS slot.
+#
+00090020  0000002f R_MIPS_TLS_TPREL3
+0009002c  0000002f R_MIPS_TLS_TPREL3
+00090024  0000002f R_MIPS_TLS_TPREL3
+00090028  0000002f R_MIPS_TLS_TPREL3
+00090030  .*03 R_MIPS_REL32      00000000   undef
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden3a.s b/ld/testsuite/ld-mips-elf/tls-hidden3a.s
new file mode 100644 (file)
index 0000000..d1e6d64
--- /dev/null
@@ -0,0 +1,10 @@
+       .macro  load
+       lw      $4,%gottprel(foo\@)($gp)
+       .endm
+
+       .rept   4
+       load
+       .endr
+
+       .section .tdata,"awT",@progbits
+       .fill   0xabc0
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden3b.s b/ld/testsuite/ld-mips-elf/tls-hidden3b.s
new file mode 100644 (file)
index 0000000..0744b07
--- /dev/null
@@ -0,0 +1,18 @@
+       .macro  load
+       .text
+       lw      $4,%gottprel(foo\@)($gp)
+
+       .global foo\@
+       .type   foo\@,@object
+       .size   foo\@,4
+       .section .tdata,"awT",@progbits
+foo\@:
+       .word   \@
+       .endm
+
+       .rept   4
+       load
+       .endr
+
+       .data
+       .word   undef
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden4.got b/ld/testsuite/ld-mips-elf/tls-hidden4.got
new file mode 100644 (file)
index 0000000..84120c0
--- /dev/null
@@ -0,0 +1,28 @@
+
+.*:     file format .*
+
+Contents of section \.got:
+#
+# The order of the TLS entries in this GOT is:
+#
+#     foo2
+#     foo3
+#     foo0
+#     foo1
+#
+# The order and address don't matter; the important thing is that the
+# addresses match the relocs in the .r dump and that there is a separate
+# entry for each symbol.
+#
+#...
+ 1c4080 0000abc8 0000abcc 0000abc0 0000abc4  .*
+#
+# Likewise, but the order of the entries in this GOT is:
+#
+#     foo3
+#     foo2
+#     foo0
+#     foo1
+#...
+ 1d00c0 00000000 00000000 00000000 0000abcc  .*
+ 1d00d0 0000abc8 0000abc0 0000abc4           .*
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden4.r b/ld/testsuite/ld-mips-elf/tls-hidden4.r
new file mode 100644 (file)
index 0000000..f6809b5
--- /dev/null
@@ -0,0 +1,19 @@
+
+Relocation section '\.rel\.dyn' at offset .* contains .* entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name
+00000000  00000000 R_MIPS_NONE      
+#
+# The order and addresses of the next eight entries don't matter.  The
+# important thing is that there is exactly one entry per GOT TLS slot
+# and that the addresses match those in the .got dump.
+#
+001d00d4  0000002f R_MIPS_TLS_TPREL3
+001d00d8  0000002f R_MIPS_TLS_TPREL3
+001d00d0  0000002f R_MIPS_TLS_TPREL3
+001d00cc  0000002f R_MIPS_TLS_TPREL3
+001c4088  0000002f R_MIPS_TLS_TPREL3
+001c408c  0000002f R_MIPS_TLS_TPREL3
+001c4080  0000002f R_MIPS_TLS_TPREL3
+001c4084  0000002f R_MIPS_TLS_TPREL3
+.* R_MIPS_REL32 .*
+#pass
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden4a.s b/ld/testsuite/ld-mips-elf/tls-hidden4a.s
new file mode 100644 (file)
index 0000000..02a0d35
--- /dev/null
@@ -0,0 +1,18 @@
+       .macro  load
+       lw      $4,%gottprel(foo\@)($gp)
+       .endm
+
+       .rept   4
+       load
+       .endr
+
+       .macro  load2
+       lw      $4,%got(undefa\@)($gp)
+       .endm
+
+       .rept   0x3000
+       load2
+       .endr
+
+       .section .tdata,"awT",@progbits
+       .fill   0xabc0
diff --git a/ld/testsuite/ld-mips-elf/tls-hidden4b.s b/ld/testsuite/ld-mips-elf/tls-hidden4b.s
new file mode 100644 (file)
index 0000000..d6deb00
--- /dev/null
@@ -0,0 +1,27 @@
+       .macro  load
+       .text
+       lw      $4,%gottprel(foo\@)($gp)
+
+       .global foo\@
+       .type   foo\@,@object
+       .size   foo\@,4
+       .section .tdata,"awT",@progbits
+foo\@:
+       .word   \@
+       .endm
+
+       .rept   4
+       load
+       .endr
+
+       .text
+       .macro  load2
+       lw      $4,%got(undefb\@)($gp)
+       .endm
+
+       .rept   0x3000
+       load2
+       .endr
+
+       .data
+       .word   undef