diff options
author | David S. Miller <davem@redhat.com> | 2012-04-17 02:29:46 +0000 |
---|---|---|
committer | David S. Miller <davem@redhat.com> | 2012-04-17 02:29:46 +0000 |
commit | 2a1079e885ccac81f0043eec1c2a638d3fdfeed3 (patch) | |
tree | fe788e631dbd55899ac127f5ff14503350a79a26 /gold | |
parent | 0bc964fc7982793fd7d54dd6017774db1a19e3c6 (diff) | |
download | binutils-gdb-2a1079e885ccac81f0043eec1c2a638d3fdfeed3.tar.gz |
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.
Diffstat (limited to 'gold')
-rw-r--r-- | gold/ChangeLog | 11 | ||||
-rw-r--r-- | gold/sparc.cc | 103 |
2 files changed, 113 insertions, 1 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index c9bfd797265..363f368939b 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,16 @@ 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 writing out 64-bit part of ranges. diff --git a/gold/sparc.cc b/gold/sparc.cc index d1e83eb1671..762da424dce 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 = 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 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 = 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 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; |