diff options
author | Alan Modra <amodra@gmail.com> | 2015-12-07 13:15:24 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2015-12-07 13:17:00 +1030 |
commit | 549dba71045c856f3d169bf2edc7bfc7cabe5a0b (patch) | |
tree | 62a344ff8fcdf99e9c3354be575e6bd4d1f6c58f | |
parent | 006589cfa144fc1efeea1d114943c0bd1624e930 (diff) | |
download | gdb-549dba71045c856f3d169bf2edc7bfc7cabe5a0b.zip gdb-549dba71045c856f3d169bf2edc7bfc7cabe5a0b.tar.gz gdb-549dba71045c856f3d169bf2edc7bfc7cabe5a0b.tar.bz2 |
[GOLD] R_PPC64_ENTRY support
elfcpp/
* powerpc.h (R_PPC64_ENTRY): Define.
gold/
* powerpc.cc (add_2_2_12, ld_2_12, lis_2): Define.
(Target_powerpc::Scan::local, global): Handle R_PPC64_ENTRY.
(Target_powerpc::Relocate::relocate): Edit code at R_PPC64_ENTRY.
-rw-r--r-- | elfcpp/ChangeLog | 4 | ||||
-rw-r--r-- | elfcpp/powerpc.h | 1 | ||||
-rw-r--r-- | gold/ChangeLog | 6 | ||||
-rw-r--r-- | gold/powerpc.cc | 47 |
4 files changed, 58 insertions, 0 deletions
diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog index c443334..0aa8627 100644 --- a/elfcpp/ChangeLog +++ b/elfcpp/ChangeLog @@ -1,3 +1,7 @@ +2015-12-07 Alan Modra <amodra@gmail.com> + + * powerpc.h (R_PPC64_ENTRY): Define. + 2015-11-11 Alan Modra <amodra@gmail.com> Peter Bergner <bergner@vnet.ibm.com> diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h index ae30c8a..a8b005e 100644 --- a/elfcpp/powerpc.h +++ b/elfcpp/powerpc.h @@ -178,6 +178,7 @@ enum R_PPC_EMB_RELSDA = 116, R_PPC64_REL24_NOTOC = 116, R_PPC64_ADDR64_LOCAL = 117, + R_PPC64_ENTRY = 118, R_PPC_VLE_REL8 = 216, R_PPC_VLE_REL15 = 217, diff --git a/gold/ChangeLog b/gold/ChangeLog index 5ead7da..c4bf4a4 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,9 @@ +2015-12-07 Alan Modra <amodra@gmail.com> + + * powerpc.cc (add_2_2_12, ld_2_12, lis_2): Define. + (Target_powerpc::Scan::local, global): Handle R_PPC64_ENTRY. + (Target_powerpc::Relocate::relocate): Edit code at R_PPC64_ENTRY. + 2015-12-03 Vladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com> * object.cc (Sized_relobj::do_for_all_local_got_entries): Use diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 39a0324..12215ff 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -3224,6 +3224,7 @@ Output_data_plt_powerpc<size, big_endian>::add_local_ifunc_entry( static const uint32_t add_0_11_11 = 0x7c0b5a14; static const uint32_t add_2_2_11 = 0x7c425a14; +static const uint32_t add_2_2_12 = 0x7c426214; static const uint32_t add_3_3_2 = 0x7c631214; static const uint32_t add_3_3_13 = 0x7c636a14; static const uint32_t add_11_0_11 = 0x7d605a14; @@ -3258,6 +3259,7 @@ static const uint32_t ld_0_12 = 0xe80c0000; static const uint32_t ld_2_1 = 0xe8410000; static const uint32_t ld_2_2 = 0xe8420000; static const uint32_t ld_2_11 = 0xe84b0000; +static const uint32_t ld_2_12 = 0xe84c0000; static const uint32_t ld_11_2 = 0xe9620000; static const uint32_t ld_11_11 = 0xe96b0000; static const uint32_t ld_12_2 = 0xe9820000; @@ -3267,6 +3269,7 @@ static const uint32_t lfd_0_1 = 0xc8010000; static const uint32_t li_0_0 = 0x38000000; static const uint32_t li_12_0 = 0x39800000; static const uint32_t lis_0 = 0x3c000000; +static const uint32_t lis_2 = 0x3c400000; static const uint32_t lis_11 = 0x3d600000; static const uint32_t lis_12 = 0x3d800000; static const uint32_t lvx_0_12_0 = 0x7c0c00ce; @@ -5607,6 +5610,7 @@ Target_powerpc<size, big_endian>::Scan::local( case elfcpp::R_POWERPC_GNU_VTENTRY: case elfcpp::R_PPC64_TOCSAVE: case elfcpp::R_POWERPC_TLS: + case elfcpp::R_PPC64_ENTRY: break; case elfcpp::R_PPC64_TOC: @@ -5982,6 +5986,7 @@ Target_powerpc<size, big_endian>::Scan::global( case elfcpp::R_POWERPC_GNU_VTENTRY: case elfcpp::R_PPC_LOCAL24PC: case elfcpp::R_POWERPC_TLS: + case elfcpp::R_PPC64_ENTRY: break; case elfcpp::R_PPC64_TOC: @@ -7655,6 +7660,48 @@ Target_powerpc<size, big_endian>::Relocate::relocate( } } break; + + case elfcpp::R_PPC64_ENTRY: + value = (target->got_section()->output_section()->address() + + object->toc_base_offset()); + if (value + 0x80008000 <= 0xffffffff + && !parameters->options().output_is_position_independent()) + { + Insn* iview = reinterpret_cast<Insn*>(view); + Insn insn1 = elfcpp::Swap<32, big_endian>::readval(iview); + Insn insn2 = elfcpp::Swap<32, big_endian>::readval(iview + 1); + + if ((insn1 & ~0xfffc) == ld_2_12 + && insn2 == add_2_2_12) + { + insn1 = lis_2 + ha(value); + elfcpp::Swap<32, big_endian>::writeval(iview, insn1); + insn2 = addi_2_2 + l(value); + elfcpp::Swap<32, big_endian>::writeval(iview + 1, insn2); + return true; + } + } + else + { + value -= address; + if (value + 0x80008000 <= 0xffffffff) + { + Insn* iview = reinterpret_cast<Insn*>(view); + Insn insn1 = elfcpp::Swap<32, big_endian>::readval(iview); + Insn insn2 = elfcpp::Swap<32, big_endian>::readval(iview + 1); + + if ((insn1 & ~0xfffc) == ld_2_12 + && insn2 == add_2_2_12) + { + insn1 = addis_2_12 + ha(value); + elfcpp::Swap<32, big_endian>::writeval(iview, insn1); + insn2 = addi_2_2 + l(value); + elfcpp::Swap<32, big_endian>::writeval(iview + 1, insn2); + return true; + } + } + } + break; } } |