mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 11:00:01 +08:00
gold: Add support for sparc GOTDATA optimizations in Gold.
gold/ * sparc.cc (Target_sparc::got_address): New function. (Sparc_relocate_functions::gdop_hix22): New function. (Sparc_relocate_functions::gdop_lox10): New function. (Target_sparc::Scan::local): Do not emit a GOT entry for GOTDATA relocs. (Target_sparc::Scan::local): Likewise if the global symbol is not preemptible and is not IFUNC. (Target_sparc::Relocate::relocate): Perform GOTDATA code transformations for local and non-preemptible non-IFUNC global symbols.
This commit is contained in:
@ -1,5 +1,16 @@
|
|||||||
2012-04-16 David S. Miller <davem@davemloft.net>
|
2012-04-16 David S. Miller <davem@davemloft.net>
|
||||||
|
|
||||||
|
* sparc.cc (Target_sparc::got_address): New function.
|
||||||
|
(Sparc_relocate_functions::gdop_hix22): New function.
|
||||||
|
(Sparc_relocate_functions::gdop_lox10): New function.
|
||||||
|
(Target_sparc::Scan::local): Do not emit a GOT entry for GOTDATA
|
||||||
|
relocs.
|
||||||
|
(Target_sparc::Scan::local): Likewise if the global symbol is not
|
||||||
|
preemptible and is not IFUNC.
|
||||||
|
(Target_sparc::Relocate::relocate): Perform GOTDATA code
|
||||||
|
transformations for local and non-preemptible non-IFUNC global
|
||||||
|
symbols.
|
||||||
|
|
||||||
* gdb-index.cc (Gdb_index::do_write): Use Swap_unaligned when
|
* gdb-index.cc (Gdb_index::do_write): Use Swap_unaligned when
|
||||||
writing out 64-bit part of ranges.
|
writing out 64-bit part of ranges.
|
||||||
|
|
||||||
|
103
gold/sparc.cc
103
gold/sparc.cc
@ -185,6 +185,15 @@ class Target_sparc : public Sized_target<size, big_endian>
|
|||||||
return this->got_size() / (size / 8);
|
return this->got_size() / (size / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the address of the GOT.
|
||||||
|
uint64_t
|
||||||
|
got_address() const
|
||||||
|
{
|
||||||
|
if (this->got_ == NULL)
|
||||||
|
return 0;
|
||||||
|
return this->got_->address();
|
||||||
|
}
|
||||||
|
|
||||||
// Return the number of entries in the PLT.
|
// Return the number of entries in the PLT.
|
||||||
unsigned int
|
unsigned int
|
||||||
plt_entry_count() const;
|
plt_entry_count() const;
|
||||||
@ -1065,6 +1074,28 @@ public:
|
|||||||
elfcpp::Swap<32, true>::writeval(wv, val | reloc);
|
elfcpp::Swap<32, true>::writeval(wv, val | reloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// R_SPARC_GOTDATA_OP_HIX22: @gdopoff(Symbol + Addend) >> 10
|
||||||
|
static inline void
|
||||||
|
gdop_hix22(unsigned char* view,
|
||||||
|
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||||
|
typename elfcpp::Elf_types<size>::Elf_Addr addend)
|
||||||
|
{
|
||||||
|
typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
|
||||||
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||||
|
Valtype val = elfcpp::Swap<32, true>::readval(wv);
|
||||||
|
int32_t reloc = static_cast<int32_t>(value + addend);
|
||||||
|
|
||||||
|
val &= ~0x3fffff;
|
||||||
|
|
||||||
|
if (reloc < 0)
|
||||||
|
reloc ^= ~static_cast<int32_t>(0);
|
||||||
|
reloc >>= 10;
|
||||||
|
|
||||||
|
reloc &= 0x3fffff;
|
||||||
|
|
||||||
|
elfcpp::Swap<32, true>::writeval(wv, val | reloc);
|
||||||
|
}
|
||||||
|
|
||||||
// R_SPARC_HIX22: ((Symbol + Addend) ^ 0xffffffffffffffff) >> 10
|
// R_SPARC_HIX22: ((Symbol + Addend) ^ 0xffffffffffffffff) >> 10
|
||||||
static inline void
|
static inline void
|
||||||
hix22(unsigned char* view,
|
hix22(unsigned char* view,
|
||||||
@ -1106,6 +1137,26 @@ public:
|
|||||||
elfcpp::Swap<32, true>::writeval(wv, val | reloc);
|
elfcpp::Swap<32, true>::writeval(wv, val | reloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// R_SPARC_GOTDATA_OP_LOX10: (@gdopoff(Symbol + Addend) & 0x3ff) | 0x1c00
|
||||||
|
static inline void
|
||||||
|
gdop_lox10(unsigned char* view,
|
||||||
|
typename elfcpp::Elf_types<size>::Elf_Addr value,
|
||||||
|
typename elfcpp::Elf_types<size>::Elf_Addr addend)
|
||||||
|
{
|
||||||
|
typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
|
||||||
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||||
|
Valtype val = elfcpp::Swap<32, true>::readval(wv);
|
||||||
|
int32_t reloc = static_cast<int32_t>(value + addend);
|
||||||
|
|
||||||
|
if (reloc < 0)
|
||||||
|
reloc = (reloc & 0x3ff) | 0x1c00;
|
||||||
|
else
|
||||||
|
reloc = (reloc & 0x3ff);
|
||||||
|
|
||||||
|
val &= ~0x1fff;
|
||||||
|
elfcpp::Swap<32, true>::writeval(wv, val | reloc);
|
||||||
|
}
|
||||||
|
|
||||||
// R_SPARC_LOX10: ((Symbol + Addend) & 0x3ff) | 0x1c00
|
// R_SPARC_LOX10: ((Symbol + Addend) & 0x3ff) | 0x1c00
|
||||||
static inline void
|
static inline void
|
||||||
lox10(unsigned char* view,
|
lox10(unsigned char* view,
|
||||||
@ -2266,6 +2317,10 @@ Target_sparc<size, big_endian>::Scan::local(
|
|||||||
case elfcpp::R_SPARC_GOTDATA_OP:
|
case elfcpp::R_SPARC_GOTDATA_OP:
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
||||||
|
// We will optimize this into a GOT relative relocation
|
||||||
|
// and code transform the GOT load into an addition.
|
||||||
|
break;
|
||||||
|
|
||||||
case elfcpp::R_SPARC_GOT10:
|
case elfcpp::R_SPARC_GOT10:
|
||||||
case elfcpp::R_SPARC_GOT13:
|
case elfcpp::R_SPARC_GOT13:
|
||||||
case elfcpp::R_SPARC_GOT22:
|
case elfcpp::R_SPARC_GOT22:
|
||||||
@ -2695,6 +2750,15 @@ Target_sparc<size, big_endian>::Scan::global(
|
|||||||
case elfcpp::R_SPARC_GOTDATA_OP:
|
case elfcpp::R_SPARC_GOTDATA_OP:
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
||||||
|
if (gsym->is_defined()
|
||||||
|
&& !gsym->is_from_dynobj()
|
||||||
|
&& !gsym->is_preemptible()
|
||||||
|
&& !is_ifunc)
|
||||||
|
{
|
||||||
|
// We will optimize this into a GOT relative relocation
|
||||||
|
// and code transform the GOT load into an addition.
|
||||||
|
break;
|
||||||
|
}
|
||||||
case elfcpp::R_SPARC_GOT10:
|
case elfcpp::R_SPARC_GOT10:
|
||||||
case elfcpp::R_SPARC_GOT13:
|
case elfcpp::R_SPARC_GOT13:
|
||||||
case elfcpp::R_SPARC_GOT22:
|
case elfcpp::R_SPARC_GOT22:
|
||||||
@ -3076,6 +3140,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
|
|||||||
typename elfcpp::Elf_types<size>::Elf_Addr address,
|
typename elfcpp::Elf_types<size>::Elf_Addr address,
|
||||||
section_size_type view_size)
|
section_size_type view_size)
|
||||||
{
|
{
|
||||||
|
bool orig_is_ifunc = psymval->is_ifunc_symbol();
|
||||||
r_type &= 0xff;
|
r_type &= 0xff;
|
||||||
|
|
||||||
if (this->ignore_gd_add_)
|
if (this->ignore_gd_add_)
|
||||||
@ -3108,7 +3173,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
|
|||||||
|
|
||||||
psymval = &symval;
|
psymval = &symval;
|
||||||
}
|
}
|
||||||
else if (gsym == NULL && psymval->is_ifunc_symbol())
|
else if (gsym == NULL && orig_is_ifunc)
|
||||||
{
|
{
|
||||||
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
|
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
|
||||||
if (object->local_has_plt_offset(r_sym))
|
if (object->local_has_plt_offset(r_sym))
|
||||||
@ -3125,11 +3190,24 @@ Target_sparc<size, big_endian>::Relocate::relocate(
|
|||||||
// pointer points to the beginning, not the end, of the table.
|
// pointer points to the beginning, not the end, of the table.
|
||||||
// So we just use the plain offset.
|
// So we just use the plain offset.
|
||||||
unsigned int got_offset = 0;
|
unsigned int got_offset = 0;
|
||||||
|
bool gdop_valid = false;
|
||||||
switch (r_type)
|
switch (r_type)
|
||||||
{
|
{
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP:
|
case elfcpp::R_SPARC_GOTDATA_OP:
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
||||||
|
// If this is local, we did not create a GOT entry because we
|
||||||
|
// intend to transform this into a GOT relative relocation.
|
||||||
|
if (gsym == NULL
|
||||||
|
|| (gsym->is_defined()
|
||||||
|
&& !gsym->is_from_dynobj()
|
||||||
|
&& !gsym->is_preemptible()
|
||||||
|
&& !orig_is_ifunc))
|
||||||
|
{
|
||||||
|
got_offset = psymval->value(object, 0) - target->got_address();
|
||||||
|
gdop_valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case elfcpp::R_SPARC_GOT10:
|
case elfcpp::R_SPARC_GOT10:
|
||||||
case elfcpp::R_SPARC_GOT13:
|
case elfcpp::R_SPARC_GOT13:
|
||||||
case elfcpp::R_SPARC_GOT22:
|
case elfcpp::R_SPARC_GOT22:
|
||||||
@ -3248,14 +3326,37 @@ Target_sparc<size, big_endian>::Relocate::relocate(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP:
|
case elfcpp::R_SPARC_GOTDATA_OP:
|
||||||
|
if (gdop_valid)
|
||||||
|
{
|
||||||
|
typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
|
||||||
|
Insntype* wv = reinterpret_cast<Insntype*>(view);
|
||||||
|
Insntype val;
|
||||||
|
|
||||||
|
// {ld,ldx} [%rs1 + %rs2], %rd --> add %rs1, %rs2, %rd
|
||||||
|
val = elfcpp::Swap<32, true>::readval(wv);
|
||||||
|
val = 0x80000000 | (val & 0x3e07c01f);
|
||||||
|
elfcpp::Swap<32, true>::writeval(wv, val);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
|
||||||
|
if (gdop_valid)
|
||||||
|
{
|
||||||
|
Reloc::gdop_lox10(view, got_offset, addend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fall through. */
|
||||||
case elfcpp::R_SPARC_GOT13:
|
case elfcpp::R_SPARC_GOT13:
|
||||||
Reloc::rela32_13(view, got_offset, addend);
|
Reloc::rela32_13(view, got_offset, addend);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
|
||||||
|
if (gdop_valid)
|
||||||
|
{
|
||||||
|
Reloc::gdop_hix22(view, got_offset, addend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fall through. */
|
||||||
case elfcpp::R_SPARC_GOT22:
|
case elfcpp::R_SPARC_GOT22:
|
||||||
Reloc::hi22(view, got_offset, addend);
|
Reloc::hi22(view, got_offset, addend);
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user