bfd/
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. ld/testsuite/ 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.
This commit is contained in:
parent
f467aa98dd
commit
142411caf2
|
@ -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>
|
2007-08-22 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* elfxx-ia64.c: Convert to ISO C90 prototypes.
|
* elfxx-ia64.c: Convert to ISO C90 prototypes.
|
||||||
|
|
490
bfd/elf32-i386.c
490
bfd/elf32-i386.c
|
@ -25,6 +25,7 @@
|
||||||
#include "libbfd.h"
|
#include "libbfd.h"
|
||||||
#include "elf-bfd.h"
|
#include "elf-bfd.h"
|
||||||
#include "elf-vxworks.h"
|
#include "elf-vxworks.h"
|
||||||
|
#include "bfd_stdint.h"
|
||||||
|
|
||||||
/* 386 uses REL relocations instead of RELA. */
|
/* 386 uses REL relocations instead of RELA. */
|
||||||
#define USE_REL 1
|
#define USE_REL 1
|
||||||
|
@ -345,12 +346,9 @@ elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static reloc_howto_type *
|
||||||
elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
|
elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
|
||||||
arelent *cache_ptr,
|
|
||||||
Elf_Internal_Rela *dst)
|
|
||||||
{
|
{
|
||||||
unsigned int r_type = ELF32_R_TYPE (dst->r_info);
|
|
||||||
unsigned int indx;
|
unsigned int indx;
|
||||||
|
|
||||||
if ((indx = r_type) >= R_386_standard
|
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);
|
abfd, (int) r_type);
|
||||||
indx = R_386_NONE;
|
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
|
/* 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);
|
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
typedef union
|
||||||
elf_i386_tls_transition (struct bfd_link_info *info, int r_type,
|
{
|
||||||
|
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)
|
struct elf_link_hash_entry *h)
|
||||||
{
|
{
|
||||||
if (info->shared)
|
unsigned int from_type = *r_type;
|
||||||
return 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_GD:
|
||||||
case R_386_TLS_GOTDESC:
|
case R_386_TLS_GOTDESC:
|
||||||
case R_386_TLS_DESC_CALL:
|
case R_386_TLS_DESC_CALL:
|
||||||
case R_386_TLS_IE_32:
|
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_IE:
|
||||||
case R_386_TLS_GOTIE:
|
case R_386_TLS_GOTIE:
|
||||||
|
if (!info->shared)
|
||||||
|
{
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
return R_386_TLS_LE_32;
|
to_type = R_386_TLS_LE_32;
|
||||||
return r_type;
|
else if (from_type != R_386_TLS_IE
|
||||||
case R_386_TLS_LDM:
|
&& from_type != R_386_TLS_GOTIE)
|
||||||
return R_386_TLS_LE_32;
|
to_type = R_386_TLS_IE_32;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r_type;
|
/* 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:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_type = to_type;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look through the relocs for a section during the first phase, and
|
/* 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;
|
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)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
|
@ -1364,7 +1637,12 @@ elf_i386_gc_sweep_hook (bfd *abfd,
|
||||||
}
|
}
|
||||||
|
|
||||||
r_type = ELF32_R_TYPE (rel->r_info);
|
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)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case R_386_TLS_LDM:
|
case R_386_TLS_LDM:
|
||||||
|
@ -2624,80 +2902,42 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
case R_386_TLS_DESC_CALL:
|
case R_386_TLS_DESC_CALL:
|
||||||
case R_386_TLS_IE_32:
|
case R_386_TLS_IE_32:
|
||||||
case R_386_TLS_GOTIE:
|
case R_386_TLS_GOTIE:
|
||||||
r_type = elf_i386_tls_transition (info, r_type, h);
|
|
||||||
tls_type = GOT_UNKNOWN;
|
tls_type = GOT_UNKNOWN;
|
||||||
if (h == NULL && local_got_offsets)
|
if (h == NULL && local_got_offsets)
|
||||||
tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx];
|
tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx];
|
||||||
else if (h != NULL)
|
else if (h != NULL)
|
||||||
{
|
|
||||||
tls_type = elf_i386_hash_entry(h)->tls_type;
|
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;
|
|
||||||
}
|
|
||||||
if (tls_type == GOT_TLS_IE)
|
if (tls_type == GOT_TLS_IE)
|
||||||
tls_type = GOT_TLS_IE_NEG;
|
tls_type = GOT_TLS_IE_NEG;
|
||||||
if (r_type == R_386_TLS_GD
|
|
||||||
|| r_type == R_386_TLS_GOTDESC
|
if (! elf_i386_tls_transition (info, input_bfd,
|
||||||
|| r_type == R_386_TLS_DESC_CALL)
|
input_section, contents,
|
||||||
{
|
symtab_hdr, sym_hashes,
|
||||||
if (tls_type == GOT_TLS_IE_POS)
|
&r_type, tls_type, rel,
|
||||||
r_type = R_386_TLS_GOTIE;
|
relend, h))
|
||||||
else if (tls_type & GOT_TLS_IE)
|
return FALSE;
|
||||||
r_type = R_386_TLS_IE_32;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r_type == R_386_TLS_LE_32)
|
if (r_type == R_386_TLS_LE_32)
|
||||||
{
|
{
|
||||||
BFD_ASSERT (! unresolved_reloc);
|
BFD_ASSERT (! unresolved_reloc);
|
||||||
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
|
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
|
||||||
{
|
{
|
||||||
unsigned int val, type;
|
unsigned int type;
|
||||||
bfd_vma roff;
|
bfd_vma roff;
|
||||||
unsigned long tls_r_symndx;
|
|
||||||
struct elf_link_hash_entry *tls_h;
|
|
||||||
|
|
||||||
/* GD->LE transition. */
|
/* GD->LE transition. */
|
||||||
BFD_ASSERT (rel->r_offset >= 2);
|
|
||||||
type = bfd_get_8 (input_bfd, contents + 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)
|
if (type == 0x04)
|
||||||
{
|
{
|
||||||
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
|
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
|
||||||
Change it into:
|
Change it into:
|
||||||
movl %gs:0, %eax; subl $foo@tpoff, %eax
|
movl %gs:0, %eax; subl $foo@tpoff, %eax
|
||||||
(6 byte form of subl). */
|
(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,
|
memcpy (contents + rel->r_offset - 3,
|
||||||
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
|
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
|
||||||
|
roff = rel->r_offset + 5;
|
||||||
}
|
}
|
||||||
else
|
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
|
/* leal foo(%reg), %eax; call ___tls_get_addr; nop
|
||||||
Change it into:
|
Change it into:
|
||||||
|
@ -2707,16 +2947,6 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
|
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
|
||||||
roff = rel->r_offset + 6;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bfd_put_32 (output_bfd, tpoff (info, relocation),
|
bfd_put_32 (output_bfd, tpoff (info, relocation),
|
||||||
contents + roff);
|
contents + roff);
|
||||||
/* Skip R_386_PC32/R_386_PLT32. */
|
/* Skip R_386_PC32/R_386_PLT32. */
|
||||||
|
@ -2733,19 +2963,11 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
|
|
||||||
Registers other than %eax may be set up here. */
|
Registers other than %eax may be set up here. */
|
||||||
|
|
||||||
unsigned int val, type;
|
unsigned int val;
|
||||||
bfd_vma roff;
|
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;
|
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);
|
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. */
|
/* Now modify the instruction as appropriate. */
|
||||||
/* aoliva FIXME: remove the above and xor the byte
|
/* aoliva FIXME: remove the above and xor the byte
|
||||||
|
@ -2762,28 +2984,18 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
It's originally:
|
It's originally:
|
||||||
call *(%eax)
|
call *(%eax)
|
||||||
Turn it into:
|
Turn it into:
|
||||||
nop; nop */
|
xchg %ax,%ax */
|
||||||
|
|
||||||
unsigned int val, type;
|
|
||||||
bfd_vma roff;
|
bfd_vma roff;
|
||||||
|
|
||||||
/* First, make sure it's a call *(%eax). */
|
|
||||||
roff = rel->r_offset;
|
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, 0x66, contents + roff);
|
||||||
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
|
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
|
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
|
||||||
{
|
{
|
||||||
unsigned int val, type;
|
unsigned int val;
|
||||||
|
|
||||||
/* IE->LE transition:
|
/* IE->LE transition:
|
||||||
Originally it can be one of:
|
Originally it can be one of:
|
||||||
|
@ -2794,9 +3006,7 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
movl $foo, %eax
|
movl $foo, %eax
|
||||||
movl $foo, %reg
|
movl $foo, %reg
|
||||||
addl $foo, %reg. */
|
addl $foo, %reg. */
|
||||||
BFD_ASSERT (rel->r_offset >= 1);
|
|
||||||
val = bfd_get_8 (input_bfd, contents + 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)
|
if (val == 0xa1)
|
||||||
{
|
{
|
||||||
/* movl foo, %eax. */
|
/* movl foo, %eax. */
|
||||||
|
@ -2805,14 +3015,14 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BFD_ASSERT (rel->r_offset >= 2);
|
unsigned int type;
|
||||||
|
|
||||||
type = bfd_get_8 (input_bfd,
|
type = bfd_get_8 (input_bfd,
|
||||||
contents + rel->r_offset - 2);
|
contents + rel->r_offset - 2);
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 0x8b:
|
case 0x8b:
|
||||||
/* movl */
|
/* movl */
|
||||||
BFD_ASSERT ((val & 0xc7) == 0x05);
|
|
||||||
bfd_put_8 (output_bfd, 0xc7,
|
bfd_put_8 (output_bfd, 0xc7,
|
||||||
contents + rel->r_offset - 2);
|
contents + rel->r_offset - 2);
|
||||||
bfd_put_8 (output_bfd,
|
bfd_put_8 (output_bfd,
|
||||||
|
@ -2821,7 +3031,6 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
/* addl */
|
/* addl */
|
||||||
BFD_ASSERT ((val & 0xc7) == 0x05);
|
|
||||||
bfd_put_8 (output_bfd, 0x81,
|
bfd_put_8 (output_bfd, 0x81,
|
||||||
contents + rel->r_offset - 2);
|
contents + rel->r_offset - 2);
|
||||||
bfd_put_8 (output_bfd,
|
bfd_put_8 (output_bfd,
|
||||||
|
@ -2850,11 +3059,8 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
subl $foo, %reg2
|
subl $foo, %reg2
|
||||||
movl $foo, %reg2 (6 byte form)
|
movl $foo, %reg2 (6 byte form)
|
||||||
addl $foo, %reg2. */
|
addl $foo, %reg2. */
|
||||||
BFD_ASSERT (rel->r_offset >= 2);
|
|
||||||
type = bfd_get_8 (input_bfd, contents + 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);
|
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)
|
if (type == 0x8b)
|
||||||
{
|
{
|
||||||
/* movl */
|
/* movl */
|
||||||
|
@ -3055,38 +3261,21 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
bfd_vma roff;
|
bfd_vma roff;
|
||||||
|
|
||||||
/* GD->IE transition. */
|
/* GD->IE transition. */
|
||||||
BFD_ASSERT (rel->r_offset >= 2);
|
|
||||||
type = bfd_get_8 (input_bfd, contents + 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);
|
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
|
||||||
if (type == 0x04)
|
if (type == 0x04)
|
||||||
{
|
{
|
||||||
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
|
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
|
||||||
Change it into:
|
Change it into:
|
||||||
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
|
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;
|
val >>= 3;
|
||||||
|
roff = rel->r_offset - 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* leal foo(%reg), %eax; call ___tls_get_addr; nop
|
/* leal foo(%reg), %eax; call ___tls_get_addr; nop
|
||||||
Change it into:
|
Change it into:
|
||||||
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
|
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;
|
roff = rel->r_offset - 2;
|
||||||
}
|
}
|
||||||
memcpy (contents + roff,
|
memcpy (contents + roff,
|
||||||
|
@ -3116,25 +3305,18 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
leal x@tlsdesc(%ebx), %eax
|
leal x@tlsdesc(%ebx), %eax
|
||||||
|
|
||||||
Change it to:
|
Change it to:
|
||||||
movl x@gotntpoff(%ebx), %eax # before nop; nop
|
movl x@gotntpoff(%ebx), %eax # before xchg %ax,%ax
|
||||||
or:
|
or:
|
||||||
movl x@gottpoff(%ebx), %eax # before negl %eax
|
movl x@gottpoff(%ebx), %eax # before negl %eax
|
||||||
|
|
||||||
Registers other than %eax may be set up here. */
|
Registers other than %eax may be set up here. */
|
||||||
|
|
||||||
unsigned int val, type;
|
|
||||||
bfd_vma roff;
|
bfd_vma roff;
|
||||||
|
|
||||||
/* First, make sure it's a leal adding ebx to a 32-bit
|
/* First, make sure it's a leal adding ebx to a 32-bit
|
||||||
offset into any register, although it's probably
|
offset into any register, although it's probably
|
||||||
almost always going to be eax. */
|
almost always going to be eax. */
|
||||||
roff = rel->r_offset;
|
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. */
|
/* Now modify the instruction as appropriate. */
|
||||||
/* To turn a leal into a movl in the form we use it, it
|
/* 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)
|
call *(%eax)
|
||||||
|
|
||||||
Change it to:
|
Change it to:
|
||||||
nop; nop
|
xchg %ax,%ax
|
||||||
or
|
or
|
||||||
negl %eax
|
negl %eax
|
||||||
depending on how we transformed the TLS_GOTDESC above.
|
depending on how we transformed the TLS_GOTDESC above.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int val, type;
|
|
||||||
bfd_vma roff;
|
bfd_vma roff;
|
||||||
|
|
||||||
/* First, make sure it's a call *(%eax). */
|
|
||||||
roff = rel->r_offset;
|
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. */
|
/* Now modify the instruction as appropriate. */
|
||||||
if (tls_type != GOT_TLS_IE_NEG)
|
if (tls_type != GOT_TLS_IE_NEG)
|
||||||
|
@ -3200,35 +3375,20 @@ elf_i386_relocate_section (bfd *output_bfd,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_386_TLS_LDM:
|
case R_386_TLS_LDM:
|
||||||
if (! info->shared)
|
if (! elf_i386_tls_transition (info, input_bfd,
|
||||||
{
|
input_section, contents,
|
||||||
unsigned int val;
|
symtab_hdr, sym_hashes,
|
||||||
unsigned long tls_r_symndx;
|
&r_type, GOT_UNKNOWN, rel,
|
||||||
struct elf_link_hash_entry *tls_h;
|
relend, h))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (r_type != R_386_TLS_LDM)
|
||||||
|
{
|
||||||
/* LD->LE transition:
|
/* LD->LE transition:
|
||||||
Ensure it is:
|
|
||||||
leal foo(%reg), %eax; call ___tls_get_addr.
|
leal foo(%reg), %eax; call ___tls_get_addr.
|
||||||
We change it into:
|
We change it into:
|
||||||
movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */
|
movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */
|
||||||
BFD_ASSERT (rel->r_offset >= 2);
|
BFD_ASSERT (r_type == R_386_TLS_LE_32);
|
||||||
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);
|
|
||||||
memcpy (contents + rel->r_offset - 2,
|
memcpy (contents + rel->r_offset - 2,
|
||||||
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
|
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
|
||||||
/* Skip R_386_PC32/R_386_PLT32. */
|
/* Skip R_386_PC32/R_386_PLT32. */
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "bfdlink.h"
|
#include "bfdlink.h"
|
||||||
#include "libbfd.h"
|
#include "libbfd.h"
|
||||||
#include "elf-bfd.h"
|
#include "elf-bfd.h"
|
||||||
|
#include "bfd_stdint.h"
|
||||||
|
|
||||||
#include "elf/x86-64.h"
|
#include "elf/x86-64.h"
|
||||||
|
|
||||||
|
@ -712,27 +713,262 @@ elf64_x86_64_elf_object_p (bfd *abfd)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
typedef union
|
||||||
elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type,
|
{
|
||||||
|
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)
|
struct elf_link_hash_entry *h)
|
||||||
{
|
{
|
||||||
if (info->shared)
|
unsigned int from_type = *r_type;
|
||||||
return 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_TLSGD:
|
||||||
case R_X86_64_GOTPC32_TLSDESC:
|
case R_X86_64_GOTPC32_TLSDESC:
|
||||||
case R_X86_64_TLSDESC_CALL:
|
case R_X86_64_TLSDESC_CALL:
|
||||||
case R_X86_64_GOTTPOFF:
|
case R_X86_64_GOTTPOFF:
|
||||||
|
if (!info->shared)
|
||||||
|
{
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
return R_X86_64_TPOFF32;
|
to_type = R_X86_64_TPOFF32;
|
||||||
return R_X86_64_GOTTPOFF;
|
else
|
||||||
case R_X86_64_TLSLD:
|
to_type = R_X86_64_GOTTPOFF;
|
||||||
return R_X86_64_TPOFF32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r_type;
|
/* 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:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_type = to_type;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look through the relocs for a section during the first phase, and
|
/* 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. */
|
linkage table, and dynamic reloc sections. */
|
||||||
|
|
||||||
static bfd_boolean
|
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)
|
const Elf_Internal_Rela *relocs)
|
||||||
{
|
{
|
||||||
struct elf64_x86_64_link_hash_table *htab;
|
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;
|
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)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case R_X86_64_TLSLD:
|
case R_X86_64_TLSLD:
|
||||||
|
@ -1173,7 +1415,8 @@ elf64_x86_64_gc_mark_hook (asection *sec,
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
|
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;
|
Elf_Internal_Shdr *symtab_hdr;
|
||||||
struct elf_link_hash_entry **sym_hashes;
|
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_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)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case R_X86_64_TLSLD:
|
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_GOTPC32_TLSDESC:
|
||||||
case R_X86_64_TLSDESC_CALL:
|
case R_X86_64_TLSDESC_CALL:
|
||||||
case R_X86_64_GOTTPOFF:
|
case R_X86_64_GOTTPOFF:
|
||||||
r_type = elf64_x86_64_tls_transition (info, r_type, h);
|
|
||||||
tls_type = GOT_UNKNOWN;
|
tls_type = GOT_UNKNOWN;
|
||||||
if (h == NULL && local_got_offsets)
|
if (h == NULL && local_got_offsets)
|
||||||
tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
|
tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
|
||||||
else if (h != NULL)
|
else if (h != NULL)
|
||||||
{
|
|
||||||
tls_type = elf64_x86_64_hash_entry (h)->tls_type;
|
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 (! elf64_x86_64_tls_transition (info, input_bfd,
|
||||||
}
|
input_section, contents,
|
||||||
if (r_type == R_X86_64_TLSGD
|
symtab_hdr, sym_hashes,
|
||||||
|| r_type == R_X86_64_GOTPC32_TLSDESC
|
&r_type, tls_type, rel,
|
||||||
|| r_type == R_X86_64_TLSDESC_CALL)
|
relend, h))
|
||||||
{
|
return FALSE;
|
||||||
if (tls_type == GOT_TLS_IE)
|
|
||||||
r_type = R_X86_64_GOTTPOFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r_type == R_X86_64_TPOFF32)
|
if (r_type == R_X86_64_TPOFF32)
|
||||||
{
|
{
|
||||||
|
bfd_vma roff = rel->r_offset;
|
||||||
|
|
||||||
BFD_ASSERT (! unresolved_reloc);
|
BFD_ASSERT (! unresolved_reloc);
|
||||||
|
|
||||||
if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
|
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.
|
/* GD->LE transition.
|
||||||
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
|
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
|
||||||
.word 0x6666; rex64; call __tls_get_addr
|
.word 0x6666; rex64; call __tls_get_addr
|
||||||
Change it into:
|
Change it into:
|
||||||
movq %fs:0, %rax
|
movq %fs:0, %rax
|
||||||
leaq foo@tpoff(%rax), %rax */
|
leaq foo@tpoff(%rax), %rax */
|
||||||
BFD_ASSERT (rel->r_offset >= 4);
|
memcpy (contents + roff - 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,
|
|
||||||
"\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
|
"\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
|
||||||
16);
|
16);
|
||||||
bfd_put_32 (output_bfd, tpoff (info, relocation),
|
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. */
|
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
|
||||||
rel++;
|
rel++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -2575,26 +2794,13 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
|
|
||||||
Change it to:
|
Change it to:
|
||||||
movl $x@tpoff, %rax
|
movl $x@tpoff, %rax
|
||||||
|
*/
|
||||||
Registers other than %rax may be set up here. */
|
|
||||||
|
|
||||||
unsigned int val, type, type2;
|
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);
|
type = bfd_get_8 (input_bfd, contents + roff - 3);
|
||||||
BFD_ASSERT ((type & 0xfb) == 0x48);
|
|
||||||
type2 = bfd_get_8 (input_bfd, contents + roff - 2);
|
type2 = bfd_get_8 (input_bfd, contents + roff - 2);
|
||||||
BFD_ASSERT (type2 == 0x8d);
|
|
||||||
val = bfd_get_8 (input_bfd, contents + roff - 1);
|
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),
|
bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
|
||||||
contents + roff - 3);
|
contents + roff - 3);
|
||||||
bfd_put_8 (output_bfd, 0xc7, contents + roff - 2);
|
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:
|
It's originally:
|
||||||
call *(%rax)
|
call *(%rax)
|
||||||
Turn it into:
|
Turn it into:
|
||||||
nop; nop. */
|
xchg %ax,%ax. */
|
||||||
|
|
||||||
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. */
|
|
||||||
bfd_put_8 (output_bfd, 0x66, contents + roff);
|
bfd_put_8 (output_bfd, 0x66, contents + roff);
|
||||||
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
|
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF)
|
||||||
{
|
{
|
||||||
unsigned int val, type, reg;
|
|
||||||
|
|
||||||
/* IE->LE transition:
|
/* IE->LE transition:
|
||||||
Originally it can be one of:
|
Originally it can be one of:
|
||||||
movq foo@gottpoff(%rip), %reg
|
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
|
movq $foo, %reg
|
||||||
leaq foo(%reg), %reg
|
leaq foo(%reg), %reg
|
||||||
addq $foo, %reg. */
|
addq $foo, %reg. */
|
||||||
BFD_ASSERT (rel->r_offset >= 3);
|
|
||||||
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 3);
|
unsigned int val, type, reg;
|
||||||
BFD_ASSERT (val == 0x48 || val == 0x4c);
|
|
||||||
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
|
val = bfd_get_8 (input_bfd, contents + roff - 3);
|
||||||
BFD_ASSERT (type == 0x8b || type == 0x03);
|
type = bfd_get_8 (input_bfd, contents + roff - 2);
|
||||||
reg = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
|
reg = bfd_get_8 (input_bfd, contents + roff - 1);
|
||||||
BFD_ASSERT ((reg & 0xc7) == 5);
|
|
||||||
reg >>= 3;
|
reg >>= 3;
|
||||||
BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
|
|
||||||
if (type == 0x8b)
|
if (type == 0x8b)
|
||||||
{
|
{
|
||||||
/* movq */
|
/* movq */
|
||||||
if (val == 0x4c)
|
if (val == 0x4c)
|
||||||
bfd_put_8 (output_bfd, 0x49,
|
bfd_put_8 (output_bfd, 0x49,
|
||||||
contents + rel->r_offset - 3);
|
contents + roff - 3);
|
||||||
bfd_put_8 (output_bfd, 0xc7,
|
bfd_put_8 (output_bfd, 0xc7,
|
||||||
contents + rel->r_offset - 2);
|
contents + roff - 2);
|
||||||
bfd_put_8 (output_bfd, 0xc0 | reg,
|
bfd_put_8 (output_bfd, 0xc0 | reg,
|
||||||
contents + rel->r_offset - 1);
|
contents + roff - 1);
|
||||||
}
|
}
|
||||||
else if (reg == 4)
|
else if (reg == 4)
|
||||||
{
|
{
|
||||||
|
@ -2667,27 +2855,29 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
special */
|
special */
|
||||||
if (val == 0x4c)
|
if (val == 0x4c)
|
||||||
bfd_put_8 (output_bfd, 0x49,
|
bfd_put_8 (output_bfd, 0x49,
|
||||||
contents + rel->r_offset - 3);
|
contents + roff - 3);
|
||||||
bfd_put_8 (output_bfd, 0x81,
|
bfd_put_8 (output_bfd, 0x81,
|
||||||
contents + rel->r_offset - 2);
|
contents + roff - 2);
|
||||||
bfd_put_8 (output_bfd, 0xc0 | reg,
|
bfd_put_8 (output_bfd, 0xc0 | reg,
|
||||||
contents + rel->r_offset - 1);
|
contents + roff - 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* addq -> leaq */
|
/* addq -> leaq */
|
||||||
if (val == 0x4c)
|
if (val == 0x4c)
|
||||||
bfd_put_8 (output_bfd, 0x4d,
|
bfd_put_8 (output_bfd, 0x4d,
|
||||||
contents + rel->r_offset - 3);
|
contents + roff - 3);
|
||||||
bfd_put_8 (output_bfd, 0x8d,
|
bfd_put_8 (output_bfd, 0x8d,
|
||||||
contents + rel->r_offset - 2);
|
contents + roff - 2);
|
||||||
bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
|
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),
|
bfd_put_32 (output_bfd, tpoff (info, relocation),
|
||||||
contents + rel->r_offset);
|
contents + roff);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
BFD_ASSERT (FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (htab->sgot == NULL)
|
if (htab->sgot == NULL)
|
||||||
|
@ -2814,42 +3004,30 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
+ htab->sgot->output_offset + off;
|
+ htab->sgot->output_offset + off;
|
||||||
unresolved_reloc = FALSE;
|
unresolved_reloc = FALSE;
|
||||||
}
|
}
|
||||||
else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
|
else
|
||||||
{
|
{
|
||||||
unsigned int i;
|
bfd_vma roff = rel->r_offset;
|
||||||
static unsigned char tlsgd[8]
|
|
||||||
= { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
|
|
||||||
|
|
||||||
|
if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
|
||||||
|
{
|
||||||
/* GD->IE transition.
|
/* GD->IE transition.
|
||||||
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
|
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
|
||||||
.word 0x6666; rex64; call __tls_get_addr@plt
|
.word 0x6666; rex64; call __tls_get_addr@plt
|
||||||
Change it into:
|
Change it into:
|
||||||
movq %fs:0, %rax
|
movq %fs:0, %rax
|
||||||
addq foo@gottpoff(%rip), %rax */
|
addq foo@gottpoff(%rip), %rax */
|
||||||
BFD_ASSERT (rel->r_offset >= 4);
|
memcpy (contents + roff - 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",
|
"\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
|
||||||
16);
|
16);
|
||||||
|
|
||||||
relocation = (htab->sgot->output_section->vma
|
relocation = (htab->sgot->output_section->vma
|
||||||
+ htab->sgot->output_offset + off
|
+ htab->sgot->output_offset + off
|
||||||
- rel->r_offset
|
- roff
|
||||||
- input_section->output_section->vma
|
- input_section->output_section->vma
|
||||||
- input_section->output_offset
|
- input_section->output_offset
|
||||||
- 12);
|
- 12);
|
||||||
bfd_put_32 (output_bfd, relocation,
|
bfd_put_32 (output_bfd, relocation,
|
||||||
contents + rel->r_offset + 8);
|
contents + roff + 8);
|
||||||
/* Skip R_X86_64_PLT32. */
|
/* Skip R_X86_64_PLT32. */
|
||||||
rel++;
|
rel++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -2861,28 +3039,17 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
leaq x@tlsdesc(%rip), %rax
|
leaq x@tlsdesc(%rip), %rax
|
||||||
|
|
||||||
Change it to:
|
Change it to:
|
||||||
movq x@gottpoff(%rip), %rax # before nop; nop
|
movq x@gottpoff(%rip), %rax # before xchg %ax,%ax
|
||||||
|
*/
|
||||||
Registers other than %rax may be set up here. */
|
|
||||||
|
|
||||||
unsigned int val, type, type2;
|
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);
|
type = bfd_get_8 (input_bfd, contents + roff - 3);
|
||||||
BFD_ASSERT ((type & 0xfb) == 0x48);
|
|
||||||
type2 = bfd_get_8 (input_bfd, contents + roff - 2);
|
type2 = bfd_get_8 (input_bfd, contents + roff - 2);
|
||||||
BFD_ASSERT (type2 == 0x8d);
|
|
||||||
val = bfd_get_8 (input_bfd, contents + roff - 1);
|
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. */
|
/* Now modify the instruction as appropriate. To
|
||||||
/* To turn a leaq into a movq in the form we use it, it
|
turn a leaq into a movq in the form we use it, it
|
||||||
suffices to change the second byte from 0x8d to
|
suffices to change the second byte from 0x8d to
|
||||||
0x8b. */
|
0x8b. */
|
||||||
bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
|
bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
|
||||||
|
@ -2904,61 +3071,37 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||||
call *(%rax)
|
call *(%rax)
|
||||||
|
|
||||||
Change it to:
|
Change it to:
|
||||||
nop; nop. */
|
xchg %ax,%ax. */
|
||||||
|
|
||||||
unsigned int val, type;
|
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);
|
type = bfd_get_8 (input_bfd, contents + roff);
|
||||||
BFD_ASSERT (type == 0xff);
|
|
||||||
val = bfd_get_8 (input_bfd, contents + roff + 1);
|
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, 0x66, contents + roff);
|
||||||
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
|
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
BFD_ASSERT (FALSE);
|
BFD_ASSERT (FALSE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_X86_64_TLSLD:
|
case R_X86_64_TLSLD:
|
||||||
if (! info->shared)
|
if (! elf64_x86_64_tls_transition (info, input_bfd,
|
||||||
{
|
input_section, contents,
|
||||||
unsigned long tls_r_symndx;
|
symtab_hdr, sym_hashes,
|
||||||
struct elf_link_hash_entry *tls_h;
|
&r_type, GOT_UNKNOWN,
|
||||||
|
rel, relend, h))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (r_type != R_X86_64_TLSLD)
|
||||||
|
{
|
||||||
/* LD->LE transition:
|
/* LD->LE transition:
|
||||||
Ensure it is:
|
|
||||||
leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
|
leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
|
||||||
We change it into:
|
We change it into:
|
||||||
.word 0x6666; .byte 0x66; movl %fs:0, %rax. */
|
.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)
|
BFD_ASSERT (r_type == R_X86_64_TPOFF32);
|
||||||
== 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);
|
|
||||||
memcpy (contents + rel->r_offset - 3,
|
memcpy (contents + rel->r_offset - 3,
|
||||||
"\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
|
"\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
|
||||||
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
|
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
|
||||||
|
|
|
@ -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>
|
2007-08-17 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
* ld-sparc/tlssunnopic32.dd: Fix up #target.
|
* ld-sparc/tlssunnopic32.dd: Fix up #target.
|
||||||
|
|
|
@ -222,235 +222,243 @@ Disassembly of section .text:
|
||||||
8049170: 90[ ]+nop *
|
8049170: 90[ ]+nop *
|
||||||
8049171: 90[ ]+nop *
|
8049171: 90[ ]+nop *
|
||||||
8049172: 90[ ]+nop *
|
8049172: 90[ ]+nop *
|
||||||
8049173: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
|
# GD -> IE because variable is not defined in executable
|
||||||
8049176: c9[ ]+leave *
|
8049173: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
8049177: c3[ ]+ret *
|
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>:
|
0+8049188 <_start>:
|
||||||
8049178: 55[ ]+push %ebp
|
8049188: 55[ ]+push %ebp
|
||||||
8049179: 89 e5[ ]+mov %esp,%ebp
|
8049189: 89 e5[ ]+mov %esp,%ebp
|
||||||
804917b: e8 00 00 00 00[ ]+call 8049180 <_start\+0x8>
|
804918b: e8 00 00 00 00[ ]+call 8049190 <_start\+0x8>
|
||||||
8049180: 59[ ]+pop %ecx
|
8049190: 59[ ]+pop %ecx
|
||||||
8049181: 81 c1 a4 0f 00 00[ ]+add \$0xfa4,%ecx
|
8049191: 81 c1 94 0f 00 00[ ]+add \$0xf94,%ecx
|
||||||
8049187: 90[ ]+nop *
|
8049197: 90[ ]+nop *
|
||||||
8049188: 90[ ]+nop *
|
8049198: 90[ ]+nop *
|
||||||
8049189: 90[ ]+nop *
|
8049199: 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
|
|
||||||
804919a: 90[ ]+nop *
|
804919a: 90[ ]+nop *
|
||||||
804919b: 90[ ]+nop *
|
# @gottpoff IE against global var
|
||||||
804919c: 90[ ]+nop *
|
804919b: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
804919d: 90[ ]+nop *
|
80491a2: 90[ ]+nop *
|
||||||
# @indntpoff IE against global var
|
80491a3: 90[ ]+nop *
|
||||||
804919e: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
80491a4: 2b 91 f4 ff ff ff[ ]+sub -0xc\(%ecx\),%edx
|
||||||
80491a4: 90[ ]+nop *
|
# ->R_386_TLS_TPOFF32 sG6
|
||||||
80491a5: 90[ ]+nop *
|
80491aa: 90[ ]+nop *
|
||||||
80491a6: 03 05 08 a1 04 08[ ]+add 0x804a108,%eax
|
80491ab: 90[ ]+nop *
|
||||||
# ->R_386_TLS_TPOFF sG7
|
|
||||||
80491ac: 90[ ]+nop *
|
80491ac: 90[ ]+nop *
|
||||||
80491ad: 90[ ]+nop *
|
80491ad: 90[ ]+nop *
|
||||||
80491ae: 90[ ]+nop *
|
# @indntpoff IE against global var
|
||||||
80491af: 90[ ]+nop *
|
80491ae: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
# @indntpoff direct %gs access IE against global var
|
80491b4: 90[ ]+nop *
|
||||||
80491b0: 8b 15 20 a1 04 08[ ]+mov 0x804a120,%edx
|
80491b5: 90[ ]+nop *
|
||||||
# ->R_386_TLS_TPOFF sG8
|
80491b6: 03 05 08 a1 04 08[ ]+add 0x804a108,%eax
|
||||||
80491b6: 90[ ]+nop *
|
# ->R_386_TLS_TPOFF sG7
|
||||||
80491b7: 90[ ]+nop *
|
|
||||||
80491b8: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
|
||||||
80491bb: 90[ ]+nop *
|
|
||||||
80491bc: 90[ ]+nop *
|
80491bc: 90[ ]+nop *
|
||||||
80491bd: 90[ ]+nop *
|
80491bd: 90[ ]+nop *
|
||||||
80491be: 90[ ]+nop *
|
80491be: 90[ ]+nop *
|
||||||
# @gottpoff IE -> LE against global var defined in exec
|
80491bf: 90[ ]+nop *
|
||||||
80491bf: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
# @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 *
|
80491c6: 90[ ]+nop *
|
||||||
80491c7: 90[ ]+nop *
|
80491c7: 90[ ]+nop *
|
||||||
80491c8: 81 ea 8c 0f 00 00[ ]+sub \$0xf8c,%edx
|
80491c8: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
||||||
# bg6
|
80491cb: 90[ ]+nop *
|
||||||
|
80491cc: 90[ ]+nop *
|
||||||
|
80491cd: 90[ ]+nop *
|
||||||
80491ce: 90[ ]+nop *
|
80491ce: 90[ ]+nop *
|
||||||
80491cf: 90[ ]+nop *
|
# @gottpoff IE -> LE against global var defined in exec
|
||||||
80491d0: 90[ ]+nop *
|
80491cf: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
80491d1: 90[ ]+nop *
|
80491d6: 90[ ]+nop *
|
||||||
# @indntpoff IE -> LE against global var defined in exec
|
80491d7: 90[ ]+nop *
|
||||||
80491d2: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
80491d8: 81 ea 8c 0f 00 00[ ]+sub \$0xf8c,%edx
|
||||||
80491d8: 90[ ]+nop *
|
# bg6
|
||||||
80491d9: 90[ ]+nop *
|
80491de: 90[ ]+nop *
|
||||||
80491da: 81 c0 78 f0 ff ff[ ]+add \$0xfffff078,%eax
|
80491df: 90[ ]+nop *
|
||||||
# bg7
|
|
||||||
80491e0: 90[ ]+nop *
|
80491e0: 90[ ]+nop *
|
||||||
80491e1: 90[ ]+nop *
|
80491e1: 90[ ]+nop *
|
||||||
80491e2: 90[ ]+nop *
|
# @indntpoff IE -> LE against global var defined in exec
|
||||||
80491e3: 90[ ]+nop *
|
80491e2: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
# @indntpoff direct %gs access IE -> LE against global var defined
|
80491e8: 90[ ]+nop *
|
||||||
# in exec
|
80491e9: 90[ ]+nop *
|
||||||
80491e4: c7 c2 7c f0 ff ff[ ]+mov \$0xfffff07c,%edx
|
80491ea: 81 c0 78 f0 ff ff[ ]+add \$0xfffff078,%eax
|
||||||
# bg8
|
# bg7
|
||||||
80491ea: 90[ ]+nop *
|
|
||||||
80491eb: 90[ ]+nop *
|
|
||||||
80491ec: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
|
||||||
80491ef: 90[ ]+nop *
|
|
||||||
80491f0: 90[ ]+nop *
|
80491f0: 90[ ]+nop *
|
||||||
80491f1: 90[ ]+nop *
|
80491f1: 90[ ]+nop *
|
||||||
80491f2: 90[ ]+nop *
|
80491f2: 90[ ]+nop *
|
||||||
# @gottpoff IE -> LE against local var
|
80491f3: 90[ ]+nop *
|
||||||
80491f3: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
# @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 *
|
80491fa: 90[ ]+nop *
|
||||||
80491fb: 90[ ]+nop *
|
80491fb: 90[ ]+nop *
|
||||||
80491fc: 81 ea 6c 0f 00 00[ ]+sub \$0xf6c,%edx
|
80491fc: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
||||||
# bl6
|
80491ff: 90[ ]+nop *
|
||||||
|
8049200: 90[ ]+nop *
|
||||||
|
8049201: 90[ ]+nop *
|
||||||
8049202: 90[ ]+nop *
|
8049202: 90[ ]+nop *
|
||||||
8049203: 90[ ]+nop *
|
# @gottpoff IE -> LE against local var
|
||||||
8049204: 90[ ]+nop *
|
8049203: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
8049205: 90[ ]+nop *
|
804920a: 90[ ]+nop *
|
||||||
# @indntpoff IE -> LE against local var
|
804920b: 90[ ]+nop *
|
||||||
8049206: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
804920c: 81 ea 6c 0f 00 00[ ]+sub \$0xf6c,%edx
|
||||||
804920c: 90[ ]+nop *
|
# bl6
|
||||||
804920d: 90[ ]+nop *
|
8049212: 90[ ]+nop *
|
||||||
804920e: 81 c0 98 f0 ff ff[ ]+add \$0xfffff098,%eax
|
8049213: 90[ ]+nop *
|
||||||
# bl7
|
|
||||||
8049214: 90[ ]+nop *
|
8049214: 90[ ]+nop *
|
||||||
8049215: 90[ ]+nop *
|
8049215: 90[ ]+nop *
|
||||||
8049216: 90[ ]+nop *
|
# @indntpoff IE -> LE against local var
|
||||||
8049217: 90[ ]+nop *
|
8049216: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
# @indntpoff direct %gs access IE -> LE against local var
|
804921c: 90[ ]+nop *
|
||||||
8049218: c7 c2 9c f0 ff ff[ ]+mov \$0xfffff09c,%edx
|
804921d: 90[ ]+nop *
|
||||||
# bl8
|
804921e: 81 c0 98 f0 ff ff[ ]+add \$0xfffff098,%eax
|
||||||
804921e: 90[ ]+nop *
|
# bl7
|
||||||
804921f: 90[ ]+nop *
|
|
||||||
8049220: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
|
||||||
8049223: 90[ ]+nop *
|
|
||||||
8049224: 90[ ]+nop *
|
8049224: 90[ ]+nop *
|
||||||
8049225: 90[ ]+nop *
|
8049225: 90[ ]+nop *
|
||||||
8049226: 90[ ]+nop *
|
8049226: 90[ ]+nop *
|
||||||
# @gottpoff IE -> LE against hidden but not local var
|
8049227: 90[ ]+nop *
|
||||||
8049227: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
# @indntpoff direct %gs access IE -> LE against local var
|
||||||
|
8049228: c7 c2 9c f0 ff ff[ ]+mov \$0xfffff09c,%edx
|
||||||
|
# bl8
|
||||||
804922e: 90[ ]+nop *
|
804922e: 90[ ]+nop *
|
||||||
804922f: 90[ ]+nop *
|
804922f: 90[ ]+nop *
|
||||||
8049230: 81 ea ac 0f 00 00[ ]+sub \$0xfac,%edx
|
8049230: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
||||||
# sh6
|
8049233: 90[ ]+nop *
|
||||||
|
8049234: 90[ ]+nop *
|
||||||
|
8049235: 90[ ]+nop *
|
||||||
8049236: 90[ ]+nop *
|
8049236: 90[ ]+nop *
|
||||||
8049237: 90[ ]+nop *
|
# @gottpoff IE -> LE against hidden but not local var
|
||||||
8049238: 90[ ]+nop *
|
8049237: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
8049239: 90[ ]+nop *
|
804923e: 90[ ]+nop *
|
||||||
# @indntpoff IE -> LE against hidden but not local var
|
804923f: 90[ ]+nop *
|
||||||
804923a: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
8049240: 81 ea ac 0f 00 00[ ]+sub \$0xfac,%edx
|
||||||
8049240: 90[ ]+nop *
|
# sh6
|
||||||
8049241: 90[ ]+nop *
|
8049246: 90[ ]+nop *
|
||||||
8049242: 81 c0 58 f0 ff ff[ ]+add \$0xfffff058,%eax
|
8049247: 90[ ]+nop *
|
||||||
# sh7
|
|
||||||
8049248: 90[ ]+nop *
|
8049248: 90[ ]+nop *
|
||||||
8049249: 90[ ]+nop *
|
8049249: 90[ ]+nop *
|
||||||
804924a: 90[ ]+nop *
|
# @indntpoff IE -> LE against hidden but not local var
|
||||||
804924b: 90[ ]+nop *
|
804924a: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
# @indntpoff direct %gs access IE -> LE against hidden but not
|
8049250: 90[ ]+nop *
|
||||||
# local var
|
8049251: 90[ ]+nop *
|
||||||
804924c: c7 c2 5c f0 ff ff[ ]+mov \$0xfffff05c,%edx
|
8049252: 81 c0 58 f0 ff ff[ ]+add \$0xfffff058,%eax
|
||||||
# sh8
|
# sh7
|
||||||
8049252: 90[ ]+nop *
|
|
||||||
8049253: 90[ ]+nop *
|
|
||||||
8049254: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
|
||||||
8049257: 90[ ]+nop *
|
|
||||||
8049258: 90[ ]+nop *
|
8049258: 90[ ]+nop *
|
||||||
8049259: 90[ ]+nop *
|
8049259: 90[ ]+nop *
|
||||||
804925a: 90[ ]+nop *
|
804925a: 90[ ]+nop *
|
||||||
# LE @tpoff, global var defined in exec
|
804925b: 90[ ]+nop *
|
||||||
804925b: ba 00 10 00 00[ ]+mov \$0x1000,%edx
|
# @indntpoff direct %gs access IE -> LE against hidden but not
|
||||||
# sg1
|
# local var
|
||||||
8049260: 90[ ]+nop *
|
804925c: c7 c2 5c f0 ff ff[ ]+mov \$0xfffff05c,%edx
|
||||||
8049261: 90[ ]+nop *
|
# sh8
|
||||||
8049262: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
8049262: 90[ ]+nop *
|
||||||
|
8049263: 90[ ]+nop *
|
||||||
|
8049264: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
|
||||||
|
8049267: 90[ ]+nop *
|
||||||
8049268: 90[ ]+nop *
|
8049268: 90[ ]+nop *
|
||||||
8049269: 90[ ]+nop *
|
8049269: 90[ ]+nop *
|
||||||
804926a: 29 d0[ ]+sub %edx,%eax
|
804926a: 90[ ]+nop *
|
||||||
804926c: 90[ ]+nop *
|
# LE @tpoff, global var defined in exec
|
||||||
804926d: 90[ ]+nop *
|
804926b: ba 00 10 00 00[ ]+mov \$0x1000,%edx
|
||||||
804926e: 90[ ]+nop *
|
# sg1
|
||||||
804926f: 90[ ]+nop *
|
8049270: 90[ ]+nop *
|
||||||
# LE @tpoff, local var
|
8049271: 90[ ]+nop *
|
||||||
8049270: b8 7f 0f 00 00[ ]+mov \$0xf7f,%eax
|
8049272: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
# bl1+1
|
8049278: 90[ ]+nop *
|
||||||
8049275: 90[ ]+nop *
|
8049279: 90[ ]+nop *
|
||||||
8049276: 90[ ]+nop *
|
804927a: 29 d0[ ]+sub %edx,%eax
|
||||||
8049277: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
804927c: 90[ ]+nop *
|
||||||
|
804927d: 90[ ]+nop *
|
||||||
804927e: 90[ ]+nop *
|
804927e: 90[ ]+nop *
|
||||||
804927f: 90[ ]+nop *
|
804927f: 90[ ]+nop *
|
||||||
8049280: 29 c2[ ]+sub %eax,%edx
|
# LE @tpoff, local var
|
||||||
8049282: 90[ ]+nop *
|
8049280: b8 7f 0f 00 00[ ]+mov \$0xf7f,%eax
|
||||||
8049283: 90[ ]+nop *
|
# bl1+1
|
||||||
8049284: 90[ ]+nop *
|
|
||||||
8049285: 90[ ]+nop *
|
8049285: 90[ ]+nop *
|
||||||
# LE @tpoff, hidden var defined in exec
|
8049286: 90[ ]+nop *
|
||||||
8049286: b8 bd 0f 00 00[ ]+mov \$0xfbd,%eax
|
8049287: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
# sh1+3
|
804928e: 90[ ]+nop *
|
||||||
804928b: 90[ ]+nop *
|
804928f: 90[ ]+nop *
|
||||||
804928c: 90[ ]+nop *
|
8049290: 29 c2[ ]+sub %eax,%edx
|
||||||
804928d: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
8049292: 90[ ]+nop *
|
||||||
|
8049293: 90[ ]+nop *
|
||||||
8049294: 90[ ]+nop *
|
8049294: 90[ ]+nop *
|
||||||
8049295: 90[ ]+nop *
|
8049295: 90[ ]+nop *
|
||||||
8049296: 29 c2[ ]+sub %eax,%edx
|
# LE @tpoff, hidden var defined in exec
|
||||||
8049298: 90[ ]+nop *
|
8049296: b8 bd 0f 00 00[ ]+mov \$0xfbd,%eax
|
||||||
8049299: 90[ ]+nop *
|
# sh1+3
|
||||||
804929a: 90[ ]+nop *
|
|
||||||
804929b: 90[ ]+nop *
|
804929b: 90[ ]+nop *
|
||||||
# LE @ntpoff, global var defined in exec
|
804929c: 90[ ]+nop *
|
||||||
804929c: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
804929d: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
80492a2: 90[ ]+nop *
|
80492a4: 90[ ]+nop *
|
||||||
80492a3: 90[ ]+nop *
|
80492a5: 90[ ]+nop *
|
||||||
80492a4: 8d 90 04 f0 ff ff[ ]+lea -0xffc\(%eax\),%edx
|
80492a6: 29 c2[ ]+sub %eax,%edx
|
||||||
# sg2
|
80492a8: 90[ ]+nop *
|
||||||
|
80492a9: 90[ ]+nop *
|
||||||
80492aa: 90[ ]+nop *
|
80492aa: 90[ ]+nop *
|
||||||
80492ab: 90[ ]+nop *
|
80492ab: 90[ ]+nop *
|
||||||
80492ac: 90[ ]+nop *
|
# LE @ntpoff, global var defined in exec
|
||||||
80492ad: 90[ ]+nop *
|
80492ac: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
|
||||||
# LE @ntpoff, local var, non-canonical sequence
|
80492b2: 90[ ]+nop *
|
||||||
80492ae: b8 86 f0 ff ff[ ]+mov \$0xfffff086,%eax
|
|
||||||
# bl2+2
|
|
||||||
80492b3: 90[ ]+nop *
|
80492b3: 90[ ]+nop *
|
||||||
80492b4: 90[ ]+nop *
|
80492b4: 8d 90 04 f0 ff ff[ ]+lea -0xffc\(%eax\),%edx
|
||||||
80492b5: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
# sg2
|
||||||
|
80492ba: 90[ ]+nop *
|
||||||
|
80492bb: 90[ ]+nop *
|
||||||
80492bc: 90[ ]+nop *
|
80492bc: 90[ ]+nop *
|
||||||
80492bd: 90[ ]+nop *
|
80492bd: 90[ ]+nop *
|
||||||
80492be: 01 c2[ ]+add %eax,%edx
|
# LE @ntpoff, local var, non-canonical sequence
|
||||||
80492c0: 90[ ]+nop *
|
80492be: b8 86 f0 ff ff[ ]+mov \$0xfffff086,%eax
|
||||||
80492c1: 90[ ]+nop *
|
# bl2+2
|
||||||
80492c2: 90[ ]+nop *
|
|
||||||
80492c3: 90[ ]+nop *
|
80492c3: 90[ ]+nop *
|
||||||
# LE @ntpoff, hidden var defined in exec, non-canonical sequence
|
80492c4: 90[ ]+nop *
|
||||||
80492c4: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
80492c5: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
80492cb: 90[ ]+nop *
|
|
||||||
80492cc: 90[ ]+nop *
|
80492cc: 90[ ]+nop *
|
||||||
80492cd: 81 c2 45 f0 ff ff[ ]+add \$0xfffff045,%edx
|
80492cd: 90[ ]+nop *
|
||||||
# sh2+1
|
80492ce: 01 c2[ ]+add %eax,%edx
|
||||||
|
80492d0: 90[ ]+nop *
|
||||||
|
80492d1: 90[ ]+nop *
|
||||||
|
80492d2: 90[ ]+nop *
|
||||||
80492d3: 90[ ]+nop *
|
80492d3: 90[ ]+nop *
|
||||||
80492d4: 90[ ]+nop *
|
# LE @ntpoff, hidden var defined in exec, non-canonical sequence
|
||||||
80492d5: 90[ ]+nop *
|
80492d4: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
|
||||||
80492d6: 90[ ]+nop *
|
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
|
# 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
|
# sg3
|
||||||
80492dd: 90[ ]+nop *
|
80492ed: 90[ ]+nop *
|
||||||
80492de: 90[ ]+nop *
|
80492ee: 90[ ]+nop *
|
||||||
80492df: 90[ ]+nop *
|
80492ef: 90[ ]+nop *
|
||||||
80492e0: 90[ ]+nop *
|
80492f0: 90[ ]+nop *
|
||||||
# LE @ntpoff, local var
|
# 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
|
# bl3+3
|
||||||
80492e8: 90[ ]+nop *
|
80492f8: 90[ ]+nop *
|
||||||
80492e9: 90[ ]+nop *
|
80492f9: 90[ ]+nop *
|
||||||
80492ea: 90[ ]+nop *
|
80492fa: 90[ ]+nop *
|
||||||
80492eb: 90[ ]+nop *
|
80492fb: 90[ ]+nop *
|
||||||
# LE @ntpoff, hidden var defined in exec
|
# 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
|
# sh3+1
|
||||||
80492f3: 90[ ]+nop *
|
8049303: 90[ ]+nop *
|
||||||
80492f4: 90[ ]+nop *
|
8049304: 90[ ]+nop *
|
||||||
80492f5: 90[ ]+nop *
|
8049305: 90[ ]+nop *
|
||||||
80492f6: 90[ ]+nop *
|
8049306: 90[ ]+nop *
|
||||||
80492f7: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
|
8049307: 8b 5d fc[ ]+mov -0x4\(%ebp\),%ebx
|
||||||
80492fa: c9[ ]+leave *
|
804930a: c9[ ]+leave *
|
||||||
80492fb: c3[ ]+ret *
|
804930b: c3[ ]+ret *
|
||||||
|
|
|
@ -32,7 +32,7 @@ Key to Flags:
|
||||||
.*
|
.*
|
||||||
|
|
||||||
Elf file type is EXEC \(Executable file\)
|
Elf file type is EXEC \(Executable file\)
|
||||||
Entry point 0x8049178
|
Entry point 0x8049188
|
||||||
There are 6 program headers, starting at offset [0-9]+
|
There are 6 program headers, starting at offset [0-9]+
|
||||||
|
|
||||||
Program Headers:
|
Program Headers:
|
||||||
|
@ -137,7 +137,7 @@ Symbol table '.symtab' contains 70 entries:
|
||||||
+[0-9]+: 00000058 +0 TLS +GLOBAL HIDDEN +9 sh7
|
+[0-9]+: 00000058 +0 TLS +GLOBAL HIDDEN +9 sh7
|
||||||
+[0-9]+: 0000005c +0 TLS +GLOBAL HIDDEN +9 sh8
|
+[0-9]+: 0000005c +0 TLS +GLOBAL HIDDEN +9 sh8
|
||||||
+[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +9 sg1
|
+[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]+: 0000004c +0 TLS +GLOBAL HIDDEN +9 sh4
|
||||||
+[0-9]+: 00000078 +0 TLS +GLOBAL DEFAULT +10 bg7
|
+[0-9]+: 00000078 +0 TLS +GLOBAL DEFAULT +10 bg7
|
||||||
+[0-9]+: 00000050 +0 TLS +GLOBAL HIDDEN +9 sh5
|
+[0-9]+: 00000050 +0 TLS +GLOBAL HIDDEN +9 sh5
|
||||||
|
|
|
@ -162,6 +162,11 @@ fn2:
|
||||||
movl %gs:(%edx), %edx
|
movl %gs:(%edx), %edx
|
||||||
nop;nop;nop;nop
|
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
|
movl -4(%ebp), %ebx
|
||||||
leave
|
leave
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -11,4 +11,6 @@ Disassembly of section .text:
|
||||||
[a-f0-9]+ <_start>:
|
[a-f0-9]+ <_start>:
|
||||||
[ ]*[a-f0-9]+: 65 a1 00 00 00 00 mov %gs:0x0,%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
|
[ ]*[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
|
#pass
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
_start:
|
_start:
|
||||||
leal foo@TLSGD(,%ebx,1), %eax
|
leal foo@TLSGD(,%ebx,1), %eax
|
||||||
call ___tls_get_addr
|
call ___tls_get_addr
|
||||||
|
leal foo@TLSGD(%ebx), %eax
|
||||||
|
call ___tls_get_addr
|
||||||
|
nop
|
||||||
.globl foo
|
.globl foo
|
||||||
.section .tdata,"awT",@progbits
|
.section .tdata,"awT",@progbits
|
||||||
.align 4
|
.align 4
|
||||||
|
|
Loading…
Reference in New Issue