aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@gmail.com>2015-03-22 11:59:21 -0700
committerCary Coutant <ccoutant@gmail.com>2015-03-22 11:59:21 -0700
commit152f702439a34bf20b74f472695490edb42ad56f (patch)
tree0d3125aa06f15976457c1af5bc08c2077382a68b
parentbccffdfdf268a84533131d6e4d6208f9873892ee (diff)
downloadgdb-152f702439a34bf20b74f472695490edb42ad56f.zip
gdb-152f702439a34bf20b74f472695490edb42ad56f.tar.gz
gdb-152f702439a34bf20b74f472695490edb42ad56f.tar.bz2
Fix support for i386 TLS GD-to-IE optimization.
There are two cases to support, one with an SIB-form (6-byte) LEA, the other with a 5-byte LEA and a NOP after the call __tls_get_addr. Gold did not yet support the second case. This patch adds that support. gold/ PR gold/18106 * i386.cc (Target_i386::Relocate::tls_gd_to_ie): Fix support for non-SIB form of lea, with nop after the call.
-rw-r--r--gold/ChangeLog6
-rw-r--r--gold/i386.cc27
2 files changed, 14 insertions, 19 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 7d281a9..71887d3 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,9 @@
+2015-03-22 Cary Coutant <cary@google.com>
+
+ PR gold/18106
+ * i386.cc (Target_i386::Relocate::tls_gd_to_ie): Fix support for
+ non-SIB form of lea, with nop after the call.
+
2015-03-21 Cary Coutant <cary@google.com>
PR gold/14217
diff --git a/gold/i386.cc b/gold/i386.cc
index 24f4103..3bc3d94 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -3253,6 +3253,8 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
{
// leal foo(,%ebx,1),%eax; call ___tls_get_addr
// ==> movl %gs:0,%eax; addl foo@gotntpoff(%ebx),%eax
+ // leal foo(%ebx),%eax; call ___tls_get_addr; nop
+ // ==> movl %gs:0,%eax; addl foo@gotntpoff(%ebx),%eax
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 9);
@@ -3264,10 +3266,7 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
op2 == 0x8d || op2 == 0x04);
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8);
- int roff = 5;
-
- // FIXME: For now, support only the first (SIB) form.
- tls::check_tls(relinfo, relnum, rel.get_r_offset(), op2 == 0x04);
+ int roff;
if (op2 == 0x04)
{
@@ -3275,28 +3274,18 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[-3] == 0x8d);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
((op1 & 0xc7) == 0x05 && op1 != (4 << 3)));
- memcpy(view - 3, "\x65\xa1\0\0\0\0\x03\x83\0\0\0", 12);
+ roff = 5;
}
else
{
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 10);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
(op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
- if (rel.get_r_offset() + 9 < view_size
- && view[9] == 0x90)
- {
- // FIXME: This is not the right instruction sequence.
- // There is a trailing nop. Use the size byte subl.
- memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
- roff = 6;
- }
- else
- {
- // FIXME: This is not the right instruction sequence.
- // Use the five byte subl.
- memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
- }
+ tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[9] == 0x90);
+ roff = 6;
}
+ memcpy(view + roff - 8, "\x65\xa1\0\0\0\0\x03\x83\0\0\0", 12);
Relocate_functions<32, false>::rel32(view + roff, value);
// The next reloc should be a PLT32 reloc against __tls_get_addr.