aboutsummaryrefslogtreecommitdiff
path: root/gold/x86_64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/x86_64.cc')
-rw-r--r--gold/x86_64.cc55
1 files changed, 45 insertions, 10 deletions
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 6c511e2..6aa489a 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -3505,6 +3505,7 @@ Target_x86_64<size>::Relocate::relocate(
if (this->skip_call_tls_get_addr_)
{
if ((r_type != elfcpp::R_X86_64_PLT32
+ && r_type != elfcpp::R_X86_64_GOTPCRELX
&& r_type != elfcpp::R_X86_64_PLT32_BND
&& r_type != elfcpp::R_X86_64_PC32_BND
&& r_type != elfcpp::R_X86_64_PC32)
@@ -4169,16 +4170,23 @@ Target_x86_64<size>::Relocate::tls_gd_to_ie(
{
// For SIZE == 64:
// .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
- // .word 0x6666; rex64; call __tls_get_addr
+ // .word 0x6666; rex64; call __tls_get_addr@PLT
+ // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x66; rex64; call *__tls_get_addr@GOTPCREL(%rip)
// ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
// For SIZE == 32:
// leaq foo@tlsgd(%rip),%rdi;
- // .word 0x6666; rex64; call __tls_get_addr
+ // .word 0x6666; rex64; call __tls_get_addr@PLT
+ // ==> movl %fs:0,%eax; addq x@gottpoff(%rip),%rax
+ // leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x66; rex64; call *__tls_get_addr@GOTPCREL(%rip)
// ==> movl %fs:0,%eax; addq x@gottpoff(%rip),%rax
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0
+ || memcmp(view + 4, "\x66\x48\xff", 3) == 0));
if (size == 64)
{
@@ -4225,16 +4233,23 @@ Target_x86_64<size>::Relocate::tls_gd_to_le(
{
// For SIZE == 64:
// .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
- // .word 0x6666; rex64; call __tls_get_addr
+ // .word 0x6666; rex64; call __tls_get_addr@PLT
+ // ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x66; rex64; call *__tls_get_addr@GOTPCREL(%rip)
// ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
// For SIZE == 32:
// leaq foo@tlsgd(%rip),%rdi;
- // .word 0x6666; rex64; call __tls_get_addr
+ // .word 0x6666; rex64; call __tls_get_addr@PLT
+ // ==> movl %fs:0,%eax; leaq x@tpoff(%rax),%rax
+ // leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x66; rex64; call *__tls_get_addr@GOTPCREL(%rip)
// ==> movl %fs:0,%eax; leaq x@tpoff(%rax),%rax
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0
+ || memcmp(view + 4, "\x66\x48\xff", 3) == 0));
if (size == 64)
{
@@ -4362,6 +4377,13 @@ Target_x86_64<size>::Relocate::tls_ld_to_le(
// For SIZE == 32:
// ... leq foo@dtpoff(%rax),%reg
// ==> nopl 0x0(%rax); movl %fs:0,%eax ... leaq x@tpoff(%rax),%rdx
+ // leaq foo@tlsld(%rip),%rdi; call *__tls_get_addr@GOTPCREL(%rip)
+ // For SIZE == 64:
+ // ... leq foo@dtpoff(%rax),%reg
+ // ==> .word 0x6666; .byte 0x6666; movq %fs:0,%rax ... leaq x@tpoff(%rax),%rdx
+ // For SIZE == 32:
+ // ... leq foo@dtpoff(%rax),%reg
+ // ==> nopw 0x0(%rax); movl %fs:0,%eax ... leaq x@tpoff(%rax),%rdx
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 9);
@@ -4369,12 +4391,25 @@ Target_x86_64<size>::Relocate::tls_ld_to_le(
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d);
- tls::check_tls(relinfo, relnum, rela.get_r_offset(), view[4] == 0xe8);
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ view[4] == 0xe8 || view[4] == 0xff);
- if (size == 64)
- memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12);
+ if (view[4] == 0xe8)
+ {
+ if (size == 64)
+ memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12);
+ else
+ memcpy(view - 3, "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0\0", 12);
+ }
else
- memcpy(view - 3, "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0\0", 12);
+ {
+ if (size == 64)
+ memcpy(view - 3, "\x66\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0",
+ 13);
+ else
+ memcpy(view - 3, "\x66\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0\0",
+ 13);
+ }
// The next reloc should be a PLT32 reloc against __tls_get_addr.
// We can skip it.