From Craig Silverstein: add LD to LE TLS optimizations.
This commit is contained in:
parent
5ffcaa866f
commit
72ec287661
103
gold/x86_64.cc
103
gold/x86_64.cc
|
@ -192,15 +192,14 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||||
unsigned char* view,
|
unsigned char* view,
|
||||||
off_t view_size);
|
off_t view_size);
|
||||||
|
|
||||||
// Check the range for a TLS relocation.
|
// Do a TLS Local-Dynamic to Local-Exec transition.
|
||||||
static inline void
|
inline void
|
||||||
check_range(const Relocate_info<64, false>*, size_t relnum,
|
tls_ld_to_le(const Relocate_info<64, false>*, size_t relnum,
|
||||||
const elfcpp::Rela<64, false>&, off_t, off_t);
|
Output_segment* tls_segment,
|
||||||
|
const elfcpp::Rela<64, false>&, unsigned int r_type,
|
||||||
// Check the validity of a TLS relocation. This is like assert.
|
elfcpp::Elf_types<64>::Elf_Addr value,
|
||||||
static inline void
|
unsigned char* view,
|
||||||
check_tls(const Relocate_info<64, false>*, size_t relnum,
|
off_t view_size);
|
||||||
const elfcpp::Rela<64, false>&, bool);
|
|
||||||
|
|
||||||
// This is set if we should skip the next reloc, which should be a
|
// This is set if we should skip the next reloc, which should be a
|
||||||
// PLT32 reloc against ___tls_get_addr.
|
// PLT32 reloc against ___tls_get_addr.
|
||||||
|
@ -572,7 +571,7 @@ Target_x86_64::copy_reloc(const General_options* options,
|
||||||
Layout* layout,
|
Layout* layout,
|
||||||
Sized_relobj<64, false>* object,
|
Sized_relobj<64, false>* object,
|
||||||
unsigned int data_shndx, Symbol* gsym,
|
unsigned int data_shndx, Symbol* gsym,
|
||||||
const elfcpp::Rela<64, false>& rel)
|
const elfcpp::Rela<64, false>& rela)
|
||||||
{
|
{
|
||||||
Sized_symbol<64>* ssym;
|
Sized_symbol<64>* ssym;
|
||||||
ssym = symtab->get_sized_symbol SELECT_SIZE_NAME(64) (gsym
|
ssym = symtab->get_sized_symbol SELECT_SIZE_NAME(64) (gsym
|
||||||
|
@ -586,7 +585,7 @@ Target_x86_64::copy_reloc(const General_options* options,
|
||||||
// symbol, then we will emit the relocation.
|
// symbol, then we will emit the relocation.
|
||||||
if (this->copy_relocs_ == NULL)
|
if (this->copy_relocs_ == NULL)
|
||||||
this->copy_relocs_ = new Copy_relocs<64, false>();
|
this->copy_relocs_ = new Copy_relocs<64, false>();
|
||||||
this->copy_relocs_->save(ssym, object, data_shndx, rel);
|
this->copy_relocs_->save(ssym, object, data_shndx, rela);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1347,7 +1346,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
|
||||||
inline void
|
inline void
|
||||||
Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
|
Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
|
||||||
size_t relnum,
|
size_t relnum,
|
||||||
const elfcpp::Rela<64, false>& rel,
|
const elfcpp::Rela<64, false>& rela,
|
||||||
unsigned int r_type,
|
unsigned int r_type,
|
||||||
const Sized_symbol<64>* gsym,
|
const Sized_symbol<64>* gsym,
|
||||||
const Symbol_value<64>* psymval,
|
const Symbol_value<64>* psymval,
|
||||||
|
@ -1358,7 +1357,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
|
||||||
Output_segment* tls_segment = relinfo->layout->tls_segment();
|
Output_segment* tls_segment = relinfo->layout->tls_segment();
|
||||||
if (tls_segment == NULL)
|
if (tls_segment == NULL)
|
||||||
{
|
{
|
||||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
||||||
_("TLS reloc but no TLS segment"));
|
_("TLS reloc but no TLS segment"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1381,11 +1380,11 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
|
||||||
if (optimized_type == tls::TLSOPT_TO_LE)
|
if (optimized_type == tls::TLSOPT_TO_LE)
|
||||||
{
|
{
|
||||||
Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
|
Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
|
||||||
rel, r_type, value, view,
|
rela, r_type, value, view,
|
||||||
view_size);
|
view_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
||||||
_("unsupported reloc type %u"),
|
_("unsupported reloc type %u"),
|
||||||
r_type);
|
r_type);
|
||||||
break;
|
break;
|
||||||
|
@ -1396,20 +1395,22 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
|
||||||
if (optimized_type == tls::TLSOPT_TO_LE)
|
if (optimized_type == tls::TLSOPT_TO_LE)
|
||||||
{
|
{
|
||||||
this->tls_gd_to_le(relinfo, relnum, tls_segment,
|
this->tls_gd_to_le(relinfo, relnum, tls_segment,
|
||||||
rel, r_type, value, view,
|
rela, r_type, value, view,
|
||||||
view_size);
|
view_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
||||||
_("unsupported reloc %u"), r_type);
|
_("unsupported reloc %u"), r_type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_X86_64_TLSLD:
|
case elfcpp::R_X86_64_TLSLD:
|
||||||
if (optimized_type == tls::TLSOPT_TO_LE)
|
if (optimized_type == tls::TLSOPT_TO_LE)
|
||||||
{
|
{
|
||||||
// FIXME: implement ld_to_le
|
this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type,
|
||||||
|
value, view, view_size);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
|
||||||
_("unsupported reloc %u"), r_type);
|
_("unsupported reloc %u"), r_type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1438,7 +1439,7 @@ inline void
|
||||||
Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
|
Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
|
||||||
size_t relnum,
|
size_t relnum,
|
||||||
Output_segment* tls_segment,
|
Output_segment* tls_segment,
|
||||||
const elfcpp::Rela<64, false>& rel,
|
const elfcpp::Rela<64, false>& rela,
|
||||||
unsigned int,
|
unsigned int,
|
||||||
elfcpp::Elf_types<64>::Elf_Addr value,
|
elfcpp::Elf_types<64>::Elf_Addr value,
|
||||||
unsigned char* view,
|
unsigned char* view,
|
||||||
|
@ -1450,8 +1451,8 @@ Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
|
||||||
// movq foo@gottpoff(%rip),%reg ==> movq $YY,%reg
|
// movq foo@gottpoff(%rip),%reg ==> movq $YY,%reg
|
||||||
// addq foo@gottpoff(%rip),%reg ==> addq $YY,%reg
|
// addq foo@gottpoff(%rip),%reg ==> addq $YY,%reg
|
||||||
|
|
||||||
Target_x86_64::Relocate::check_range(relinfo, relnum, rel, view_size, -3);
|
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
|
||||||
Target_x86_64::Relocate::check_range(relinfo, relnum, rel, view_size, 4);
|
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
|
||||||
|
|
||||||
unsigned char op1 = view[-3];
|
unsigned char op1 = view[-3];
|
||||||
unsigned char op2 = view[-2];
|
unsigned char op2 = view[-2];
|
||||||
|
@ -1494,7 +1495,7 @@ inline void
|
||||||
Target_x86_64::Relocate::tls_gd_to_le(const Relocate_info<64, false>* relinfo,
|
Target_x86_64::Relocate::tls_gd_to_le(const Relocate_info<64, false>* relinfo,
|
||||||
size_t relnum,
|
size_t relnum,
|
||||||
Output_segment* tls_segment,
|
Output_segment* tls_segment,
|
||||||
const elfcpp::Rela<64, false>& rel,
|
const elfcpp::Rela<64, false>& rela,
|
||||||
unsigned int,
|
unsigned int,
|
||||||
elfcpp::Elf_types<64>::Elf_Addr value,
|
elfcpp::Elf_types<64>::Elf_Addr value,
|
||||||
unsigned char* view,
|
unsigned char* view,
|
||||||
|
@ -1504,15 +1505,13 @@ Target_x86_64::Relocate::tls_gd_to_le(const Relocate_info<64, false>* relinfo,
|
||||||
// .word 0x6666; rex64; call __tls_get_addr
|
// .word 0x6666; rex64; call __tls_get_addr
|
||||||
// ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
|
// ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
|
||||||
|
|
||||||
Target_x86_64::Relocate::check_range(relinfo, relnum, rel, view_size, -4);
|
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4);
|
||||||
Target_x86_64::Relocate::check_range(relinfo, relnum, rel, view_size, 12);
|
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
|
||||||
|
|
||||||
Target_x86_64::Relocate::check_tls(relinfo, relnum, rel,
|
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
|
||||||
(memcmp(view - 4, "\x66\x48\x8d\x3d", 4)
|
(memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
|
||||||
== 0));
|
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
|
||||||
Target_x86_64::Relocate::check_tls(relinfo, relnum, rel,
|
(memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
|
||||||
(memcmp(view + 4, "\x66\x66\x48\xe8", 4)
|
|
||||||
== 0));
|
|
||||||
|
|
||||||
memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", 16);
|
memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", 16);
|
||||||
|
|
||||||
|
@ -1524,31 +1523,33 @@ Target_x86_64::Relocate::tls_gd_to_le(const Relocate_info<64, false>* relinfo,
|
||||||
this->skip_call_tls_get_addr_ = true;
|
this->skip_call_tls_get_addr_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the range for a TLS relocation.
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
Target_x86_64::Relocate::check_range(const Relocate_info<64, false>* relinfo,
|
Target_x86_64::Relocate::tls_ld_to_le(const Relocate_info<64, false>* relinfo,
|
||||||
size_t relnum,
|
size_t relnum,
|
||||||
const elfcpp::Rela<64, false>& rel,
|
Output_segment*,
|
||||||
off_t view_size, off_t off)
|
const elfcpp::Rela<64, false>& rela,
|
||||||
|
unsigned int,
|
||||||
|
elfcpp::Elf_types<64>::Elf_Addr,
|
||||||
|
unsigned char* view,
|
||||||
|
off_t view_size)
|
||||||
{
|
{
|
||||||
off_t offset = rel.get_r_offset() + off;
|
// leaq foo@tlsld(%rip),%rdi; call __tls_get_addr@plt;
|
||||||
if (offset < 0 || offset > view_size)
|
// ... leq foo@dtpoff(%rax),%reg
|
||||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
// ==> .word 0x6666; .byte 0x66; movq %fs:0,%rax ... leaq x@tpoff(%rax),%rdx
|
||||||
_("TLS relocation out of range"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the validity of a TLS relocation. This is like assert.
|
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
|
||||||
|
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 9);
|
||||||
|
|
||||||
inline void
|
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
|
||||||
Target_x86_64::Relocate::check_tls(const Relocate_info<64, false>* relinfo,
|
view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d);
|
||||||
size_t relnum,
|
|
||||||
const elfcpp::Rela<64, false>& rel,
|
tls::check_tls(relinfo, relnum, rela.get_r_offset(), view[4] == 0xe8);
|
||||||
bool valid)
|
|
||||||
{
|
memcpy(view - 3, "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0\0", 12);
|
||||||
if (!valid)
|
|
||||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
// The next reloc should be a PLT32 reloc against __tls_get_addr.
|
||||||
_("TLS relocation against invalid instruction"));
|
// We can skip it.
|
||||||
|
this->skip_call_tls_get_addr_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relocate section data.
|
// Relocate section data.
|
||||||
|
|
Loading…
Reference in New Issue