gold: x86-64: Fix TLSDESC relaxation for x32

X32 TLSDESC sequences can be:

40 8d 05 00 00 00 00	rex lea	foo@TLSDESC(%rip), %reg
...
67 ff 10		call	*foo@TLSCALL(%eax)

or the same sequence as LP64:

48 8d 05 00 00 00 00	lea	foo@TLSDESC(%rip), %reg
...
ff 10			call	*foo@TLSCALL(%rax)

We need to support both sequences for x32.  For both GDesc -> IE/LE
transitions,

67 ff 10		call	*foo@TLSCALL(%eax)

should relaxed to

0f 1f 00		nopl	(%rax)

For GDesc -> LE transition,

40 8d 05 00 00 00 00	rex lea	foo@TLSDESC(%rip), %reg

should relaxed to

40 c7 c0 fc ff ff ff	rex movl $foo@tpoff, %reg

For GDesc -> IE transition,

40 8d 05 00 00 00 00	rex lea	foo@TLSDESC(%rip), %reg

should relaxed to

40 8b 05 00 00 00 00	rex movl foo@gottpoff(%rip), %eax

	PR gold/25426
	* x86_64.cc (Target_x86_64<size>::Relocate::tls_desc_gd_to_ie):
	For x32, relax "rex leal foo@tlsdesc(%rip), %reg" to
	"rex movl foo@gottpoff(%rip), %eax" and relax ""call *(%eax)"
	to "nopl (%rax)".
	(Target_x86_64<size>::Relocate::tls_desc_gd_to_le): For x32,
	relax "rex leal foo@tlsdesc(%rip), %reg" to
	"rex movl foo@tpoff, %eax" and relax "call *foo@tlscall(%eax)"
	to "nopl (%rax)".
	* testsuite/Makefile.am (tls_test_gnu2.o): Depend on
	gcctestdir/as.
	(tls_test_file2_gnu2.o): Likewise.
	(tls_test_c_gnu2.o): Likewise.
	* testsuite/Makefile.in: Regenerated.
This commit is contained in:
H.J. Lu 2020-05-01 10:11:06 -07:00
parent 6d520e36de
commit ccf20d460f
4 changed files with 82 additions and 23 deletions

View File

@ -1,3 +1,20 @@
2020-05-01 H.J. Lu <hongjiu.lu@intel.com>
PR gold/25426
* x86_64.cc (Target_x86_64<size>::Relocate::tls_desc_gd_to_ie):
For x32, relax "rex leal foo@tlsdesc(%rip), %reg" to
"rex movl foo@gottpoff(%rip), %eax" and relax ""call *(%eax)"
to "nopl (%rax)".
(Target_x86_64<size>::Relocate::tls_desc_gd_to_le): For x32,
relax "rex leal foo@tlsdesc(%rip), %reg" to
"rex movl foo@tpoff, %eax" and relax "call *foo@tlscall(%eax)"
to "nopl (%rax)".
* testsuite/Makefile.am (tls_test_gnu2.o): Depend on
gcctestdir/as.
(tls_test_file2_gnu2.o): Likewise.
(tls_test_c_gnu2.o): Likewise.
* testsuite/Makefile.in: Regenerated.
2020-05-01 H.J. Lu <hongjiu.lu@intel.com>
PR gold/25473

View File

@ -1032,11 +1032,11 @@ if TLS_GNU2_DIALECT
check_PROGRAMS += tls_shared_gnu2_gd_to_ie_test
tls_test_gnu2.o: tls_test.cc
tls_test_gnu2.o: tls_test.cc gcctestdir/as
$(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
tls_test_file2_gnu2.o: tls_test_file2.cc
tls_test_file2_gnu2.o: tls_test_file2.cc gcctestdir/as
$(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
tls_test_c_gnu2.o: tls_test_c.c
tls_test_c_gnu2.o: tls_test_c.c gcctestdir/as
$(COMPILE) -c -fpic -mtls-dialect=gnu2 $(TLS_TEST_C_CFLAGS) -o $@ $<
tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
$(CXXLINK) -shared tls_test_file2_gnu2.o

View File

@ -8275,11 +8275,11 @@ uninstall-am:
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ tls_test_c_pic.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) $(THREADFLAGS) -pie tls_test_main_pie.o tls_test_pic.o tls_test_file2_pic.o tls_test_c_pic.o $(THREADLIBS)
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2.o: tls_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2.o: tls_test.cc gcctestdir/as
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_file2_gnu2.o: tls_test_file2.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_file2_gnu2.o: tls_test_file2.cc gcctestdir/as
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_c_gnu2.o: tls_test_c.c
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_c_gnu2.o: tls_test_c.c gcctestdir/as
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(COMPILE) -c -fpic -mtls-dialect=gnu2 $(TLS_TEST_C_CFLAGS) -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@ $(CXXLINK) -shared tls_test_file2_gnu2.o

View File

@ -5472,12 +5472,15 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
{
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
{
// leaq foo@tlsdesc(%rip), %rax
// ==> movq foo@gottpoff(%rip), %rax
// LP64: leaq foo@tlsdesc(%rip), %rax
// ==> movq foo@gottpoff(%rip), %rax
// X32: rex leal foo@tlsdesc(%rip), %eax
// ==> rex movl foo@gottpoff(%rip), %eax
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
((view[-3] & 0xfb) == 0x48
(((view[-3] & 0xfb) == 0x48
|| (size == 32 && (view[-3] & 0xfb) == 0x40))
&& view[-2] == 0x8d
&& (view[-1] & 0xc7) == 0x05));
view[-2] = 0x8b;
@ -5486,14 +5489,32 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
}
else
{
// call *foo@tlscall(%rax)
// ==> nop; nop
// LP64: call *foo@tlscall(%rax)
// ==> xchg %ax, %ax
// X32: call *foo@tlscall(%eax)
// ==> nopl (%rax)
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
int prefix = 0;
if (size == 32 && view[0] == 0x67)
{
tls::check_range(relinfo, relnum, rela.get_r_offset(),
view_size, 3);
prefix = 1;
}
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
view[0] == 0xff && view[1] == 0x10);
view[0] = 0x66;
view[1] = 0x90;
view[prefix] == 0xff && view[prefix + 1] == 0x10);
if (prefix)
{
view[0] = 0x0f;
view[1] = 0x1f;
view[2] = 0x00;
}
else
{
view[0] = 0x66;
view[1] = 0x90;
}
}
}
@ -5513,15 +5534,18 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le(
{
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
{
// leaq foo@tlsdesc(%rip), %rax
// ==> movq foo@tpoff, %rax
// LP64: leaq foo@tlsdesc(%rip), %rax
// ==> movq foo@tpoff, %rax
// X32: rex leal foo@tlsdesc(%rip), %eax
// ==> rex movl foo@tpoff, %eax
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
((view[-3] & 0xfb) == 0x48
(((view[-3] & 0xfb) == 0x48
|| (size == 32 && (view[-3] & 0xfb) == 0x40))
&& view[-2] == 0x8d
&& (view[-1] & 0xc7) == 0x05));
view[-3] = 0x48 | ((view[-3] >> 2) & 1);
view[-3] = (view[-3] & 0x48) | ((view[-3] >> 2) & 1);
view[-2] = 0xc7;
view[-1] = 0xc0 | ((view[-1] >> 3) & 7);
value -= tls_segment->memsz();
@ -5529,14 +5553,32 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le(
}
else
{
// call *foo@tlscall(%rax)
// ==> nop; nop
// LP64: call *foo@tlscall(%rax)
// ==> xchg %ax, %ax
// X32: call *foo@tlscall(%eax)
// ==> nopl (%rax)
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
int prefix = 0;
if (size == 32 && view[0] == 0x67)
{
tls::check_range(relinfo, relnum, rela.get_r_offset(),
view_size, 3);
prefix = 1;
}
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
view[0] == 0xff && view[1] == 0x10);
view[0] = 0x66;
view[1] = 0x90;
view[prefix] == 0xff && view[prefix + 1] == 0x10);
if (prefix)
{
view[0] = 0x0f;
view[1] = 0x1f;
view[2] = 0x00;
}
else
{
view[0] = 0x66;
view[1] = 0x90;
}
}
}