aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog27
-rw-r--r--bfd/elf32-i386.c508
-rw-r--r--bfd/elf64-x86-64.c613
-rw-r--r--ld/testsuite/ChangeLog10
-rw-r--r--ld/testsuite/ld-i386/tlsbin.dd364
-rw-r--r--ld/testsuite/ld-i386/tlsbin.rd4
-rw-r--r--ld/testsuite/ld-i386/tlsbinpic.s5
-rw-r--r--ld/testsuite/ld-i386/tlsgd1.dd2
-rw-r--r--ld/testsuite/ld-i386/tlsgd1.s3
9 files changed, 947 insertions, 589 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index a437ad8..71d760a 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,30 @@
+2007-08-23 H.J. Lu <hongjiu.lu@intel.com>
+
+ * elf32-i386.c: Include "bfd_stdint.h".
+ (elf_i386_rtype_to_howto): New function.
+ (elf_i386_info_to_howto_rel): Use it.
+ (x86_64_opcode16): New union type.
+ (elf_i386_check_tls_transition): New function.
+ (elf_i386_tls_transition): Updated to check transition and
+ issue an error if a transition isn't supported.
+ (elf_i386_check_relocs): Return FALSE if
+ elf_i386_tls_transition returns FALSE.
+ (elf_i386_gc_sweep_hook): Likewise.
+ (elf_i386_relocate_section): Likewise. Remove BFD_ASSERT
+ on TLS transitions.
+
+ * elf64-x86-64.c: Include "bfd_stdint.h".
+ (x86_64_opcode16): New union type.
+ (x86_64_opcode32): Likewise.
+ (elf64_x86_64_check_tls_transition): New function.
+ (elf64_x86_64_tls_transition): Updated to check transition and
+ issue an error if a transition isn't supported.
+ (elf64_x86_64_check_relocs): Return FALSE if
+ elf64_x86_64_tls_transition returns FALSE.
+ (elf64_x86_64_gc_sweep_hook): Likewise.
+ (elf64_x86_64_relocate_section): Likewise. Remove BFD_ASSERT
+ on TLS transitions.
+
2007-08-22 H.J. Lu <hongjiu.lu@intel.com>
* elfxx-ia64.c: Convert to ISO C90 prototypes.
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index af3b860..072dc6f 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -25,6 +25,7 @@
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf-vxworks.h"
+#include "bfd_stdint.h"
/* 386 uses REL relocations instead of RELA. */
#define USE_REL 1
@@ -345,12 +346,9 @@ elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
return NULL;
}
-static void
-elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
- arelent *cache_ptr,
- Elf_Internal_Rela *dst)
+static reloc_howto_type *
+elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
{
- unsigned int r_type = ELF32_R_TYPE (dst->r_info);
unsigned int indx;
if ((indx = r_type) >= R_386_standard
@@ -365,7 +363,17 @@ elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
abfd, (int) r_type);
indx = R_386_NONE;
}
- cache_ptr->howto = &elf_howto_table[indx];
+ BFD_ASSERT (elf_howto_table [indx].type == r_type);
+ return &elf_howto_table[indx];
+}
+
+static void
+elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *cache_ptr,
+ Elf_Internal_Rela *dst)
+{
+ unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+ cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type);
}
/* Return whether a symbol name implies a local label. The UnixWare
@@ -893,32 +901,293 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
-static int
-elf_i386_tls_transition (struct bfd_link_info *info, int r_type,
- struct elf_link_hash_entry *h)
+typedef union
+ {
+ unsigned char c[2];
+ uint16_t i;
+ }
+i386_opcode16;
+
+/* Return TRUE if the TLS access code sequence support transition
+ from R_TYPE. */
+
+static bfd_boolean
+elf_i386_check_tls_transition (bfd *abfd, asection *sec,
+ bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int r_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend)
{
- if (info->shared)
- return r_type;
+ unsigned int val, type;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ bfd_vma offset;
+
+ /* Get the section contents. */
+ if (contents == NULL)
+ {
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else
+ {
+ /* FIXME: How to better handle error condition? */
+ if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ return FALSE;
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ offset = rel->r_offset;
switch (r_type)
{
case R_386_TLS_GD:
+ case R_386_TLS_LDM:
+ if (offset < 2 || (rel + 1) >= relend)
+ return FALSE;
+
+ type = bfd_get_8 (abfd, contents + offset - 2);
+ if (r_type == R_386_TLS_GD)
+ {
+ /* Check transition from LD access model. Only
+ leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr
+ leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop
+ can transit to different access model. */
+ if ((offset + 10) > sec->size ||
+ (type != 0x8d && type != 0x04))
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if (type == 0x04)
+ {
+ /* leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr */
+ if (offset < 3)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset - 3) != 0x8d)
+ return FALSE;
+
+ if ((val & 0xc7) != 0x05 || val == (4 << 3))
+ return FALSE;
+ }
+ else
+ {
+ /* leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop */
+ if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset + 9) != 0x90)
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Check transition from LD access model. Only
+ leal foo@tlsgd(%reg), %eax; call ___tls_get_addr
+ can transit to different access model. */
+ if (type != 0x8d || (offset + 9) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+ return FALSE;
+ }
+
+ if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8)
+ return FALSE;
+
+ r_symndx = ELF32_R_SYM (rel[1].r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ return FALSE;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ return (h != NULL
+ && h->root.root.string != NULL
+ && (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
+ || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32)
+ && (strcmp (h->root.root.string, "___tls_get_addr") == 0));
+
+ case R_386_TLS_IE:
+ /* Check transition from IE access model:
+ movl foo@indntpoff(%rip), %eax
+ movl foo@indntpoff(%rip), %reg
+ addl foo@indntpoff(%rip), %reg
+ */
+
+ if (offset < 1 || (offset + 4) > sec->size)
+ return FALSE;
+
+ /* Check "movl foo@tpoff(%rip), %eax" first. */
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if (val == 0xa1)
+ return TRUE;
+
+ if (offset < 2)
+ return FALSE;
+
+ /* Check movl|addl foo@tpoff(%rip), %reg. */
+ type = bfd_get_8 (abfd, contents + offset - 2);
+ return ((type == 0x8b || type == 0x03)
+ && (val & 0xc7) == 0x05);
+
+ case R_386_TLS_GOTIE:
+ case R_386_TLS_IE_32:
+ /* Check transition from {IE_32,GOTIE} access model:
+ subl foo@{tpoff,gontoff}(%reg1), %reg2
+ movl foo@{tpoff,gontoff}(%reg1), %reg2
+ addl foo@{tpoff,gontoff}(%reg1), %reg2
+ */
+
+ if (offset < 2 || (offset + 4) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if ((val & 0xc0) != 0x80 || (val & 7) == 4)
+ return FALSE;
+
+ type = bfd_get_8 (abfd, contents + offset - 2);
+ return type == 0x8b || type == 0x2b || type == 0x03;
+
+ case R_386_TLS_GOTDESC:
+ /* Check transition from GDesc access model:
+ leal x@tlsdesc(%ebx), %eax
+
+ Make sure it's a leal adding ebx to a 32-bit offset
+ into any register, although it's probably almost always
+ going to be eax. */
+
+ if (offset < 2 || (offset + 4) > sec->size)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ return (val & 0xc7) == 0x83;
+
+ case R_386_TLS_DESC_CALL:
+ /* Check transition from GDesc access model:
+ call *x@tlsdesc(%rax)
+ */
+ if (offset + 2 <= sec->size)
+ {
+ /* Make sure that it's a call *x@tlsdesc(%rax). */
+ static i386_opcode16 call = { { 0xff, 0x10 } };
+ return bfd_get_16 (abfd, contents + offset) == call.i;
+ }
+
+ return FALSE;
+
+ default:
+ abort ();
+ }
+}
+
+/* Return TRUE if the TLS access transition is OK or no transition
+ will be performed. Update R_TYPE if there is a transition. */
+
+static bfd_boolean
+elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
+ asection *sec, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int *r_type, int tls_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend,
+ struct elf_link_hash_entry *h)
+{
+ unsigned int from_type = *r_type;
+ unsigned int to_type = from_type;
+ bfd_boolean check = TRUE;
+
+ switch (from_type)
+ {
+ case R_386_TLS_GD:
case R_386_TLS_GOTDESC:
case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
- if (h == NULL)
- return R_386_TLS_LE_32;
- return R_386_TLS_IE_32;
case R_386_TLS_IE:
case R_386_TLS_GOTIE:
- if (h == NULL)
- return R_386_TLS_LE_32;
- return r_type;
+ if (!info->shared)
+ {
+ if (h == NULL)
+ to_type = R_386_TLS_LE_32;
+ else if (from_type != R_386_TLS_IE
+ && from_type != R_386_TLS_GOTIE)
+ to_type = R_386_TLS_IE_32;
+ }
+
+ /* When we are called from elf_i386_relocate_section, CONTENTS
+ isn't NULL and there may be additional transitions based on
+ TLS_TYPE. */
+ if (contents != NULL)
+ {
+ unsigned int new_to_type = to_type;
+
+ if (!info->shared
+ && h != NULL
+ && h->dynindx == -1
+ && (tls_type & GOT_TLS_IE))
+ new_to_type = R_386_TLS_LE_32;
+
+ if (to_type == R_386_TLS_GD
+ || to_type == R_386_TLS_GOTDESC
+ || to_type == R_386_TLS_DESC_CALL)
+ {
+ if (tls_type == GOT_TLS_IE_POS)
+ new_to_type = R_386_TLS_GOTIE;
+ else if (tls_type & GOT_TLS_IE)
+ new_to_type = R_386_TLS_IE_32;
+ }
+
+ /* We checked the transition before when we were called from
+ elf_i386_check_relocs. We only want to check the new
+ transition which hasn't been checked before. */
+ check = new_to_type != to_type && from_type == to_type;
+ to_type = new_to_type;
+ }
+
+ break;
+
case R_386_TLS_LDM:
- return R_386_TLS_LE_32;
+ if (!info->shared)
+ to_type = R_386_TLS_LE_32;
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ /* Return TRUE if there is no transition. */
+ if (from_type == to_type)
+ return TRUE;
+
+ /* Check if the transition can be performed. */
+ if (check
+ && ! elf_i386_check_tls_transition (abfd, sec, contents,
+ symtab_hdr, sym_hashes,
+ from_type, rel, relend))
+ {
+ const reloc_howto_type *from, *to;
+
+ from = elf_i386_rtype_to_howto (abfd, from_type);
+ to = elf_i386_rtype_to_howto (abfd, to_type);
+
+ (*_bfd_error_handler)
+ (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
+ "in section `%A' failed"),
+ abfd, sec, from->name, to->name,
+ h ? h->root.root.string : "a local symbol",
+ (unsigned long) rel->r_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
- return r_type;
+ *r_type = to_type;
+ return TRUE;
}
/* Look through the relocs for a section during the first phase, and
@@ -975,7 +1244,11 @@ elf_i386_check_relocs (bfd *abfd,
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
- r_type = elf_i386_tls_transition (info, r_type, h);
+ if (! elf_i386_tls_transition (info, abfd, sec, NULL,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, rel_end, h))
+ return FALSE;
switch (r_type)
{
@@ -1364,7 +1637,12 @@ elf_i386_gc_sweep_hook (bfd *abfd,
}
r_type = ELF32_R_TYPE (rel->r_info);
- r_type = elf_i386_tls_transition (info, r_type, h);
+ if (! elf_i386_tls_transition (info, abfd, sec, NULL,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, relend, h))
+ return FALSE;
+
switch (r_type)
{
case R_386_TLS_LDM:
@@ -2624,98 +2902,50 @@ elf_i386_relocate_section (bfd *output_bfd,
case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
case R_386_TLS_GOTIE:
- r_type = elf_i386_tls_transition (info, r_type, h);
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx];
else if (h != NULL)
- {
- tls_type = elf_i386_hash_entry(h)->tls_type;
- if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
- r_type = R_386_TLS_LE_32;
- }
+ tls_type = elf_i386_hash_entry(h)->tls_type;
if (tls_type == GOT_TLS_IE)
tls_type = GOT_TLS_IE_NEG;
- if (r_type == R_386_TLS_GD
- || r_type == R_386_TLS_GOTDESC
- || r_type == R_386_TLS_DESC_CALL)
- {
- if (tls_type == GOT_TLS_IE_POS)
- r_type = R_386_TLS_GOTIE;
- else if (tls_type & GOT_TLS_IE)
- r_type = R_386_TLS_IE_32;
- }
+
+ if (! elf_i386_tls_transition (info, input_bfd,
+ input_section, contents,
+ symtab_hdr, sym_hashes,
+ &r_type, tls_type, rel,
+ relend, h))
+ return FALSE;
if (r_type == R_386_TLS_LE_32)
{
BFD_ASSERT (! unresolved_reloc);
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
{
- unsigned int val, type;
+ unsigned int type;
bfd_vma roff;
- unsigned long tls_r_symndx;
- struct elf_link_hash_entry *tls_h;
/* GD->LE transition. */
- BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
- BFD_ASSERT (type == 0x8d || type == 0x04);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- tls_r_symndx = ELF32_R_SYM (rel[1].r_info);
- BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
- tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
- BFD_ASSERT (tls_h != NULL
- && tls_h->root.root.string != NULL
- && strcmp (tls_h->root.root.string,
- "___tls_get_addr") == 0);
- BFD_ASSERT ((! info->shared
- && ELF32_R_TYPE (rel[1].r_info) == R_386_PC32)
- || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
- roff = rel->r_offset + 5;
- val = bfd_get_8 (input_bfd,
- contents + rel->r_offset - 1);
if (type == 0x04)
{
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
Change it into:
movl %gs:0, %eax; subl $foo@tpoff, %eax
(6 byte form of subl). */
- BFD_ASSERT (rel->r_offset >= 3);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset - 3)
- == 0x8d);
- BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
memcpy (contents + rel->r_offset - 3,
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ roff = rel->r_offset + 5;
}
else
{
- BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
- if (rel->r_offset + 10 <= input_section->size
- && bfd_get_8 (input_bfd,
- contents + rel->r_offset + 9) == 0x90)
- {
- /* leal foo(%reg), %eax; call ___tls_get_addr; nop
- Change it into:
- movl %gs:0, %eax; subl $foo@tpoff, %eax
- (6 byte form of subl). */
- memcpy (contents + rel->r_offset - 2,
- "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
- roff = rel->r_offset + 6;
- }
- else
- {
- /* leal foo(%reg), %eax; call ___tls_get_addr
- Change it into:
- movl %gs:0, %eax; subl $foo@tpoff, %eax
- (5 byte form of subl). */
- memcpy (contents + rel->r_offset - 2,
- "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
- }
+ /* leal foo(%reg), %eax; call ___tls_get_addr; nop
+ Change it into:
+ movl %gs:0, %eax; subl $foo@tpoff, %eax
+ (6 byte form of subl). */
+ memcpy (contents + rel->r_offset - 2,
+ "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ roff = rel->r_offset + 6;
}
bfd_put_32 (output_bfd, tpoff (info, relocation),
contents + roff);
@@ -2733,19 +2963,11 @@ elf_i386_relocate_section (bfd *output_bfd,
Registers other than %eax may be set up here. */
- unsigned int val, type;
+ unsigned int val;
bfd_vma roff;
- /* First, make sure it's a leal adding ebx to a
- 32-bit offset into any register, although it's
- probably almost always going to be eax. */
roff = rel->r_offset;
- BFD_ASSERT (roff >= 2);
- type = bfd_get_8 (input_bfd, contents + roff - 2);
- BFD_ASSERT (type == 0x8d);
val = bfd_get_8 (input_bfd, contents + roff - 1);
- BFD_ASSERT ((val & 0xc7) == 0x83);
- BFD_ASSERT (roff + 4 <= input_section->size);
/* Now modify the instruction as appropriate. */
/* aoliva FIXME: remove the above and xor the byte
@@ -2762,28 +2984,18 @@ elf_i386_relocate_section (bfd *output_bfd,
It's originally:
call *(%eax)
Turn it into:
- nop; nop */
+ xchg %ax,%ax */
- unsigned int val, type;
bfd_vma roff;
-
- /* First, make sure it's a call *(%eax). */
+
roff = rel->r_offset;
- BFD_ASSERT (roff + 2 <= input_section->size);
- type = bfd_get_8 (input_bfd, contents + roff);
- BFD_ASSERT (type == 0xff);
- val = bfd_get_8 (input_bfd, contents + roff + 1);
- BFD_ASSERT (val == 0x10);
-
- /* Now modify the instruction as appropriate. Use
- xchg %ax,%ax instead of 2 nops. */
bfd_put_8 (output_bfd, 0x66, contents + roff);
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
continue;
}
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
{
- unsigned int val, type;
+ unsigned int val;
/* IE->LE transition:
Originally it can be one of:
@@ -2794,9 +3006,7 @@ elf_i386_relocate_section (bfd *output_bfd,
movl $foo, %eax
movl $foo, %reg
addl $foo, %reg. */
- BFD_ASSERT (rel->r_offset >= 1);
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
if (val == 0xa1)
{
/* movl foo, %eax. */
@@ -2805,14 +3015,14 @@ elf_i386_relocate_section (bfd *output_bfd,
}
else
{
- BFD_ASSERT (rel->r_offset >= 2);
+ unsigned int type;
+
type = bfd_get_8 (input_bfd,
contents + rel->r_offset - 2);
switch (type)
{
case 0x8b:
/* movl */
- BFD_ASSERT ((val & 0xc7) == 0x05);
bfd_put_8 (output_bfd, 0xc7,
contents + rel->r_offset - 2);
bfd_put_8 (output_bfd,
@@ -2821,7 +3031,6 @@ elf_i386_relocate_section (bfd *output_bfd,
break;
case 0x03:
/* addl */
- BFD_ASSERT ((val & 0xc7) == 0x05);
bfd_put_8 (output_bfd, 0x81,
contents + rel->r_offset - 2);
bfd_put_8 (output_bfd,
@@ -2850,11 +3059,8 @@ elf_i386_relocate_section (bfd *output_bfd,
subl $foo, %reg2
movl $foo, %reg2 (6 byte form)
addl $foo, %reg2. */
- BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
- BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
if (type == 0x8b)
{
/* movl */
@@ -3055,38 +3261,21 @@ elf_i386_relocate_section (bfd *output_bfd,
bfd_vma roff;
/* GD->IE transition. */
- BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
- BFD_ASSERT (type == 0x8d || type == 0x04);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
- roff = rel->r_offset - 3;
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
if (type == 0x04)
{
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
Change it into:
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
- BFD_ASSERT (rel->r_offset >= 3);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset - 3)
- == 0x8d);
- BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
val >>= 3;
+ roff = rel->r_offset - 3;
}
else
{
/* leal foo(%reg), %eax; call ___tls_get_addr; nop
Change it into:
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
- BFD_ASSERT (rel->r_offset + 10 <= input_section->size);
- BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset + 9)
- == 0x90);
roff = rel->r_offset - 2;
}
memcpy (contents + roff,
@@ -3116,25 +3305,18 @@ elf_i386_relocate_section (bfd *output_bfd,
leal x@tlsdesc(%ebx), %eax
Change it to:
- movl x@gotntpoff(%ebx), %eax # before nop; nop
+ movl x@gotntpoff(%ebx), %eax # before xchg %ax,%ax
or:
movl x@gottpoff(%ebx), %eax # before negl %eax
Registers other than %eax may be set up here. */
- unsigned int val, type;
bfd_vma roff;
/* First, make sure it's a leal adding ebx to a 32-bit
offset into any register, although it's probably
almost always going to be eax. */
roff = rel->r_offset;
- BFD_ASSERT (roff >= 2);
- type = bfd_get_8 (input_bfd, contents + roff - 2);
- BFD_ASSERT (type == 0x8d);
- val = bfd_get_8 (input_bfd, contents + roff - 1);
- BFD_ASSERT ((val & 0xc7) == 0x83);
- BFD_ASSERT (roff + 4 <= input_section->size);
/* Now modify the instruction as appropriate. */
/* To turn a leal into a movl in the form we use it, it
@@ -3162,22 +3344,15 @@ elf_i386_relocate_section (bfd *output_bfd,
call *(%eax)
Change it to:
- nop; nop
+ xchg %ax,%ax
or
negl %eax
depending on how we transformed the TLS_GOTDESC above.
*/
- unsigned int val, type;
bfd_vma roff;
- /* First, make sure it's a call *(%eax). */
roff = rel->r_offset;
- BFD_ASSERT (roff + 2 <= input_section->size);
- type = bfd_get_8 (input_bfd, contents + roff);
- BFD_ASSERT (type == 0xff);
- val = bfd_get_8 (input_bfd, contents + roff + 1);
- BFD_ASSERT (val == 0x10);
/* Now modify the instruction as appropriate. */
if (tls_type != GOT_TLS_IE_NEG)
@@ -3200,35 +3375,20 @@ elf_i386_relocate_section (bfd *output_bfd,
break;
case R_386_TLS_LDM:
- if (! info->shared)
- {
- unsigned int val;
- unsigned long tls_r_symndx;
- struct elf_link_hash_entry *tls_h;
+ if (! elf_i386_tls_transition (info, input_bfd,
+ input_section, contents,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN, rel,
+ relend, h))
+ return FALSE;
+ if (r_type != R_386_TLS_LDM)
+ {
/* LD->LE transition:
- Ensure it is:
leal foo(%reg), %eax; call ___tls_get_addr.
We change it into:
movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */
- BFD_ASSERT (rel->r_offset >= 2);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
- == 0x8d);
- val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- tls_r_symndx = ELF32_R_SYM (rel[1].r_info);
- BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
- tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
- BFD_ASSERT (tls_h != NULL
- && tls_h->root.root.string != NULL
- && strcmp (tls_h->root.root.string,
- "___tls_get_addr") == 0);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
- || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ BFD_ASSERT (r_type == R_386_TLS_LE_32);
memcpy (contents + rel->r_offset - 2,
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
/* Skip R_386_PC32/R_386_PLT32. */
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index d73b270..34eae58 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -25,6 +25,7 @@
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
+#include "bfd_stdint.h"
#include "elf/x86-64.h"
@@ -712,27 +713,262 @@ elf64_x86_64_elf_object_p (bfd *abfd)
return TRUE;
}
-static int
-elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type,
- struct elf_link_hash_entry *h)
+typedef union
+ {
+ unsigned char c[2];
+ uint16_t i;
+ }
+x86_64_opcode16;
+
+typedef union
+ {
+ unsigned char c[4];
+ uint32_t i;
+ }
+x86_64_opcode32;
+
+/* Return TRUE if the TLS access code sequence support transition
+ from R_TYPE. */
+
+static bfd_boolean
+elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
+ bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int r_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend)
{
- if (info->shared)
- return r_type;
+ unsigned int val;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ bfd_vma offset;
+ /* Get the section contents. */
+ if (contents == NULL)
+ {
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else
+ {
+ /* FIXME: How to better handle error condition? */
+ if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ return FALSE;
+
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ offset = rel->r_offset;
switch (r_type)
{
case R_X86_64_TLSGD:
+ case R_X86_64_TLSLD:
+ if ((rel + 1) >= relend)
+ return FALSE;
+
+ if (r_type == R_X86_64_TLSGD)
+ {
+ /* Check transition from GD access model. Only
+ .byte 0x66; leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr
+ can transit to different access model. */
+
+ static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } },
+ call = { { 0x66, 0x66, 0x48, 0xe8 } };
+ if (offset < 4
+ || (offset + 12) > sec->size
+ || bfd_get_32 (abfd, contents + offset - 4) != leaq.i
+ || bfd_get_32 (abfd, contents + offset + 4) != call.i)
+ return FALSE;
+ }
+ else
+ {
+ /* Check transition from LD access model. Only
+ leaq foo@tlsld(%rip), %rdi;
+ call __tls_get_addr
+ can transit to different access model. */
+
+ static x86_64_opcode32 ld = { { 0x48, 0x8d, 0x3d, 0xe8 } };
+ x86_64_opcode32 op;
+
+ if (offset < 3 || (offset + 9) > sec->size)
+ return FALSE;
+
+ op.i = bfd_get_32 (abfd, contents + offset - 3);
+ op.c[3] = bfd_get_8 (abfd, contents + offset + 4);
+ if (op.i != ld.i)
+ return FALSE;
+ }
+
+ r_symndx = ELF64_R_SYM (rel[1].r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ return FALSE;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ return (h != NULL
+ && h->root.root.string != NULL
+ && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
+ || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
+ && (strcmp (h->root.root.string, "__tls_get_addr") == 0));
+
+ case R_X86_64_GOTTPOFF:
+ /* Check transition from IE access model:
+ movq foo@gottpoff(%rip), %reg
+ addq foo@gottpoff(%rip), %reg
+ */
+
+ if (offset < 3 || (offset + 4) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 3);
+ if (val != 0x48 && val != 0x4c)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 2);
+ if (val != 0x8b && val != 0x03)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ return (val & 0xc7) == 5;
+
+ case R_X86_64_GOTPC32_TLSDESC:
+ /* Check transition from GDesc access model:
+ leaq x@tlsdesc(%rip), %rax
+
+ Make sure it's a leaq adding rip to a 32-bit offset
+ into any register, although it's probably almost always
+ going to be rax. */
+
+ if (offset < 3 || (offset + 4) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 3);
+ if ((val & 0xfb) != 0x48)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ return (val & 0xc7) == 0x05;
+
+ case R_X86_64_TLSDESC_CALL:
+ /* Check transition from GDesc access model:
+ call *x@tlsdesc(%rax)
+ */
+ if (offset + 2 <= sec->size)
+ {
+ /* Make sure that it's a call *x@tlsdesc(%rax). */
+ static x86_64_opcode16 call = { { 0xff, 0x10 } };
+ return bfd_get_16 (abfd, contents + offset) == call.i;
+ }
+
+ return FALSE;
+
+ default:
+ abort ();
+ }
+}
+
+/* Return TRUE if the TLS access transition is OK or no transition
+ will be performed. Update R_TYPE if there is a transition. */
+
+static bfd_boolean
+elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
+ asection *sec, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int *r_type, int tls_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend,
+ struct elf_link_hash_entry *h)
+{
+ unsigned int from_type = *r_type;
+ unsigned int to_type = from_type;
+ bfd_boolean check = TRUE;
+
+ switch (from_type)
+ {
+ case R_X86_64_TLSGD:
case R_X86_64_GOTPC32_TLSDESC:
case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
- if (h == NULL)
- return R_X86_64_TPOFF32;
- return R_X86_64_GOTTPOFF;
+ if (!info->shared)
+ {
+ if (h == NULL)
+ to_type = R_X86_64_TPOFF32;
+ else
+ to_type = R_X86_64_GOTTPOFF;
+ }
+
+ /* When we are called from elf64_x86_64_relocate_section,
+ CONTENTS isn't NULL and there may be additional transitions
+ based on TLS_TYPE. */
+ if (contents != NULL)
+ {
+ unsigned int new_to_type = to_type;
+
+ if (!info->shared
+ && h != NULL
+ && h->dynindx == -1
+ && tls_type == GOT_TLS_IE)
+ new_to_type = R_X86_64_TPOFF32;
+
+ if (to_type == R_X86_64_TLSGD
+ || to_type == R_X86_64_GOTPC32_TLSDESC
+ || to_type == R_X86_64_TLSDESC_CALL)
+ {
+ if (tls_type == GOT_TLS_IE)
+ new_to_type = R_X86_64_GOTTPOFF;
+ }
+
+ /* We checked the transition before when we were called from
+ elf64_x86_64_check_relocs. We only want to check the new
+ transition which hasn't been checked before. */
+ check = new_to_type != to_type && from_type == to_type;
+ to_type = new_to_type;
+ }
+
+ break;
+
case R_X86_64_TLSLD:
- return R_X86_64_TPOFF32;
+ if (!info->shared)
+ to_type = R_X86_64_TPOFF32;
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ /* Return TRUE if there is no transition. */
+ if (from_type == to_type)
+ return TRUE;
+
+ /* Check if the transition can be performed. */
+ if (check
+ && ! elf64_x86_64_check_tls_transition (abfd, sec, contents,
+ symtab_hdr, sym_hashes,
+ from_type, rel, relend))
+ {
+ const reloc_howto_type *from, *to;
+
+ from = elf64_x86_64_rtype_to_howto (abfd, from_type);
+ to = elf64_x86_64_rtype_to_howto (abfd, to_type);
+
+ (*_bfd_error_handler)
+ (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
+ "in section `%A' failed"),
+ abfd, sec, from->name, to->name,
+ h ? h->root.root.string : "a local symbol",
+ (unsigned long) rel->r_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
- return r_type;
+ *r_type = to_type;
+ return TRUE;
}
/* Look through the relocs for a section during the first phase, and
@@ -740,7 +976,8 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type,
linkage table, and dynamic reloc sections. */
static bfd_boolean
-elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
+elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
+ asection *sec,
const Elf_Internal_Rela *relocs)
{
struct elf64_x86_64_link_hash_table *htab;
@@ -786,7 +1023,12 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
- r_type = elf64_x86_64_tls_transition (info, r_type, h);
+ if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, rel_end, h))
+ return FALSE;
+
switch (r_type)
{
case R_X86_64_TLSLD:
@@ -1173,7 +1415,8 @@ elf64_x86_64_gc_mark_hook (asection *sec,
static bfd_boolean
elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
- asection *sec, const Elf_Internal_Rela *relocs)
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
@@ -1216,7 +1459,12 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
}
r_type = ELF64_R_TYPE (rel->r_info);
- r_type = elf64_x86_64_tls_transition (info, r_type, h);
+ if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, relend, h))
+ return FALSE;
+
switch (r_type)
{
case R_X86_64_TLSLD:
@@ -2502,67 +2750,38 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_X86_64_GOTPC32_TLSDESC:
case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
- r_type = elf64_x86_64_tls_transition (info, r_type, h);
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
else if (h != NULL)
- {
- tls_type = elf64_x86_64_hash_entry (h)->tls_type;
- if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
- r_type = R_X86_64_TPOFF32;
- }
- if (r_type == R_X86_64_TLSGD
- || r_type == R_X86_64_GOTPC32_TLSDESC
- || r_type == R_X86_64_TLSDESC_CALL)
- {
- if (tls_type == GOT_TLS_IE)
- r_type = R_X86_64_GOTTPOFF;
- }
+ tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+
+ if (! elf64_x86_64_tls_transition (info, input_bfd,
+ input_section, contents,
+ symtab_hdr, sym_hashes,
+ &r_type, tls_type, rel,
+ relend, h))
+ return FALSE;
if (r_type == R_X86_64_TPOFF32)
{
+ bfd_vma roff = rel->r_offset;
+
BFD_ASSERT (! unresolved_reloc);
+
if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
{
- unsigned int i;
- static unsigned char tlsgd[8]
- = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
- unsigned long tls_r_symndx;
- struct elf_link_hash_entry *tls_h;
-
/* GD->LE transition.
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr
Change it into:
movq %fs:0, %rax
leaq foo@tpoff(%rax), %rax */
- BFD_ASSERT (rel->r_offset >= 4);
- for (i = 0; i < 4; i++)
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset - 4 + i)
- == tlsgd[i]);
- BFD_ASSERT (rel->r_offset + 12 <= input_section->size);
- for (i = 0; i < 4; i++)
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset + 4 + i)
- == tlsgd[i+4]);
- BFD_ASSERT (rel + 1 < relend);
- tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
- BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
- tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
- BFD_ASSERT (tls_h != NULL
- && tls_h->root.root.string != NULL
- && strcmp (tls_h->root.root.string,
- "__tls_get_addr") == 0);
- BFD_ASSERT ((! info->shared
- && ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32)
- || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
- memcpy (contents + rel->r_offset - 4,
+ memcpy (contents + roff - 4,
"\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
16);
bfd_put_32 (output_bfd, tpoff (info, relocation),
- contents + rel->r_offset + 8);
+ contents + roff + 8);
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;
@@ -2575,26 +2794,13 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
Change it to:
movl $x@tpoff, %rax
-
- Registers other than %rax may be set up here. */
+ */
unsigned int val, type, type2;
- bfd_vma roff;
- /* First, make sure it's a leaq adding rip to a
- 32-bit offset into any register, although it's
- probably almost always going to be rax. */
- roff = rel->r_offset;
- BFD_ASSERT (roff >= 3);
type = bfd_get_8 (input_bfd, contents + roff - 3);
- BFD_ASSERT ((type & 0xfb) == 0x48);
type2 = bfd_get_8 (input_bfd, contents + roff - 2);
- BFD_ASSERT (type2 == 0x8d);
val = bfd_get_8 (input_bfd, contents + roff - 1);
- BFD_ASSERT ((val & 0xc7) == 0x05);
- BFD_ASSERT (roff + 4 <= input_section->size);
-
- /* Now modify the instruction as appropriate. */
bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
contents + roff - 3);
bfd_put_8 (output_bfd, 0xc7, contents + roff - 2);
@@ -2610,29 +2816,13 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
It's originally:
call *(%rax)
Turn it into:
- nop; nop. */
-
- unsigned int val, type;
- bfd_vma roff;
-
- /* First, make sure it's a call *(%rax). */
- roff = rel->r_offset;
- BFD_ASSERT (roff + 2 <= input_section->size);
- type = bfd_get_8 (input_bfd, contents + roff);
- BFD_ASSERT (type == 0xff);
- val = bfd_get_8 (input_bfd, contents + roff + 1);
- BFD_ASSERT (val == 0x10);
-
- /* Now modify the instruction as appropriate. Use
- xchg %ax,%ax instead of 2 nops. */
+ xchg %ax,%ax. */
bfd_put_8 (output_bfd, 0x66, contents + roff);
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
continue;
}
- else
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF)
{
- unsigned int val, type, reg;
-
/* IE->LE transition:
Originally it can be one of:
movq foo@gottpoff(%rip), %reg
@@ -2641,25 +2831,23 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
movq $foo, %reg
leaq foo(%reg), %reg
addq $foo, %reg. */
- BFD_ASSERT (rel->r_offset >= 3);
- val = bfd_get_8 (input_bfd, contents + rel->r_offset - 3);
- BFD_ASSERT (val == 0x48 || val == 0x4c);
- type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
- BFD_ASSERT (type == 0x8b || type == 0x03);
- reg = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT ((reg & 0xc7) == 5);
+
+ unsigned int val, type, reg;
+
+ val = bfd_get_8 (input_bfd, contents + roff - 3);
+ type = bfd_get_8 (input_bfd, contents + roff - 2);
+ reg = bfd_get_8 (input_bfd, contents + roff - 1);
reg >>= 3;
- BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
if (type == 0x8b)
{
/* movq */
if (val == 0x4c)
bfd_put_8 (output_bfd, 0x49,
- contents + rel->r_offset - 3);
+ contents + roff - 3);
bfd_put_8 (output_bfd, 0xc7,
- contents + rel->r_offset - 2);
+ contents + roff - 2);
bfd_put_8 (output_bfd, 0xc0 | reg,
- contents + rel->r_offset - 1);
+ contents + roff - 1);
}
else if (reg == 4)
{
@@ -2667,27 +2855,29 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
special */
if (val == 0x4c)
bfd_put_8 (output_bfd, 0x49,
- contents + rel->r_offset - 3);
+ contents + roff - 3);
bfd_put_8 (output_bfd, 0x81,
- contents + rel->r_offset - 2);
+ contents + roff - 2);
bfd_put_8 (output_bfd, 0xc0 | reg,
- contents + rel->r_offset - 1);
+ contents + roff - 1);
}
else
{
/* addq -> leaq */
if (val == 0x4c)
bfd_put_8 (output_bfd, 0x4d,
- contents + rel->r_offset - 3);
+ contents + roff - 3);
bfd_put_8 (output_bfd, 0x8d,
- contents + rel->r_offset - 2);
+ contents + roff - 2);
bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
- contents + rel->r_offset - 1);
+ contents + roff - 1);
}
bfd_put_32 (output_bfd, tpoff (info, relocation),
- contents + rel->r_offset);
+ contents + roff);
continue;
}
+ else
+ BFD_ASSERT (FALSE);
}
if (htab->sgot == NULL)
@@ -2814,151 +3004,104 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
+ htab->sgot->output_offset + off;
unresolved_reloc = FALSE;
}
- else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
- {
- unsigned int i;
- static unsigned char tlsgd[8]
- = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
-
- /* GD->IE transition.
- .byte 0x66; leaq foo@tlsgd(%rip), %rdi
- .word 0x6666; rex64; call __tls_get_addr@plt
- Change it into:
- movq %fs:0, %rax
- addq foo@gottpoff(%rip), %rax */
- BFD_ASSERT (rel->r_offset >= 4);
- for (i = 0; i < 4; i++)
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset - 4 + i)
- == tlsgd[i]);
- BFD_ASSERT (rel->r_offset + 12 <= input_section->size);
- for (i = 0; i < 4; i++)
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset + 4 + i)
- == tlsgd[i+4]);
- BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
- memcpy (contents + rel->r_offset - 4,
- "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
- 16);
-
- relocation = (htab->sgot->output_section->vma
- + htab->sgot->output_offset + off
- - rel->r_offset
- - input_section->output_section->vma
- - input_section->output_offset
- - 12);
- bfd_put_32 (output_bfd, relocation,
- contents + rel->r_offset + 8);
- /* Skip R_X86_64_PLT32. */
- rel++;
- continue;
- }
- else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+ else
{
- /* GDesc -> IE transition.
- It's originally something like:
- leaq x@tlsdesc(%rip), %rax
-
- Change it to:
- movq x@gottpoff(%rip), %rax # before nop; nop
-
- Registers other than %rax may be set up here. */
-
- unsigned int val, type, type2;
- bfd_vma roff;
-
- /* First, make sure it's a leaq adding rip to a 32-bit
- offset into any register, although it's probably
- almost always going to be rax. */
- roff = rel->r_offset;
- BFD_ASSERT (roff >= 3);
- type = bfd_get_8 (input_bfd, contents + roff - 3);
- BFD_ASSERT ((type & 0xfb) == 0x48);
- type2 = bfd_get_8 (input_bfd, contents + roff - 2);
- BFD_ASSERT (type2 == 0x8d);
- val = bfd_get_8 (input_bfd, contents + roff - 1);
- BFD_ASSERT ((val & 0xc7) == 0x05);
- BFD_ASSERT (roff + 4 <= input_section->size);
-
- /* Now modify the instruction as appropriate. */
- /* To turn a leaq into a movq in the form we use it, it
- suffices to change the second byte from 0x8d to
- 0x8b. */
- bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
+ bfd_vma roff = rel->r_offset;
- bfd_put_32 (output_bfd,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + off
- - rel->r_offset
- - input_section->output_section->vma
- - input_section->output_offset
- - 4,
- contents + roff);
- continue;
- }
- else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
- {
- /* GDesc -> IE transition.
- It's originally:
- call *(%rax)
+ if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
+ {
+ /* GD->IE transition.
+ .byte 0x66; leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr@plt
+ Change it into:
+ movq %fs:0, %rax
+ addq foo@gottpoff(%rip), %rax */
+ memcpy (contents + roff - 4,
+ "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+ 16);
- Change it to:
- nop; nop. */
+ relocation = (htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - roff
+ - input_section->output_section->vma
+ - input_section->output_offset
+ - 12);
+ bfd_put_32 (output_bfd, relocation,
+ contents + roff + 8);
+ /* Skip R_X86_64_PLT32. */
+ rel++;
+ continue;
+ }
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+ {
+ /* GDesc -> IE transition.
+ It's originally something like:
+ leaq x@tlsdesc(%rip), %rax
- unsigned int val, type;
- bfd_vma roff;
+ Change it to:
+ movq x@gottpoff(%rip), %rax # before xchg %ax,%ax
+ */
- /* First, make sure it's a call *(%eax). */
- roff = rel->r_offset;
- BFD_ASSERT (roff + 2 <= input_section->size);
- type = bfd_get_8 (input_bfd, contents + roff);
- BFD_ASSERT (type == 0xff);
- val = bfd_get_8 (input_bfd, contents + roff + 1);
- BFD_ASSERT (val == 0x10);
+ unsigned int val, type, type2;
- /* Now modify the instruction as appropriate. Use
- xchg %ax,%ax instead of 2 nops. */
- bfd_put_8 (output_bfd, 0x66, contents + roff);
- bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+ type = bfd_get_8 (input_bfd, contents + roff - 3);
+ type2 = bfd_get_8 (input_bfd, contents + roff - 2);
+ val = bfd_get_8 (input_bfd, contents + roff - 1);
- continue;
+ /* Now modify the instruction as appropriate. To
+ turn a leaq into a movq in the form we use it, it
+ suffices to change the second byte from 0x8d to
+ 0x8b. */
+ bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
+
+ bfd_put_32 (output_bfd,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - rel->r_offset
+ - input_section->output_section->vma
+ - input_section->output_offset
+ - 4,
+ contents + roff);
+ continue;
+ }
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
+ {
+ /* GDesc -> IE transition.
+ It's originally:
+ call *(%rax)
+
+ Change it to:
+ xchg %ax,%ax. */
+
+ unsigned int val, type;
+
+ type = bfd_get_8 (input_bfd, contents + roff);
+ val = bfd_get_8 (input_bfd, contents + roff + 1);
+ bfd_put_8 (output_bfd, 0x66, contents + roff);
+ bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+ continue;
+ }
+ else
+ BFD_ASSERT (FALSE);
}
- else
- BFD_ASSERT (FALSE);
break;
case R_X86_64_TLSLD:
- if (! info->shared)
- {
- unsigned long tls_r_symndx;
- struct elf_link_hash_entry *tls_h;
+ if (! elf64_x86_64_tls_transition (info, input_bfd,
+ input_section, contents,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, relend, h))
+ return FALSE;
+ if (r_type != R_X86_64_TLSLD)
+ {
/* LD->LE transition:
- Ensure it is:
leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
We change it into:
.word 0x6666; .byte 0x66; movl %fs:0, %rax. */
- BFD_ASSERT (rel->r_offset >= 3);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 3)
- == 0x48);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
- == 0x8d);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 1)
- == 0x3d);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
- BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
- tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
- BFD_ASSERT (tls_h != NULL
- && tls_h->root.root.string != NULL
- && strcmp (tls_h->root.root.string,
- "__tls_get_addr") == 0);
- BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
- || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+
+ BFD_ASSERT (r_type == R_X86_64_TPOFF32);
memcpy (contents + rel->r_offset - 3,
"\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 59223f0..ad42541 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2007-08-23 H.J. Lu <hongjiu.lu@intel.com>
+
+ * ld-i386/tlsbinpic.s: Add a new GD -> IE test.
+
+ * ld-i386/tlsgd1.s: Add a new GD -> LE test.
+
+ * ld-i386/tlsbin.dd: Updated.
+ * ld-i386/tlsbin.rd: Likewise.
+ * ld-i386/tlsgd1.dd: Likewise.
+
2007-08-17 Jakub Jelinek <jakub@redhat.com>
* ld-sparc/tlssunnopic32.dd: Fix up #target.
diff --git a/ld/testsuite/ld-i386/tlsbin.dd b/ld/testsuite/ld-i386/tlsbin.dd
index 0e3ef4d..e399f86 100644
--- a/ld/testsuite/ld-i386/tlsbin.dd
+++ b/ld/testsuite/ld-i386/tlsbin.dd
@@ -222,235 +222,243 @@ Disassembly of section .text:
8049170: 90[ ]+nop *
8049171: 90[ ]+nop *
8049172: 90[ ]+nop *
- 8049173: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
- 8049176: c9[ ]+leave *
- 8049177: c3[ ]+ret *
+# GD -> IE because variable is not defined in executable
+ 8049173: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 8049179: 2b 83 f8 ff ff ff[ ]+sub -0x8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG1
+ 804917f: 90[ ]+nop *
+ 8049180: 90[ ]+nop *
+ 8049181: 90[ ]+nop *
+ 8049182: 90[ ]+nop *
+ 8049183: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
+ 8049186: c9[ ]+leave *
+ 8049187: c3[ ]+ret *
-0+8049178 <_start>:
- 8049178: 55[ ]+push %ebp
- 8049179: 89 e5[ ]+mov %esp,%ebp
- 804917b: e8 00 00 00 00[ ]+call 8049180 <_start\+0x8>
- 8049180: 59[ ]+pop %ecx
- 8049181: 81 c1 a4 0f 00 00[ ]+add \$0xfa4,%ecx
- 8049187: 90[ ]+nop *
- 8049188: 90[ ]+nop *
- 8049189: 90[ ]+nop *
- 804918a: 90[ ]+nop *
+0+8049188 <_start>:
+ 8049188: 55[ ]+push %ebp
+ 8049189: 89 e5[ ]+mov %esp,%ebp
+ 804918b: e8 00 00 00 00[ ]+call 8049190 <_start\+0x8>
+ 8049190: 59[ ]+pop %ecx
+ 8049191: 81 c1 94 0f 00 00[ ]+add \$0xf94,%ecx
+ 8049197: 90[ ]+nop *
+ 8049198: 90[ ]+nop *
+ 8049199: 90[ ]+nop *
+ 804919a: 90[ ]+nop *
# @gottpoff IE against global var
- 804918b: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
- 8049192: 90[ ]+nop *
- 8049193: 90[ ]+nop *
- 8049194: 2b 91 f4 ff ff ff[ ]+sub -0xc\(%ecx\),%edx
+ 804919b: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80491a2: 90[ ]+nop *
+ 80491a3: 90[ ]+nop *
+ 80491a4: 2b 91 f4 ff ff ff[ ]+sub -0xc\(%ecx\),%edx
# ->R_386_TLS_TPOFF32 sG6
- 804919a: 90[ ]+nop *
- 804919b: 90[ ]+nop *
- 804919c: 90[ ]+nop *
- 804919d: 90[ ]+nop *
-# @indntpoff IE against global var
- 804919e: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
- 80491a4: 90[ ]+nop *
- 80491a5: 90[ ]+nop *
- 80491a6: 03 05 08 a1 04 08[ ]+add 0x804a108,%eax
-# ->R_386_TLS_TPOFF sG7
+ 80491aa: 90[ ]+nop *
+ 80491ab: 90[ ]+nop *
80491ac: 90[ ]+nop *
80491ad: 90[ ]+nop *
- 80491ae: 90[ ]+nop *
- 80491af: 90[ ]+nop *
-# @indntpoff direct %gs access IE against global var
- 80491b0: 8b 15 20 a1 04 08[ ]+mov 0x804a120,%edx
-# ->R_386_TLS_TPOFF sG8
- 80491b6: 90[ ]+nop *
- 80491b7: 90[ ]+nop *
- 80491b8: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
- 80491bb: 90[ ]+nop *
+# @indntpoff IE against global var
+ 80491ae: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 80491b4: 90[ ]+nop *
+ 80491b5: 90[ ]+nop *
+ 80491b6: 03 05 08 a1 04 08[ ]+add 0x804a108,%eax
+# ->R_386_TLS_TPOFF sG7
80491bc: 90[ ]+nop *
80491bd: 90[ ]+nop *
80491be: 90[ ]+nop *
-# @gottpoff IE -> LE against global var defined in exec
- 80491bf: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80491bf: 90[ ]+nop *
+# @indntpoff direct %gs access IE against global var
+ 80491c0: 8b 15 20 a1 04 08[ ]+mov 0x804a120,%edx
+# ->R_386_TLS_TPOFF sG8
80491c6: 90[ ]+nop *
80491c7: 90[ ]+nop *
- 80491c8: 81 ea 8c 0f 00 00[ ]+sub \$0xf8c,%edx
-# bg6
+ 80491c8: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ 80491cb: 90[ ]+nop *
+ 80491cc: 90[ ]+nop *
+ 80491cd: 90[ ]+nop *
80491ce: 90[ ]+nop *
- 80491cf: 90[ ]+nop *
- 80491d0: 90[ ]+nop *
- 80491d1: 90[ ]+nop *
-# @indntpoff IE -> LE against global var defined in exec
- 80491d2: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
- 80491d8: 90[ ]+nop *
- 80491d9: 90[ ]+nop *
- 80491da: 81 c0 78 f0 ff ff[ ]+add \$0xfffff078,%eax
-# bg7
+# @gottpoff IE -> LE against global var defined in exec
+ 80491cf: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80491d6: 90[ ]+nop *
+ 80491d7: 90[ ]+nop *
+ 80491d8: 81 ea 8c 0f 00 00[ ]+sub \$0xf8c,%edx
+# bg6
+ 80491de: 90[ ]+nop *
+ 80491df: 90[ ]+nop *
80491e0: 90[ ]+nop *
80491e1: 90[ ]+nop *
- 80491e2: 90[ ]+nop *
- 80491e3: 90[ ]+nop *
-# @indntpoff direct %gs access IE -> LE against global var defined
-# in exec
- 80491e4: c7 c2 7c f0 ff ff[ ]+mov \$0xfffff07c,%edx
-# bg8
- 80491ea: 90[ ]+nop *
- 80491eb: 90[ ]+nop *
- 80491ec: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
- 80491ef: 90[ ]+nop *
+# @indntpoff IE -> LE against global var defined in exec
+ 80491e2: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 80491e8: 90[ ]+nop *
+ 80491e9: 90[ ]+nop *
+ 80491ea: 81 c0 78 f0 ff ff[ ]+add \$0xfffff078,%eax
+# bg7
80491f0: 90[ ]+nop *
80491f1: 90[ ]+nop *
80491f2: 90[ ]+nop *
-# @gottpoff IE -> LE against local var
- 80491f3: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80491f3: 90[ ]+nop *
+# @indntpoff direct %gs access IE -> LE against global var defined
+# in exec
+ 80491f4: c7 c2 7c f0 ff ff[ ]+mov \$0xfffff07c,%edx
+# bg8
80491fa: 90[ ]+nop *
80491fb: 90[ ]+nop *
- 80491fc: 81 ea 6c 0f 00 00[ ]+sub \$0xf6c,%edx
-# bl6
+ 80491fc: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ 80491ff: 90[ ]+nop *
+ 8049200: 90[ ]+nop *
+ 8049201: 90[ ]+nop *
8049202: 90[ ]+nop *
- 8049203: 90[ ]+nop *
- 8049204: 90[ ]+nop *
- 8049205: 90[ ]+nop *
-# @indntpoff IE -> LE against local var
- 8049206: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
- 804920c: 90[ ]+nop *
- 804920d: 90[ ]+nop *
- 804920e: 81 c0 98 f0 ff ff[ ]+add \$0xfffff098,%eax
-# bl7
+# @gottpoff IE -> LE against local var
+ 8049203: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 804920a: 90[ ]+nop *
+ 804920b: 90[ ]+nop *
+ 804920c: 81 ea 6c 0f 00 00[ ]+sub \$0xf6c,%edx
+# bl6
+ 8049212: 90[ ]+nop *
+ 8049213: 90[ ]+nop *
8049214: 90[ ]+nop *
8049215: 90[ ]+nop *
- 8049216: 90[ ]+nop *
- 8049217: 90[ ]+nop *
-# @indntpoff direct %gs access IE -> LE against local var
- 8049218: c7 c2 9c f0 ff ff[ ]+mov \$0xfffff09c,%edx
-# bl8
- 804921e: 90[ ]+nop *
- 804921f: 90[ ]+nop *
- 8049220: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
- 8049223: 90[ ]+nop *
+# @indntpoff IE -> LE against local var
+ 8049216: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 804921c: 90[ ]+nop *
+ 804921d: 90[ ]+nop *
+ 804921e: 81 c0 98 f0 ff ff[ ]+add \$0xfffff098,%eax
+# bl7
8049224: 90[ ]+nop *
8049225: 90[ ]+nop *
8049226: 90[ ]+nop *
-# @gottpoff IE -> LE against hidden but not local var
- 8049227: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 8049227: 90[ ]+nop *
+# @indntpoff direct %gs access IE -> LE against local var
+ 8049228: c7 c2 9c f0 ff ff[ ]+mov \$0xfffff09c,%edx
+# bl8
804922e: 90[ ]+nop *
804922f: 90[ ]+nop *
- 8049230: 81 ea ac 0f 00 00[ ]+sub \$0xfac,%edx
-# sh6
+ 8049230: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ 8049233: 90[ ]+nop *
+ 8049234: 90[ ]+nop *
+ 8049235: 90[ ]+nop *
8049236: 90[ ]+nop *
- 8049237: 90[ ]+nop *
- 8049238: 90[ ]+nop *
- 8049239: 90[ ]+nop *
-# @indntpoff IE -> LE against hidden but not local var
- 804923a: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
- 8049240: 90[ ]+nop *
- 8049241: 90[ ]+nop *
- 8049242: 81 c0 58 f0 ff ff[ ]+add \$0xfffff058,%eax
-# sh7
+# @gottpoff IE -> LE against hidden but not local var
+ 8049237: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 804923e: 90[ ]+nop *
+ 804923f: 90[ ]+nop *
+ 8049240: 81 ea ac 0f 00 00[ ]+sub \$0xfac,%edx
+# sh6
+ 8049246: 90[ ]+nop *
+ 8049247: 90[ ]+nop *
8049248: 90[ ]+nop *
8049249: 90[ ]+nop *
- 804924a: 90[ ]+nop *
- 804924b: 90[ ]+nop *
-# @indntpoff direct %gs access IE -> LE against hidden but not
-# local var
- 804924c: c7 c2 5c f0 ff ff[ ]+mov \$0xfffff05c,%edx
-# sh8
- 8049252: 90[ ]+nop *
- 8049253: 90[ ]+nop *
- 8049254: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
- 8049257: 90[ ]+nop *
+# @indntpoff IE -> LE against hidden but not local var
+ 804924a: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 8049250: 90[ ]+nop *
+ 8049251: 90[ ]+nop *
+ 8049252: 81 c0 58 f0 ff ff[ ]+add \$0xfffff058,%eax
+# sh7
8049258: 90[ ]+nop *
8049259: 90[ ]+nop *
804925a: 90[ ]+nop *
-# LE @tpoff, global var defined in exec
- 804925b: ba 00 10 00 00[ ]+mov \$0x1000,%edx
-# sg1
- 8049260: 90[ ]+nop *
- 8049261: 90[ ]+nop *
- 8049262: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 804925b: 90[ ]+nop *
+# @indntpoff direct %gs access IE -> LE against hidden but not
+# local var
+ 804925c: c7 c2 5c f0 ff ff[ ]+mov \$0xfffff05c,%edx
+# sh8
+ 8049262: 90[ ]+nop *
+ 8049263: 90[ ]+nop *
+ 8049264: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ 8049267: 90[ ]+nop *
8049268: 90[ ]+nop *
8049269: 90[ ]+nop *
- 804926a: 29 d0[ ]+sub %edx,%eax
- 804926c: 90[ ]+nop *
- 804926d: 90[ ]+nop *
- 804926e: 90[ ]+nop *
- 804926f: 90[ ]+nop *
-# LE @tpoff, local var
- 8049270: b8 7f 0f 00 00[ ]+mov \$0xf7f,%eax
-# bl1+1
- 8049275: 90[ ]+nop *
- 8049276: 90[ ]+nop *
- 8049277: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 804926a: 90[ ]+nop *
+# LE @tpoff, global var defined in exec
+ 804926b: ba 00 10 00 00[ ]+mov \$0x1000,%edx
+# sg1
+ 8049270: 90[ ]+nop *
+ 8049271: 90[ ]+nop *
+ 8049272: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 8049278: 90[ ]+nop *
+ 8049279: 90[ ]+nop *
+ 804927a: 29 d0[ ]+sub %edx,%eax
+ 804927c: 90[ ]+nop *
+ 804927d: 90[ ]+nop *
804927e: 90[ ]+nop *
804927f: 90[ ]+nop *
- 8049280: 29 c2[ ]+sub %eax,%edx
- 8049282: 90[ ]+nop *
- 8049283: 90[ ]+nop *
- 8049284: 90[ ]+nop *
+# LE @tpoff, local var
+ 8049280: b8 7f 0f 00 00[ ]+mov \$0xf7f,%eax
+# bl1+1
8049285: 90[ ]+nop *
-# LE @tpoff, hidden var defined in exec
- 8049286: b8 bd 0f 00 00[ ]+mov \$0xfbd,%eax
-# sh1+3
- 804928b: 90[ ]+nop *
- 804928c: 90[ ]+nop *
- 804928d: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 8049286: 90[ ]+nop *
+ 8049287: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 804928e: 90[ ]+nop *
+ 804928f: 90[ ]+nop *
+ 8049290: 29 c2[ ]+sub %eax,%edx
+ 8049292: 90[ ]+nop *
+ 8049293: 90[ ]+nop *
8049294: 90[ ]+nop *
8049295: 90[ ]+nop *
- 8049296: 29 c2[ ]+sub %eax,%edx
- 8049298: 90[ ]+nop *
- 8049299: 90[ ]+nop *
- 804929a: 90[ ]+nop *
+# LE @tpoff, hidden var defined in exec
+ 8049296: b8 bd 0f 00 00[ ]+mov \$0xfbd,%eax
+# sh1+3
804929b: 90[ ]+nop *
-# LE @ntpoff, global var defined in exec
- 804929c: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
- 80492a2: 90[ ]+nop *
- 80492a3: 90[ ]+nop *
- 80492a4: 8d 90 04 f0 ff ff[ ]+lea -0xffc\(%eax\),%edx
-# sg2
+ 804929c: 90[ ]+nop *
+ 804929d: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80492a4: 90[ ]+nop *
+ 80492a5: 90[ ]+nop *
+ 80492a6: 29 c2[ ]+sub %eax,%edx
+ 80492a8: 90[ ]+nop *
+ 80492a9: 90[ ]+nop *
80492aa: 90[ ]+nop *
80492ab: 90[ ]+nop *
- 80492ac: 90[ ]+nop *
- 80492ad: 90[ ]+nop *
-# LE @ntpoff, local var, non-canonical sequence
- 80492ae: b8 86 f0 ff ff[ ]+mov \$0xfffff086,%eax
-# bl2+2
+# LE @ntpoff, global var defined in exec
+ 80492ac: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ 80492b2: 90[ ]+nop *
80492b3: 90[ ]+nop *
- 80492b4: 90[ ]+nop *
- 80492b5: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80492b4: 8d 90 04 f0 ff ff[ ]+lea -0xffc\(%eax\),%edx
+# sg2
+ 80492ba: 90[ ]+nop *
+ 80492bb: 90[ ]+nop *
80492bc: 90[ ]+nop *
80492bd: 90[ ]+nop *
- 80492be: 01 c2[ ]+add %eax,%edx
- 80492c0: 90[ ]+nop *
- 80492c1: 90[ ]+nop *
- 80492c2: 90[ ]+nop *
+# LE @ntpoff, local var, non-canonical sequence
+ 80492be: b8 86 f0 ff ff[ ]+mov \$0xfffff086,%eax
+# bl2+2
80492c3: 90[ ]+nop *
-# LE @ntpoff, hidden var defined in exec, non-canonical sequence
- 80492c4: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
- 80492cb: 90[ ]+nop *
+ 80492c4: 90[ ]+nop *
+ 80492c5: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
80492cc: 90[ ]+nop *
- 80492cd: 81 c2 45 f0 ff ff[ ]+add \$0xfffff045,%edx
-# sh2+1
+ 80492cd: 90[ ]+nop *
+ 80492ce: 01 c2[ ]+add %eax,%edx
+ 80492d0: 90[ ]+nop *
+ 80492d1: 90[ ]+nop *
+ 80492d2: 90[ ]+nop *
80492d3: 90[ ]+nop *
- 80492d4: 90[ ]+nop *
- 80492d5: 90[ ]+nop *
- 80492d6: 90[ ]+nop *
+# LE @ntpoff, hidden var defined in exec, non-canonical sequence
+ 80492d4: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ 80492db: 90[ ]+nop *
+ 80492dc: 90[ ]+nop *
+ 80492dd: 81 c2 45 f0 ff ff[ ]+add \$0xfffff045,%edx
+# sh2+1
+ 80492e3: 90[ ]+nop *
+ 80492e4: 90[ ]+nop *
+ 80492e5: 90[ ]+nop *
+ 80492e6: 90[ ]+nop *
# LE @ntpoff, global var defined in exec
- 80492d7: 65 a1 08 f0 ff ff[ ]+mov %gs:0xfffff008,%eax
+ 80492e7: 65 a1 08 f0 ff ff[ ]+mov %gs:0xfffff008,%eax
# sg3
- 80492dd: 90[ ]+nop *
- 80492de: 90[ ]+nop *
- 80492df: 90[ ]+nop *
- 80492e0: 90[ ]+nop *
+ 80492ed: 90[ ]+nop *
+ 80492ee: 90[ ]+nop *
+ 80492ef: 90[ ]+nop *
+ 80492f0: 90[ ]+nop *
# LE @ntpoff, local var
- 80492e1: 65 8b 15 8b f0 ff ff[ ]+mov %gs:0xfffff08b,%edx
+ 80492f1: 65 8b 15 8b f0 ff ff[ ]+mov %gs:0xfffff08b,%edx
# bl3+3
- 80492e8: 90[ ]+nop *
- 80492e9: 90[ ]+nop *
- 80492ea: 90[ ]+nop *
- 80492eb: 90[ ]+nop *
+ 80492f8: 90[ ]+nop *
+ 80492f9: 90[ ]+nop *
+ 80492fa: 90[ ]+nop *
+ 80492fb: 90[ ]+nop *
# LE @ntpoff, hidden var defined in exec
- 80492ec: 65 8b 15 49 f0 ff ff[ ]+mov %gs:0xfffff049,%edx
+ 80492fc: 65 8b 15 49 f0 ff ff[ ]+mov %gs:0xfffff049,%edx
# sh3+1
- 80492f3: 90[ ]+nop *
- 80492f4: 90[ ]+nop *
- 80492f5: 90[ ]+nop *
- 80492f6: 90[ ]+nop *
- 80492f7: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
- 80492fa: c9[ ]+leave *
- 80492fb: c3[ ]+ret *
+ 8049303: 90[ ]+nop *
+ 8049304: 90[ ]+nop *
+ 8049305: 90[ ]+nop *
+ 8049306: 90[ ]+nop *
+ 8049307: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
+ 804930a: c9[ ]+leave *
+ 804930b: c3[ ]+ret *
diff --git a/ld/testsuite/ld-i386/tlsbin.rd b/ld/testsuite/ld-i386/tlsbin.rd
index 54abd8b..10934cb 100644
--- a/ld/testsuite/ld-i386/tlsbin.rd
+++ b/ld/testsuite/ld-i386/tlsbin.rd
@@ -32,7 +32,7 @@ Key to Flags:
.*
Elf file type is EXEC \(Executable file\)
-Entry point 0x8049178
+Entry point 0x8049188
There are 6 program headers, starting at offset [0-9]+
Program Headers:
@@ -137,7 +137,7 @@ Symbol table '.symtab' contains 70 entries:
+[0-9]+: 00000058 +0 TLS +GLOBAL HIDDEN +9 sh7
+[0-9]+: 0000005c +0 TLS +GLOBAL HIDDEN +9 sh8
+[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +9 sg1
- +[0-9]+: 0+8049178 +0 FUNC +GLOBAL DEFAULT +8 _start
+ +[0-9]+: 0+8049188 +0 FUNC +GLOBAL DEFAULT +8 _start
+[0-9]+: 0000004c +0 TLS +GLOBAL HIDDEN +9 sh4
+[0-9]+: 00000078 +0 TLS +GLOBAL DEFAULT +10 bg7
+[0-9]+: 00000050 +0 TLS +GLOBAL HIDDEN +9 sh5
diff --git a/ld/testsuite/ld-i386/tlsbinpic.s b/ld/testsuite/ld-i386/tlsbinpic.s
index 844f952..9c8a006 100644
--- a/ld/testsuite/ld-i386/tlsbinpic.s
+++ b/ld/testsuite/ld-i386/tlsbinpic.s
@@ -162,6 +162,11 @@ fn2:
movl %gs:(%edx), %edx
nop;nop;nop;nop
+ /* GD -> IE because variable is not defined in executable */
+ leal sG1@tlsgd(%ebx), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop;nop
+
movl -4(%ebp), %ebx
leave
ret
diff --git a/ld/testsuite/ld-i386/tlsgd1.dd b/ld/testsuite/ld-i386/tlsgd1.dd
index 54d7416..9a33132 100644
--- a/ld/testsuite/ld-i386/tlsgd1.dd
+++ b/ld/testsuite/ld-i386/tlsgd1.dd
@@ -11,4 +11,6 @@ Disassembly of section .text:
[a-f0-9]+ <_start>:
[ ]*[a-f0-9]+: 65 a1 00 00 00 00 mov %gs:0x0,%eax
[ ]*[a-f0-9]+: 81 e8 04 00 00 00 sub \$0x4,%eax
+[ ]*[a-f0-9]+: 65 a1 00 00 00 00 mov %gs:0x0,%eax
+[ ]*[a-f0-9]+: 81 e8 04 00 00 00 sub \$0x4,%eax
#pass
diff --git a/ld/testsuite/ld-i386/tlsgd1.s b/ld/testsuite/ld-i386/tlsgd1.s
index 2b3ed0e..552ca09 100644
--- a/ld/testsuite/ld-i386/tlsgd1.s
+++ b/ld/testsuite/ld-i386/tlsgd1.s
@@ -3,6 +3,9 @@
_start:
leal foo@TLSGD(,%ebx,1), %eax
call ___tls_get_addr
+ leal foo@TLSGD(%ebx), %eax
+ call ___tls_get_addr
+ nop
.globl foo
.section .tdata,"awT",@progbits
.align 4