@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 \
@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 \
@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
--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'; \
@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
// 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>*
// 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.
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:
// 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
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;
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:
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:
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
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)
{
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)
{
&& 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:
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:
// 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
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)
{
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)
{
// 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);
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
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)
{
? 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
}
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.
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())
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
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));
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)
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)
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)