]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Add missing file
authorUlrich Drepper <drepper@redhat.com>
Sat, 23 Feb 2008 06:50:01 +0000 (06:50 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 23 Feb 2008 06:50:01 +0000 (06:50 +0000)
Add more TLS support for x86 linker.

TODO
src/ChangeLog
src/i386_ld.c
src/ld.c
src/ldgeneric.c
tests/sha1-tst.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index b3b4441b3f52e1d51f2debd6a7d26d24d810e91a..b2bcf6e94f1501b8e48d1539cf7cdb89abce4a64 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,7 +1,7 @@
                      ToDo list for elfutils                      -*-outline-*-
                       ----------------------
 
-Time-stamp: <2006-06-11 11:07:01 drepper>
+Time-stamp: <2008-02-03 14:15:41 drepper>
 
 * mkinstalldirs
 
@@ -102,6 +102,12 @@ Time-stamp: <2006-06-11 11:07:01 drepper>
 
    check whether any relocation is for a merge-able section
 
+   check TLS relocation depencies
+
+*** for x86
+
+    check that R_386_TLS_GD is followed by R_386_PLT32 for __tls_get_addr
+
 ** relax
 
    prelink generated files
index f28c70065e485a281b6d901160116796f573a29e..71b82b1e1981854422b19cdaf275314892203b6f 100644 (file)
@@ -1,3 +1,9 @@
+2008-02-03  Ulrich Drepper  <drepper@redhat.com>
+
+       * i386_ld.c (elf_i386_count_relocations): Implement R_386_TLS_GD
+       when linked into executable.
+       (elf_i386_create_relocations): Likewise.
+
 2008-02-20  Roland McGrath  <roland@redhat.com>
 
        * readelf.c (print_attributes): New function.
index c123d823d52e4c72a2ce5bf70e9bb995677bca21..2702ef85d665962a0f95224be25bc6eb6e5f04a7 100644 (file)
@@ -649,6 +649,7 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
            case R_386_TLS_LDO_32:
              if (statep->file_type != executable_file_type)
                abort ();
+             /* We do not need a relocation in the output file.  */
              break;
 
            case R_386_TLS_LE:
@@ -656,8 +657,25 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
              break;
 
            case R_386_TLS_IE:
-           case R_386_TLS_GOTIE:
+             if (statep->file_type == dso_file_type)
+               error (EXIT_FAILURE, 0, gettext ("initial-executable TLS relocation cannot be used "));
+             if (!scninfo->fileinfo->symref[r_sym]->defined
+                 || scninfo->fileinfo->symref[r_sym]->in_dso)
+               {
+                 abort ();
+               }
+             break;
+
            case R_386_TLS_GD:
+             if (statep->file_type != executable_file_type
+                 || !scninfo->fileinfo->symref[r_sym]->defined
+                 || scninfo->fileinfo->symref[r_sym]->in_dso)
+               {
+                 abort ();
+               }
+             break;
+
+           case R_386_TLS_GOTIE:
            case R_386_TLS_LDM:
            case R_386_TLS_GD_32:
            case R_386_TLS_GD_PUSH:
@@ -791,7 +809,7 @@ elf_i386_create_relocations (struct ld_state *statep,
            }
 
          /* Address of the relocated memory in the data buffer.  */
-         void *relloc = (char *) data->d_buf + rel->r_offset;
+         unsigned char *relloc = (unsigned char *) data->d_buf + rel->r_offset;
 
          uint32_t thisgotidx;
          switch (XELF_R_TYPE (rel->r_info))
@@ -940,16 +958,92 @@ elf_i386_create_relocations (struct ld_state *statep,
              store_4ubyte_unaligned (relloc, value);
              break;
 
+           case R_386_TLS_IE:
+             if (symref[idx]->defined && !symref[idx]->in_dso)
+               {
+                 /* The symbol is defined in the executable.
+                    Perform the IE->LE optimization.
+                    There are multiple versions, though.
+
+                    First version: mov ADDR,REG.  */
+                 if (relloc[-2] == 0x8b
+                     && ((relloc[-1] & 0xc7) == 0x05))
+                   {
+                     relloc[-2] = 0xc7;
+                     relloc[-1] = 0xc0 | ((relloc[-1] >> 3) & 7);
+                     store_4ubyte_unaligned (relloc, (symref[idx]->merge.value
+                                                      - ld_state.tls_tcb));
+                   }
+                 else
+                   {
+                     abort ();
+                   }
+               }
+             else
+               {
+                 abort ();
+               }
+             break;
+
            case R_386_TLS_LDO_32:
              value = symref[idx]->merge.value - ld_state.tls_start;
              store_4ubyte_unaligned (relloc, value);
              break;
 
+           case R_386_TLS_GD:
+             if (ld_state.file_type == executable_file_type)
+               {
+                 if (symref[idx]->defined && !symref[idx]->in_dso)
+                   {
+                     /* The symbol is defined in the executable.
+                        Perform the GD->LE optimization.  */
+                     static const char gd_to_le[] =
+                       {
+                         /* mov %gs:0x0,%eax */
+                         0x65, 0xa1, 0x00, 0x00, 0x00, 0x00,
+                         /* sub $OFFSET,%eax */
+                         0x81, 0xe8
+                       };
+#ifndef NDEBUG
+                     static const char gd_text[] =
+                       {
+                         /* lea 0x0(,%ebx,1),%eax */
+                         0x8d, 0x04, 0x1d, 0x00, 0x00, 0x00, 0x00,
+                         /* call ___tls_get_addr */
+                         0xe8
+                       };
+                     assert (memcmp (relloc - 3, gd_text, sizeof (gd_text))
+                             == 0);
+#endif
+                     relloc = mempcpy (relloc - 3, gd_to_le,
+                                       sizeof (gd_to_le));
+                     value = ld_state.tls_tcb- symref[idx]->merge.value;
+                     store_4ubyte_unaligned (relloc, value);
+
+                     /* We have to skip over the next relocation which is
+                        the matching R_i386_PLT32 for __tls_get_addr.  */
+                     ++cnt;
+#ifndef NDEBUG
+                     assert (cnt < nrels);
+                     XElf_Off old_offset = rel->r_offset;
+                     xelf_getrel (reldata, cnt, rel);
+                     assert (rel != NULL);
+                     assert (XELF_R_TYPE (rel->r_info) == R_386_PLT32);
+                     idx = XELF_R_SYM (rel->r_info);
+                     assert (strcmp (symref[idx]->name, "___tls_get_addr")
+                             == 0);
+                     assert (old_offset + 5 == rel->r_offset);
+#endif
+
+                     break;
+                   }
+               }
+             abort ();
+             break;
+
            case R_386_32PLT:
            case R_386_TLS_TPOFF:
-           case R_386_TLS_IE:
            case R_386_TLS_GOTIE:
-           case R_386_TLS_GD:
            case R_386_TLS_LDM:
            case R_386_16:
            case R_386_PC16:
index 11c5cabd07b45238d6fa2ae01150755de534d35d..63fc378f7e66f9eea4a8e94cb42e737657ec250c 100644 (file)
--- a/src/ld.c
+++ b/src/ld.c
@@ -507,7 +507,8 @@ replace_args (int argc, char *argv[])
   } args[] =
       {
        { "-export-dynamic", "--export-dynamic" },
-       { "-dynamic-linker", "--dynamic-linker" }
+       { "-dynamic-linker", "--dynamic-linker" },
+       { "-static", "--static" },
       };
   const size_t nargs = sizeof (args) / sizeof (args[0]);
 
index e0cc4b483a9175deab42668004cf7ab9e22b68ac..8df2a57e0dbe2b7d6e7373ffc7578e83ffa3b838 100644 (file)
@@ -1108,6 +1108,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
   size_t nsymbols = 0;
   size_t nlocalsymbols = 0;
   bool has_merge_sections = false;
+  bool has_tls_symbols = false;
   /* Unless we have different information we assume the code needs
      an executable stack.  */
   enum execstack execstack = execstack_true;
@@ -1164,6 +1165,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
 
       /* Check whether this section is marked as merge-able.  */
       has_merge_sections |= (shdr->sh_flags & SHF_MERGE) != 0;
+      has_tls_symbols |= (shdr->sh_flags & SHF_TLS) != 0;
 
       /* Get the ELF section header and data.  */
       /* Make the file structure available.  */
@@ -1392,7 +1394,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
       /* In case this file contains merge-able sections we have to
         locate the symbols which are in these sections.  */
       fileinfo->has_merge_sections = has_merge_sections;
-      if (likely (has_merge_sections))
+      if (likely (has_merge_sections || has_tls_symbols))
        {
          fileinfo->symref = (struct symbol **)
            obstack_calloc (&ld_state.smem,
@@ -1424,8 +1426,9 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
 
              if (XELF_ST_TYPE (sym->st_info) != STT_SECTION
                  && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)
-                 && (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags
-                     & SHF_MERGE))
+                 && ((SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags
+                      & SHF_MERGE)
+                     || XELF_ST_TYPE (sym->st_info) == STT_TLS))
                {
                  /* Create a symbol record for this symbol and add it
                     to the list for this section.  */
@@ -1437,6 +1440,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
                  newp->symidx = cnt;
                  newp->scndx = shndx;
                  newp->file = fileinfo;
+                 newp->defined = 1;
                  fileinfo->symref[cnt] = newp;
 
                  if (fileinfo->scninfo[shndx].symbols == NULL)
diff --git a/tests/sha1-tst.c b/tests/sha1-tst.c
new file mode 100644 (file)
index 0000000..9ff8141
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) 2008 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2008.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sha1.h>
+
+
+int
+main (void)
+{
+  char buf[1000];
+  int result = 0;
+
+  struct sha1_ctx ctx;
+  sha1_init_ctx (&ctx);
+  sha1_process_bytes ("abc", 3, &ctx);
+  sha1_finish_ctx (&ctx, buf);
+  static const char expected1[SHA1_DIGEST_SIZE] =
+    "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e"
+    "\x25\x71\x78\x50\xc2\x6c\x9c\xd0\xd8\x9d";
+  if (memcmp (buf, expected1, SHA1_DIGEST_SIZE) != 0)
+    {
+      puts ("test 1 failed");
+      result = 1;
+    }
+
+  sha1_init_ctx (&ctx);
+  sha1_process_bytes ("\
+abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, &ctx);
+  sha1_finish_ctx (&ctx, buf);
+  static const char expected2[SHA1_DIGEST_SIZE] =
+    "\x84\x98\x3e\x44\x1c\x3b\xd2\x6e\xba\xae"
+    "\x4a\xa1\xf9\x51\x29\xe5\xe5\x46\x70\xf1";
+  if (memcmp (buf, expected2, SHA1_DIGEST_SIZE) != 0)
+    {
+      puts ("test 2 failed");
+      result = 1;
+    }
+
+  sha1_init_ctx (&ctx);
+  memset (buf, 'a', sizeof (buf));
+  for (int i = 0; i < 1000; ++i)
+    sha1_process_bytes (buf, sizeof (buf), &ctx);
+  sha1_finish_ctx (&ctx, buf);
+  static const char expected3[SHA1_DIGEST_SIZE] =
+    "\x34\xaa\x97\x3c\xd4\xc4\xda\xa4\xf6\x1e"
+    "\xeb\x2b\xdb\xad\x27\x31\x65\x34\x01\x6f";
+  if (memcmp (buf, expected3, SHA1_DIGEST_SIZE) != 0)
+    {
+      puts ("test 3 failed");
+      result = 1;
+    }
+
+  return result;
+}