From 142411caf2c5e5625b3870049219e1c52e2ffaec Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 23 Aug 2007 16:13:37 +0000 Subject: [PATCH] bfd/ 2007-08-23 H.J. Lu * 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. ld/testsuite/ 2007-08-23 H.J. Lu * 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. --- bfd/ChangeLog | 27 ++ bfd/elf32-i386.c | 508 ++++++++++++++++--------- bfd/elf64-x86-64.c | 627 +++++++++++++++++++------------ ld/testsuite/ChangeLog | 10 + ld/testsuite/ld-i386/tlsbin.dd | 366 +++++++++--------- ld/testsuite/ld-i386/tlsbin.rd | 4 +- ld/testsuite/ld-i386/tlsbinpic.s | 5 + ld/testsuite/ld-i386/tlsgd1.dd | 2 + ld/testsuite/ld-i386/tlsgd1.s | 3 + 9 files changed, 955 insertions(+), 597 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a437ad82bd..71d760a2f5 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,30 @@ +2007-08-23 H.J. Lu + + * 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 * elfxx-ia64.c: Convert to ISO C90 prototypes. diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index af3b860ab7..072dc6fe9f 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, +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) +{ + 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) { - if (info->shared) - return r_type; + unsigned int from_type = *r_type; + unsigned int to_type = from_type; + bfd_boolean check = TRUE; - switch (r_type) + 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 r_type; + /* 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; + } + + *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 d73b270f75..34eae58768 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, +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) +{ + 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) { - if (info->shared) - return r_type; + unsigned int from_type = *r_type; + unsigned int to_type = from_type; + bfd_boolean check = TRUE; - switch (r_type) + 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 r_type; + /* 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; + } + + *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) - { - /* 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_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: - nop; nop. */ - - 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 - BFD_ASSERT (FALSE); + { + bfd_vma roff = rel->r_offset; + + 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); + + 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 + + Change it to: + movq x@gottpoff(%rip), %rax # before xchg %ax,%ax + */ + + unsigned int val, type, type2; + + 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); + + /* 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); + } 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 59223f0dfe..ad425418a5 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2007-08-23 H.J. Lu + + * 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 * ld-sparc/tlssunnopic32.dd: Fix up #target. diff --git a/ld/testsuite/ld-i386/tlsbin.dd b/ld/testsuite/ld-i386/tlsbin.dd index 0e3ef4d948..e399f867d4 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 * -# @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 -# ->R_386_TLS_TPOFF32 sG6 +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 * - 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 +# @gottpoff IE against global var + 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 + 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 54abd8bdbf..10934cb087 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 844f952628..9c8a0064df 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 54d741651f..9a3313242a 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 2b3ed0e8be..552ca09458 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