diff options
author | Ulrich Drepper <[email protected]> | 2008-02-23 06:50:01 +0000 |
---|---|---|
committer | Ulrich Drepper <[email protected]> | 2008-02-23 06:50:01 +0000 |
commit | 834de6f38901b6add14b6f5f7dda8550638d98ec (patch) | |
tree | c6d7a7e7d25e33ac5a1e0c7a7cd650324298b028 | |
parent | 658094acf8d506867e62c10f70c51f65b8f7a829 (diff) |
Add missing file
Add more TLS support for x86 linker.
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | src/ChangeLog | 6 | ||||
-rw-r--r-- | src/i386_ld.c | 102 | ||||
-rw-r--r-- | src/ld.c | 3 | ||||
-rw-r--r-- | src/ldgeneric.c | 10 | ||||
-rw-r--r-- | tests/sha1-tst.c | 79 |
6 files changed, 199 insertions, 9 deletions
@@ -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: @@ -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; +} |