Gold: Handle R_X86_64_CODE_4_GOTPC32_TLSDESC/R_X86_64_CODE_4_GOTTPOFF

Handle R_X86_64_CODE_4_GOTTPOFF and R_X86_64_CODE_4_GOTPC32_TLSDESC.
Convert

	add	name@gottpoff(%rip), %reg
	mov	name@gottpoff(%rip), %reg

to

	add	$name@tpoff, %reg
	mov	$name@tpoff, %reg

and

	lea	name@tlsdesc(%rip), %reg

to

	mov     $name@tpoff, %reg
	mov	name@gottpoff(%rip), %reg

if the instruction is encoded with the REX2 prefix when possible.

elfcpp/

	* x86_64.h (R_X86_64_CODE_4_GOTTPOFF): New.
	(R_X86_64_CODE_4_GOTPC32_TLSDESC): Likewise.

gold/

	* x86_64.cc (Target_x86_64::optimize_tls_reloc): Handle
	R_X86_64_CODE_4_GOTPC32_TLSDESC and R_X86_64_CODE_4_GOTTPOFF.
	(Target_x86_64::Scan::get_reference_flags): Likewise.
	(Target_x86_64::Scan::local): Likewise.
	(Target_x86_64::Scan::global): Likewise.
	(Target_x86_64::Relocate::relocate): Likewise.
	(Target_x86_64::Relocate::relocate_tls): Likewise.
	(Target_x86_64::Relocate::tls_desc_gd_to_ie): Handle
	R_X86_64_CODE_4_GOTPC32_TLSDESC.
	(Target_x86_64::Relocate::tls_desc_gd_to_le): Likewise.
	(Target_x86_64::Relocate::tls_ie_to_le): Handle.
	R_X86_64_CODE_4_GOTTPOFF.
	* testsuite/Makefile.am: Add x86_64_ie_to_le test.
	* testsuite/Makefile.in: Regenerated.
	* testsuite/x86_64_gd_to_le.s: Add R_X86_64_CODE_4_GOTPC32_TLSDESC
	test.
	* testsuite/x86_64_gd_to_le.sh: Check GDesc to LE conversion.
	* testsuite/x86_64_ie_to_le.s: New file.
	* testsuite/x86_64_ie_to_le.sh: Likewise.
This commit is contained in:
H.J. Lu 2023-07-02 07:46:21 -07:00
parent a533c8df59
commit 00a17c6ad0
8 changed files with 203 additions and 37 deletions

View File

@ -102,6 +102,14 @@ enum
// GOT if the instruction starts at 4
// bytes before the relocation offset,
// relaxable.
R_X86_64_CODE_4_GOTTPOFF = 44, // 32 bit signed PC relative offset to
// GOT entry for IE symbol if the
// instruction starts at 4 bytes before
// the relocation offset.
R_X86_64_CODE_4_GOTPC32_TLSDESC = 45, // 32-bit PC relative to TLS
// descriptor in GOT if the
// instruction starts at 4 bytes
// before the relocation offset.
// GNU vtable garbage collection extensions.
R_X86_64_GNU_VTINHERIT = 250,
R_X86_64_GNU_VTENTRY = 251

View File

@ -1244,6 +1244,17 @@ x86_64_gd_to_le: x86_64_gd_to_le.o gcctestdir/ld
x86_64_gd_to_le.stdout: x86_64_gd_to_le
$(TEST_OBJDUMP) -dw $< > $@
check_SCRIPTS += x86_64_ie_to_le.sh
check_DATA += x86_64_ie_to_le.stdout
MOSTLYCLEANFILES += x86_64_ie_to_le
x86_64_ie_to_le.o: x86_64_ie_to_le.s
$(TEST_AS) --64 -o $@ $<
x86_64_ie_to_le: x86_64_ie_to_le.o gcctestdir/ld
gcctestdir/ld -o $@ $<
x86_64_ie_to_le.stdout: x86_64_ie_to_le
$(TEST_OBJDUMP) -dw $< > $@
check_SCRIPTS += x86_64_overflow_pc32.sh
check_DATA += x86_64_overflow_pc32.err
MOSTLYCLEANFILES += x86_64_overflow_pc32.err

View File

@ -296,6 +296,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_31 = x86_64_mov_to_lea.sh \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_indirect_call_to_direct.sh \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_gd_to_le.sh \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_ie_to_le.sh \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_overflow_pc32.sh \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x32_overflow_pc32.sh \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ pr23016_1.sh \
@ -319,6 +320,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_indirect_call_to_direct1.stdout \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_indirect_jump_to_direct1.stdout \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_gd_to_le.stdout \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_ie_to_le.stdout \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_overflow_pc32.err \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x32_overflow_pc32.err \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ pr23016_1.stdout \
@ -343,6 +345,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_indirect_call_to_direct1 \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_indirect_jump_to_direct1 \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_gd_to_le \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_ie_to_le \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x86_64_overflow_pc32.err \
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ x32_overflow_pc32.err
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_34 = pr17704a_test
@ -5747,6 +5750,13 @@ x86_64_gd_to_le.sh.log: x86_64_gd_to_le.sh
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
x86_64_ie_to_le.sh.log: x86_64_ie_to_le.sh
@p='x86_64_ie_to_le.sh'; \
b='x86_64_ie_to_le.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
x86_64_overflow_pc32.sh.log: x86_64_overflow_pc32.sh
@p='x86_64_overflow_pc32.sh'; \
b='x86_64_overflow_pc32.sh'; \
@ -8485,6 +8495,13 @@ uninstall-am:
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ $<
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@x86_64_gd_to_le.stdout: x86_64_gd_to_le
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -dw $< > $@
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@x86_64_ie_to_le.o: x86_64_ie_to_le.s
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AS) --64 -o $@ $<
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@x86_64_ie_to_le: x86_64_ie_to_le.o gcctestdir/ld
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ $<
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@x86_64_ie_to_le.stdout: x86_64_ie_to_le
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -dw $< > $@
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@x86_64_overflow_pc32.o: x86_64_overflow_pc32.s
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_AS) -o $@ $<
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@x86_64_overflow_pc32.err: x86_64_overflow_pc32.o gcctestdir/ld

View File

@ -7,6 +7,7 @@ _start:
subq $8, %rsp
.cfi_def_cfa_offset 16
leaq foo@TLSDESC(%rip), %r9
leaq foo@TLSDESC(%rip), %r29
movq %r9, %rax
call *foo@TLSCALL(%rax)
addq %fs:0, %rax

View File

@ -24,3 +24,4 @@
set -e
grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%r9" x86_64_gd_to_le.stdout
grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%r29" x86_64_gd_to_le.stdout

View File

@ -0,0 +1,17 @@
.text
.p2align 4
.globl _start
.type _start, @function
_start:
addq foo@gottpoff(%rip), %r12
movq foo@gottpoff(%rip), %rax
addq foo@gottpoff(%rip), %r16
movq foo@gottpoff(%rip), %r20
.size _start, .-_start
.section .tdata,"awT",@progbits
.align 4
.type foo, @object
.size foo, 4
foo:
.long 30
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,29 @@
#!/bin/sh
# x86_64_ie_to_le.sh -- a test for IE -> LE conversion.
# Copyright (C) 2023 Free Software Foundation, Inc.
# This file is part of gold.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
# MA 02110-1301, USA.
set -e
grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r12" x86_64_ie_to_le.stdout
grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%rax" x86_64_ie_to_le.stdout
grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r16" x86_64_ie_to_le.stdout
grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%r20" x86_64_ie_to_le.stdout

View File

@ -1110,7 +1110,8 @@ class Target_x86_64 : public Sized_target<size, false>
// Adjust TLS relocation type based on the options and whether this
// is a local symbol.
static tls::Tls_optimization
optimize_tls_reloc(bool is_final, int r_type);
optimize_tls_reloc(bool is_final, int r_type, size_t r_offset,
const unsigned char* reloc_view);
// Get the GOT section, creating it if necessary.
Output_data_got<64, false>*
@ -2878,11 +2879,13 @@ Target_x86_64<size>::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
// Optimize the TLS relocation type based on what we know about the
// symbol. IS_FINAL is true if the final address of this symbol is
// known at link time.
// known at link time. RELOC_VIEW points to the relocation offset.
template<int size>
tls::Tls_optimization
Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type)
Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
size_t r_offset,
const unsigned char* reloc_view)
{
// If we are generating a shared library, then we can't do anything
// in the linker.
@ -2891,6 +2894,10 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type)
switch (r_type)
{
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
if (r_offset <= 4 || *(reloc_view - 4) != 0xd5)
return tls::TLSOPT_NONE;
// Fall through.
case elfcpp::R_X86_64_TLSGD:
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_TLSDESC_CALL:
@ -2913,6 +2920,10 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type)
// Another Local-Dynamic reloc.
return tls::TLSOPT_TO_LE;
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
if (r_offset <= 4 || *(reloc_view - 4) != 0xd5)
return tls::TLSOPT_NONE;
// Fall through.
case elfcpp::R_X86_64_GOTTPOFF:
// These are Initial-Exec relocs which get the thread offset
// from the GOT. If we know that we are linking against the
@ -2979,11 +2990,13 @@ Target_x86_64<size>::Scan::get_reference_flags(unsigned int r_type)
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_TLSDESC_CALL:
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
case elfcpp::R_X86_64_DTPOFF32:
case elfcpp::R_X86_64_DTPOFF64:
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
case elfcpp::R_X86_64_TPOFF32: // Local-exec
return Symbol::TLS_REF;
@ -3148,6 +3161,8 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab,
target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
}
const unsigned char* reloc_view = NULL;
switch (r_type)
{
case elfcpp::R_X86_64_NONE:
@ -3345,6 +3360,13 @@ need_got:
break;
// These are initial tls relocs, which are expected when linking
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
{
section_size_type stype;
reloc_view = object->section_contents(data_shndx, &stype, true);
}
// Fall through.
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_X86_64_TLSDESC_CALL:
@ -3355,9 +3377,11 @@ need_got:
case elfcpp::R_X86_64_TPOFF32: // Local-exec
{
bool output_is_shared = parameters->options().shared();
size_t r_offset = reloc.get_r_offset();
const tls::Tls_optimization optimized_type
= Target_x86_64<size>::optimize_tls_reloc(!output_is_shared,
r_type);
r_type, r_offset,
reloc_view + r_offset);
switch (r_type)
{
case elfcpp::R_X86_64_TLSGD: // General-dynamic
@ -3386,6 +3410,7 @@ need_got:
break;
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
@ -3438,6 +3463,7 @@ need_got:
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
@ -3615,6 +3641,8 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
&& this->reloc_needs_plt_for_ifunc(object, r_type))
target->make_plt_entry(symtab, layout, gsym);
const unsigned char *reloc_view = NULL;
switch (r_type)
{
case elfcpp::R_X86_64_NONE:
@ -3872,6 +3900,13 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
break;
// These are initial tls relocs, which are expected for global()
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
{
section_size_type stype;
reloc_view = object->section_contents(data_shndx, &stype, true);
}
// Fall through.
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_X86_64_TLSDESC_CALL:
@ -3884,11 +3919,15 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
// For the Initial-Exec model, we can treat undef symbols as final
// when building an executable.
const bool is_final = (gsym->final_value_is_known() ||
(r_type == elfcpp::R_X86_64_GOTTPOFF &&
((r_type == elfcpp::R_X86_64_GOTTPOFF ||
r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF) &&
gsym->is_undefined() &&
parameters->options().output_is_executable()));
size_t r_offset = reloc.get_r_offset();
const tls::Tls_optimization optimized_type
= Target_x86_64<size>::optimize_tls_reloc(is_final, r_type);
= Target_x86_64<size>::optimize_tls_reloc(is_final, r_type,
r_offset,
reloc_view + r_offset);
switch (r_type)
{
case elfcpp::R_X86_64_TLSGD: // General-dynamic
@ -3917,6 +3956,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
break;
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
@ -3965,6 +4005,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
@ -4560,11 +4601,13 @@ Target_x86_64<size>::Relocate::relocate(
// These are initial tls relocs, which are expected when linking
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_TLSDESC_CALL:
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
case elfcpp::R_X86_64_DTPOFF32:
case elfcpp::R_X86_64_DTPOFF64:
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
case elfcpp::R_X86_64_TPOFF32: // Local-exec
this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
view, address, view_size);
@ -4636,8 +4679,10 @@ Target_x86_64<size>::Relocate::relocate_tls(
const bool is_final = (gsym == NULL
? !parameters->options().shared()
: gsym->final_value_is_known());
size_t r_offset = rela.get_r_offset();
tls::Tls_optimization optimized_type
= Target_x86_64<size>::optimize_tls_reloc(is_final, r_type);
= Target_x86_64<size>::optimize_tls_reloc(is_final, r_type,
r_offset, view);
switch (r_type)
{
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
@ -4704,6 +4749,7 @@ Target_x86_64<size>::Relocate::relocate_tls(
break;
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_TLSDESC_CALL:
if (!is_executable && optimized_type == tls::TLSOPT_TO_LE)
{
@ -4729,7 +4775,8 @@ Target_x86_64<size>::Relocate::relocate_tls(
? GOT_TYPE_TLS_OFFSET
: GOT_TYPE_TLS_DESC);
unsigned int got_offset = 0;
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
if ((r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
|| r_type == elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC)
&& optimized_type == tls::TLSOPT_NONE)
{
// We created GOT entries in the .got.tlsdesc portion of
@ -4760,7 +4807,8 @@ Target_x86_64<size>::Relocate::relocate_tls(
}
else if (optimized_type == tls::TLSOPT_NONE)
{
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
|| r_type == elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC)
{
// Relocate the field with the offset of the pair of GOT
// entries.
@ -4845,6 +4893,7 @@ Target_x86_64<size>::Relocate::relocate_tls(
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
if (gsym != NULL
&& gsym->is_undefined()
&& parameters->options().output_is_executable())
@ -5051,7 +5100,8 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type view_size)
{
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
|| r_type == elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC)
{
// LP64: leaq foo@tlsdesc(%rip), %rax
// ==> movq foo@gottpoff(%rip), %rax
@ -5060,7 +5110,8 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie(
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
((r_type == elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC
|| (view[-3] & 0xfb) == 0x48
|| (size == 32 && (view[-3] & 0xfb) == 0x40))
&& view[-2] == 0x8d
&& (view[-1] & 0xc7) == 0x05));
@ -5132,6 +5183,22 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le(
value -= tls_segment->memsz();
Relocate_functions<size, false>::rela32(view, value, 0);
}
else if (r_type == elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC)
{
// REX2: lea foo@tlsdesc(%rip), %reg
// ==> mov foo@tpoff, %reg
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[-2] == 0x8d
&& (view[-1] & 0xc7) == 0x05));
unsigned char rex2_mask = 4 | 4 << 4;
view[-3] = (view[-3] & ~rex2_mask) | ((view[-3] & rex2_mask) >> 2);
view[-2] = 0xc7;
view[-1] = 0xc0 | ((view[-1] >> 3) & 7);
value -= tls_segment->memsz();
Relocate_functions<size, false>::rela32(view, value, 0);
}
else
{
// LP64: call *foo@tlscall(%rax)
@ -5231,7 +5298,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
size_t relnum,
Output_segment* tls_segment,
const elfcpp::Rela<size, false>& rela,
unsigned int,
unsigned int r_type,
typename elfcpp::Elf_types<size>::Elf_Addr value,
unsigned char* view,
section_size_type view_size)
@ -5250,35 +5317,50 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
unsigned char op3 = view[-1];
unsigned char reg = op3 >> 3;
if (op2 == 0x8b)
if (r_type == elfcpp::R_X86_64_GOTTPOFF)
{
// movq
if (op1 == 0x4c)
view[-3] = 0x49;
else if (size == 32 && op1 == 0x44)
view[-3] = 0x41;
view[-2] = 0xc7;
view[-1] = 0xc0 | reg;
}
else if (reg == 4)
{
// Special handling for %rsp.
if (op1 == 0x4c)
view[-3] = 0x49;
else if (size == 32 && op1 == 0x44)
view[-3] = 0x41;
view[-2] = 0x81;
view[-1] = 0xc0 | reg;
if (op2 == 0x8b)
{
// movq
if (op1 == 0x4c)
view[-3] = 0x49;
else if (size == 32 && op1 == 0x44)
view[-3] = 0x41;
view[-2] = 0xc7;
view[-1] = 0xc0 | reg;
}
else if (reg == 4)
{
// Special handling for %rsp.
if (op1 == 0x4c)
view[-3] = 0x49;
else if (size == 32 && op1 == 0x44)
view[-3] = 0x41;
view[-2] = 0x81;
view[-1] = 0xc0 | reg;
}
else
{
// addq
if (op1 == 0x4c)
view[-3] = 0x4d;
else if (size == 32 && op1 == 0x44)
view[-3] = 0x45;
view[-2] = 0x8d;
view[-1] = 0x80 | reg | (reg << 3);
}
}
else
{
// addq
if (op1 == 0x4c)
view[-3] = 0x4d;
else if (size == 32 && op1 == 0x44)
view[-3] = 0x45;
view[-2] = 0x8d;
view[-1] = 0x80 | reg | (reg << 3);
if (op2 == 0x8b)
op2 = 0xc7;
else
op2 = 0x81;
unsigned char rex2_mask = 4 | 4 << 4;
view[-3] = (view[-3] & ~rex2_mask) | ((view[-3] & rex2_mask) >> 2);
view[-2] = op2;
view[-1] = 0xc0 | reg;
}
if (tls_segment != NULL)