summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlrich Drepper <[email protected]>2008-02-23 06:50:01 +0000
committerUlrich Drepper <[email protected]>2008-02-23 06:50:01 +0000
commit834de6f38901b6add14b6f5f7dda8550638d98ec (patch)
treec6d7a7e7d25e33ac5a1e0c7a7cd650324298b028
parent658094acf8d506867e62c10f70c51f65b8f7a829 (diff)
Add missing file
Add more TLS support for x86 linker.
-rw-r--r--TODO8
-rw-r--r--src/ChangeLog6
-rw-r--r--src/i386_ld.c102
-rw-r--r--src/ld.c3
-rw-r--r--src/ldgeneric.c10
-rw-r--r--tests/sha1-tst.c79
6 files changed, 199 insertions, 9 deletions
diff --git a/TODO b/TODO
index b3b4441b..b2bcf6e9 100644
--- 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
diff --git a/src/ChangeLog b/src/ChangeLog
index f28c7006..71b82b1e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2008-02-03 Ulrich Drepper <[email protected]>
+
+ * 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 <[email protected]>
* readelf.c (print_attributes): New function.
diff --git a/src/i386_ld.c b/src/i386_ld.c
index c123d823..2702ef85 100644
--- a/src/i386_ld.c
+++ b/src/i386_ld.c
@@ -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:
diff --git a/src/ld.c b/src/ld.c
index 11c5cabd..63fc378f 100644
--- 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]);
diff --git a/src/ldgeneric.c b/src/ldgeneric.c
index e0cc4b48..8df2a57e 100644
--- a/src/ldgeneric.c
+++ b/src/ldgeneric.c
@@ -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
index 00000000..9ff8141b
--- /dev/null
+++ b/tests/sha1-tst.c
@@ -0,0 +1,79 @@
+/* Copyright (C) 2008 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+ Written by Ulrich Drepper <[email protected]>, 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;
+}