* [PATCH] Add support for sparc GOTDATA optimizations in Gold.
@ 2012-04-11 22:29 David Miller
2012-04-17 0:16 ` Ian Lance Taylor
0 siblings, 1 reply; 3+ messages in thread
From: David Miller @ 2012-04-11 22:29 UTC (permalink / raw)
To: binutils
Basically, this mirrors the logic in the BFD linker which
already supports this transformation.
For a PIC transformation of the form:
sethi %gdop_hix22(symbol), %g1
xor %g1, %gdop_lox10(symbol), %g1
ld [%l7 + %g1], %o0
into:
sethi %hi(~(symbol - got_base)), %g1
xor %g1, %lo(((symbol - got_base)&0x3ff)|0x1c00), %g1
add %l7, %g1, %o0
and also eliminates the GOT slot. The funny arithmatic and the use of
'xor' is so that on 64-bit arbitrary 32-bit negative offsets can work
and are properly sign extended.
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.
---
gold/sparc.cc | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 1 deletion(-)
diff --git a/gold/sparc.cc b/gold/sparc.cc
index d1e83eb..a513a00 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -185,6 +185,15 @@ class Target_sparc : public Sized_target<size, big_endian>
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.
unsigned int
plt_entry_count() const;
@@ -1065,6 +1074,28 @@ public:
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 = (value + addend);
+
+ val &= ~0x3fffff;
+
+ if (reloc < 0)
+ reloc ^= ~(Valtype)0;
+ reloc >>= 10;
+
+ reloc &= 0x3fffff;
+
+ elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+ }
+
// R_SPARC_HIX22: ((Symbol + Addend) ^ 0xffffffffffffffff) >> 10
static inline void
hix22(unsigned char* view,
@@ -1106,6 +1137,26 @@ public:
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 = (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
static inline void
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_HIX22:
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_GOT13:
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_HIX22:
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_GOT13:
case elfcpp::R_SPARC_GOT22:
@@ -3076,6 +3140,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type view_size)
{
+ bool orig_is_ifunc = psymval->is_ifunc_symbol();
r_type &= 0xff;
if (this->ignore_gd_add_)
@@ -3108,7 +3173,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
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());
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.
// So we just use the plain offset.
unsigned int got_offset = 0;
+ bool gdop_valid = false;
switch (r_type)
{
case elfcpp::R_SPARC_GOTDATA_OP:
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
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_GOT13:
case elfcpp::R_SPARC_GOT22:
@@ -3248,14 +3326,37 @@ Target_sparc<size, big_endian>::Relocate::relocate(
break;
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;
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:
Reloc::rela32_13(view, got_offset, addend);
break;
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:
Reloc::hi22(view, got_offset, addend);
break;
--
1.7.9.5
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Add support for sparc GOTDATA optimizations in Gold.
2012-04-11 22:29 [PATCH] Add support for sparc GOTDATA optimizations in Gold David Miller
@ 2012-04-17 0:16 ` Ian Lance Taylor
2012-04-17 2:33 ` David Miller
0 siblings, 1 reply; 3+ messages in thread
From: Ian Lance Taylor @ 2012-04-17 0:16 UTC (permalink / raw)
To: David Miller; +Cc: binutils
David Miller <davem@davemloft.net> writes:
> 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.
> + // 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 = (value + addend);
> +
> + val &= ~0x3fffff;
> +
> + if (reloc < 0)
> + reloc ^= ~(Valtype)0;
> + reloc >>= 10;
> +
> + reloc &= 0x3fffff;
> +
> + elfcpp::Swap<32, true>::writeval(wv, val | reloc);
> + }
I think I would change the line setting reloc to
int32_t reloc = static_cast<int32_t>(value + addend);
to make clear that you are intentionally dropping some bits for the
64-bit target.
The line
reloc ^= ~(Valtype)0;
should probably be
reloc ^= ~static_cast<int32_t>(0);
or perhaps even, for extreme clarity,
reloc = static_cast<int32_t>(static_cast<uint32_t>(reloc)
^ static_cast<uint32_t>(0));
to avoid bit operations on signed types.
This is OK with changes along those lines.
Thanks.
Ian
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Add support for sparc GOTDATA optimizations in Gold.
2012-04-17 0:16 ` Ian Lance Taylor
@ 2012-04-17 2:33 ` David Miller
0 siblings, 0 replies; 3+ messages in thread
From: David Miller @ 2012-04-17 2:33 UTC (permalink / raw)
To: iant; +Cc: binutils
From: Ian Lance Taylor <iant@google.com>
Date: Mon, 16 Apr 2012 17:15:35 -0700
> I think I would change the line setting reloc to
> int32_t reloc = static_cast<int32_t>(value + addend);
> to make clear that you are intentionally dropping some bits for the
> 64-bit target.
>
> The line
> reloc ^= ~(Valtype)0;
> should probably be
> reloc ^= ~static_cast<int32_t>(0);
> or perhaps even, for extreme clarity,
> reloc = static_cast<int32_t>(static_cast<uint32_t>(reloc)
> ^ static_cast<uint32_t>(0));
> to avoid bit operations on signed types.
>
> This is OK with changes along those lines.
Ok, I choose the medium level of clarity :-)
Thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-04-17 2:30 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-11 22:29 [PATCH] Add support for sparc GOTDATA optimizations in Gold David Miller
2012-04-17 0:16 ` Ian Lance Taylor
2012-04-17 2:33 ` David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).