diff options
Diffstat (limited to 'binutils-2.25')
-rw-r--r-- | binutils-2.25/gold/ChangeLog | 17 | ||||
-rw-r--r-- | binutils-2.25/gold/arm.cc | 127 | ||||
-rw-r--r-- | binutils-2.25/gold/options.h | 4 |
3 files changed, 127 insertions, 21 deletions
diff --git a/binutils-2.25/gold/ChangeLog b/binutils-2.25/gold/ChangeLog index 2ba3b2b..aa93c36 100644 --- a/binutils-2.25/gold/ChangeLog +++ b/binutils-2.25/gold/ChangeLog @@ -1,3 +1,20 @@ +2015-12-17 Peter Collingbourne <pcc@google.com> + + PR gold/18780 + * arm.cc (Target_arm::do_make_data_plt): Choose PLT generator based + on value of --long-plt flag. + (Output_data_plt_arm_standard::do_get_plt_entry_size): Moved to + Output_data_plt_arm_short. + (Output_data_plt_arm_standard::do_fill_plt_entry): Likewise. + (Output_data_plt_arm_standard::plt_entry): Likewise. + (Output_data_plt_arm_standard::do_fill_first_plt_entry): Fix + variable reference. + (Output_data_plt_arm_short): New class. + (Output_data_plt_arm_short::do_fill_plt_entry): Error out on too large + PLT offsets instead of asserting. + (Output_data_plt_arm_long): New class. + * options.h (General_options): Define --long-plt flag. + 2016-01-15 Han Shen <shenhan@google.com> PR gold/19472 - need pc-relative stubs. diff --git a/binutils-2.25/gold/arm.cc b/binutils-2.25/gold/arm.cc index 86920c4..94149d6 100644 --- a/binutils-2.25/gold/arm.cc +++ b/binutils-2.25/gold/arm.cc @@ -62,7 +62,10 @@ template<bool big_endian> class Output_data_plt_arm; template<bool big_endian> -class Output_data_plt_arm_standard; +class Output_data_plt_arm_short; + +template<bool big_endian> +class Output_data_plt_arm_long; template<bool big_endian> class Stub_table; @@ -2558,7 +2561,11 @@ class Target_arm : public Sized_target<32, big_endian> Output_data_space* got_irelative) { gold_assert(got_plt != NULL && got_irelative != NULL); - return new Output_data_plt_arm_standard<big_endian>( + if (parameters->options().long_plt()) + return new Output_data_plt_arm_long<big_endian>( + layout, got, got_plt, got_irelative); + else + return new Output_data_plt_arm_short<big_endian>( layout, got, got_plt, got_irelative); } @@ -7777,29 +7784,14 @@ class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian> do_first_plt_entry_offset() const { return sizeof(first_plt_entry); } - // Return the size of a PLT entry. - virtual unsigned int - do_get_plt_entry_size() const - { return sizeof(plt_entry); } - virtual void do_fill_first_plt_entry(unsigned char* pov, Arm_address got_address, Arm_address plt_address); - virtual void - do_fill_plt_entry(unsigned char* pov, - Arm_address got_address, - Arm_address plt_address, - unsigned int got_offset, - unsigned int plt_offset); - private: // Template for the first PLT entry. static const uint32_t first_plt_entry[5]; - - // Template for subsequent PLT entries. - static const uint32_t plt_entry[3]; }; // ARM PLTs. @@ -7827,7 +7819,7 @@ Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry( { // Write first PLT entry. All but the last word are constants. const size_t num_first_plt_words = (sizeof(first_plt_entry) - / sizeof(plt_entry[0])); + / sizeof(first_plt_entry[0])); for (size_t i = 0; i < num_first_plt_words - 1; i++) elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]); // Last word in first PLT entry is &GOT[0] - . @@ -7836,9 +7828,39 @@ Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry( } // Subsequent entries in the PLT. +// This class generates short (12-byte) entries, for displacements up to 2^28. template<bool big_endian> -const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] = +class Output_data_plt_arm_short : public Output_data_plt_arm_standard<big_endian> +{ + public: + Output_data_plt_arm_short(Layout* layout, + Arm_output_data_got<big_endian>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_arm_standard<big_endian>(layout, got, got_plt, got_irelative) + { } + + protected: + // Return the size of a PLT entry. + virtual unsigned int + do_get_plt_entry_size() const + { return sizeof(plt_entry); } + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset); + + private: + // Template for subsequent PLT entries. + static const uint32_t plt_entry[3]; +}; + +template<bool big_endian> +const uint32_t Output_data_plt_arm_short<big_endian>::plt_entry[3] = { 0xe28fc600, // add ip, pc, #0xNN00000 0xe28cca00, // add ip, ip, #0xNN000 @@ -7847,7 +7869,7 @@ const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] = template<bool big_endian> void -Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry( +Output_data_plt_arm_short<big_endian>::do_fill_plt_entry( unsigned char* pov, Arm_address got_address, Arm_address plt_address, @@ -7856,8 +7878,9 @@ Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry( { int32_t offset = ((got_address + got_offset) - (plt_address + plt_offset + 8)); + if (offset < 0 || offset > 0x0fffffff) + gold_error(_("PLT offset too large, try linking with --long-plt")); - gold_assert(offset >= 0 && offset < 0x0fffffff); uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff); elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff); @@ -7866,6 +7889,68 @@ Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry( elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); } +// This class generates long (16-byte) entries, for arbitrary displacements. + +template<bool big_endian> +class Output_data_plt_arm_long : public Output_data_plt_arm_standard<big_endian> +{ + public: + Output_data_plt_arm_long(Layout* layout, + Arm_output_data_got<big_endian>* got, + Output_data_space* got_plt, + Output_data_space* got_irelative) + : Output_data_plt_arm_standard<big_endian>(layout, got, got_plt, got_irelative) + { } + + protected: + // Return the size of a PLT entry. + virtual unsigned int + do_get_plt_entry_size() const + { return sizeof(plt_entry); } + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset); + + private: + // Template for subsequent PLT entries. + static const uint32_t plt_entry[4]; +}; + +template<bool big_endian> +const uint32_t Output_data_plt_arm_long<big_endian>::plt_entry[4] = +{ + 0xe28fc200, // add ip, pc, #0xN0000000 + 0xe28cc600, // add ip, ip, #0xNN00000 + 0xe28cca00, // add ip, ip, #0xNN000 + 0xe5bcf000, // ldr pc, [ip, #0xNNN]! +}; + +template<bool big_endian> +void +Output_data_plt_arm_long<big_endian>::do_fill_plt_entry( + unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset) +{ + int32_t offset = ((got_address + got_offset) + - (plt_address + plt_offset + 8)); + + uint32_t plt_insn0 = plt_entry[0] | (offset >> 28); + elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); + uint32_t plt_insn1 = plt_entry[1] | ((offset >> 20) & 0xff); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); + uint32_t plt_insn2 = plt_entry[2] | ((offset >> 12) & 0xff); + elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); + uint32_t plt_insn3 = plt_entry[3] | (offset & 0xfff); + elfcpp::Swap<32, big_endian>::writeval(pov + 12, plt_insn3); +} + // Write out the PLT. This uses the hand-coded instructions above, // and adjusts them as needed. This is all specified by the arm ELF // Processor Supplement. diff --git a/binutils-2.25/gold/options.h b/binutils-2.25/gold/options.h index db5254b..0fa26f1 100644 --- a/binutils-2.25/gold/options.h +++ b/binutils-2.25/gold/options.h @@ -841,6 +841,10 @@ class General_options "veneer"), NULL); + DEFINE_bool(long_plt, options::TWO_DASHES, '\0', false, + N_("(ARM only) Generate long PLT entries"), + N_("(ARM only) Do not generate long PLT entries")); + DEFINE_bool(g, options::EXACTLY_ONE_DASH, '\0', false, N_("Ignored"), NULL); |