aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-x86-64.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2011-03-12 14:38:31 +0000
committerH.J. Lu <hjl.tools@gmail.com>2011-03-12 14:38:31 +0000
commit52bc799a91cd19a56cb59a9ecd29c0f63153c302 (patch)
tree9758117f87054ed61dcb91856653af377acef75d /bfd/elf64-x86-64.c
parentdbc6760729c24524100f30592d0c0df31b2b41c8 (diff)
downloadgdb-52bc799a91cd19a56cb59a9ecd29c0f63153c302.zip
gdb-52bc799a91cd19a56cb59a9ecd29c0f63153c302.tar.gz
gdb-52bc799a91cd19a56cb59a9ecd29c0f63153c302.tar.bz2
Support TLS x32 GD->IE, GD->LE and LD->LE transitions.
bfd/ 2011-03-12 H.J. Lu <hongjiu.lu@intel.com> * elf64-x86-64.c (elf_x86_64_check_tls_transition): Supprt TLS x32 GD->IE and GD->LE transitions. (elf_x86_64_relocate_section): Supprt TLS x32 GD->IE, GD->LE and LD->LE transitions. ld/testsuite/ 2011-03-12 H.J. Lu <hongjiu.lu@intel.com> * ld-x86-64/tlsgd4.dd: New. * ld-x86-64/tlsgd4.s: Likewise. * ld-x86-64/tlsgd5.dd: Likewise. * ld-x86-64/tlsgd5a.s: Likewise. * ld-x86-64/tlsgd5b.s: Likewise. * ld-x86-64/tlsgd6.dd: Likewise. * ld-x86-64/tlsgd6a.s: Likewise. * ld-x86-64/tlsgd6b.s: Likewise. * ld-x86-64/tlsld2.dd: Likewise. * ld-x86-64/tlsld2.s: Likewise. * ld-x86-64/x86-64.exp (x86_64tests): Add tlsgd4, libtlsgd5.so, tlsgd5, libtlsgd6.so, tlsgd6 and tlsld2.
Diffstat (limited to 'bfd/elf64-x86-64.c')
-rw-r--r--bfd/elf64-x86-64.c84
1 files changed, 64 insertions, 20 deletions
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index c26c40b..927b3ed 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -865,18 +865,34 @@ elf_x86_64_check_tls_transition (bfd *abfd,
if (r_type == R_X86_64_TLSGD)
{
- /* Check transition from GD access model. Only
+ /* Check transition from GD access model. For 64bit, only
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr
+ can transit to different access model. For 32bit, only
+ 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
+ static x86_64_opcode32 call = { { 0x66, 0x66, 0x48, 0xe8 } };
+ if ((offset + 12) > sec->size
|| bfd_get_32 (abfd, contents + offset + 4) != call.i)
return FALSE;
+
+ if (ABI_64_P (abfd))
+ {
+ static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } };
+ if (offset < 4
+ || bfd_get_32 (abfd, contents + offset - 4) != leaq.i)
+ return FALSE;
+ }
+ else
+ {
+ static x86_64_opcode16 lea = { { 0x8d, 0x3d } };
+ if (offset < 3
+ || bfd_get_8 (abfd, contents + offset - 3) != 0x48
+ || bfd_get_16 (abfd, contents + offset - 2) != lea.i)
+ return FALSE;
+ }
}
else
{
@@ -3434,15 +3450,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
{
- /* GD->LE transition.
+ /* GD->LE transition. For 64bit, change
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr
- Change it into:
+ into:
movq %fs:0, %rax
+ leaq foo@tpoff(%rax), %rax
+ For 32bit, change
+ leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr
+ into:
+ movl %fs:0, %eax
leaq foo@tpoff(%rax), %rax */
- memcpy (contents + roff - 4,
- "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
- 16);
+ if (ABI_64_P (output_bfd))
+ memcpy (contents + roff - 4,
+ "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+ 16);
+ else
+ memcpy (contents + roff - 3,
+ "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+ 15);
bfd_put_32 (output_bfd,
elf_x86_64_tpoff (info, relocation),
contents + roff + 8);
@@ -3670,15 +3697,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
{
- /* GD->IE transition.
+ /* GD->IE transition. For 64bit, change
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr@plt
- Change it into:
+ into:
movq %fs:0, %rax
+ addq foo@gottpoff(%rip), %rax
+ For 32bit, change
+ leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr@plt
+ into:
+ movl %fs:0, %eax
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);
+ if (ABI_64_P (output_bfd))
+ memcpy (contents + roff - 4,
+ "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+ 16);
+ else
+ memcpy (contents + roff - 3,
+ "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+ 15);
relocation = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset + off
@@ -3747,12 +3785,18 @@ elf_x86_64_relocate_section (bfd *output_bfd,
{
/* LD->LE transition:
leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
- We change it into:
- .word 0x6666; .byte 0x66; movl %fs:0, %rax. */
+ For 64bit, we change it into:
+ .word 0x6666; .byte 0x66; movq %fs:0, %rax.
+ For 32bit, we change it into:
+ nopl 0x0(%rax); movl %fs:0, %eax. */
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);
+ if (ABI_64_P (output_bfd))
+ memcpy (contents + rel->r_offset - 3,
+ "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+ else
+ memcpy (contents + rel->r_offset - 3,
+ "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;