* [PATCH] gold: Implement --long-plt flag.
@ 2015-11-20 23:46 Peter Collingbourne
2015-12-02 18:17 ` Peter Collingbourne
2015-12-17 0:42 ` Cary Coutant
0 siblings, 2 replies; 6+ messages in thread
From: Peter Collingbourne @ 2015-11-20 23:46 UTC (permalink / raw)
To: binutils; +Cc: Peter Collingbourne
gold/
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_long): New class.
* options.h (General_options): Define --long-plt flag.
---
gold/arm.cc | 124 +++++++++++++++++++++++++++++++++++++++++++++++----------
gold/options.h | 4 ++
2 files changed, 108 insertions(+), 20 deletions(-)
diff --git a/gold/arm.cc b/gold/arm.cc
index 4a6d414..2381442 100644
--- a/gold/arm.cc
+++ b/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;
@@ -2555,7 +2558,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);
}
@@ -7719,29 +7726,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.
@@ -7769,7 +7761,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] - .
@@ -7778,9 +7770,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
@@ -7789,7 +7811,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,
@@ -7808,6 +7830,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/gold/options.h b/gold/options.h
index ffc44e6..d83ea54 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -834,6 +834,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);
--
2.6.0.rc2.230.g3dd15c0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] gold: Implement --long-plt flag.
2015-11-20 23:46 [PATCH] gold: Implement --long-plt flag Peter Collingbourne
@ 2015-12-02 18:17 ` Peter Collingbourne
2015-12-14 18:28 ` Peter Collingbourne
2015-12-17 0:42 ` Cary Coutant
1 sibling, 1 reply; 6+ messages in thread
From: Peter Collingbourne @ 2015-12-02 18:17 UTC (permalink / raw)
To: binutils; +Cc: ccoutant
Ping.
On Fri, Nov 20, 2015 at 3:45 PM, Peter Collingbourne <pcc@google.com> wrote:
> gold/
> 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_long): New class.
> * options.h (General_options): Define --long-plt flag.
> ---
> gold/arm.cc | 124 +++++++++++++++++++++++++++++++++++++++++++++++----------
> gold/options.h | 4 ++
> 2 files changed, 108 insertions(+), 20 deletions(-)
>
> diff --git a/gold/arm.cc b/gold/arm.cc
> index 4a6d414..2381442 100644
> --- a/gold/arm.cc
> +++ b/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;
> @@ -2555,7 +2558,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);
> }
>
> @@ -7719,29 +7726,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.
> @@ -7769,7 +7761,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] - .
> @@ -7778,9 +7770,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
> @@ -7789,7 +7811,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,
> @@ -7808,6 +7830,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/gold/options.h b/gold/options.h
> index ffc44e6..d83ea54 100644
> --- a/gold/options.h
> +++ b/gold/options.h
> @@ -834,6 +834,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);
>
> --
> 2.6.0.rc2.230.g3dd15c0
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] gold: Implement --long-plt flag.
2015-12-02 18:17 ` Peter Collingbourne
@ 2015-12-14 18:28 ` Peter Collingbourne
0 siblings, 0 replies; 6+ messages in thread
From: Peter Collingbourne @ 2015-12-14 18:28 UTC (permalink / raw)
To: binutils; +Cc: Cary Coutant
Ping^2.
On Wed, Dec 2, 2015 at 10:17 AM, Peter Collingbourne <pcc@google.com> wrote:
> Ping.
>
> On Fri, Nov 20, 2015 at 3:45 PM, Peter Collingbourne <pcc@google.com> wrote:
>> gold/
>> 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_long): New class.
>> * options.h (General_options): Define --long-plt flag.
>> ---
>> gold/arm.cc | 124 +++++++++++++++++++++++++++++++++++++++++++++++----------
>> gold/options.h | 4 ++
>> 2 files changed, 108 insertions(+), 20 deletions(-)
>>
>> diff --git a/gold/arm.cc b/gold/arm.cc
>> index 4a6d414..2381442 100644
>> --- a/gold/arm.cc
>> +++ b/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;
>> @@ -2555,7 +2558,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);
>> }
>>
>> @@ -7719,29 +7726,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.
>> @@ -7769,7 +7761,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] - .
>> @@ -7778,9 +7770,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
>> @@ -7789,7 +7811,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,
>> @@ -7808,6 +7830,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/gold/options.h b/gold/options.h
>> index ffc44e6..d83ea54 100644
>> --- a/gold/options.h
>> +++ b/gold/options.h
>> @@ -834,6 +834,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);
>>
>> --
>> 2.6.0.rc2.230.g3dd15c0
>>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] gold: Implement --long-plt flag.
2015-11-20 23:46 [PATCH] gold: Implement --long-plt flag Peter Collingbourne
2015-12-02 18:17 ` Peter Collingbourne
@ 2015-12-17 0:42 ` Cary Coutant
2015-12-17 20:33 ` Peter Collingbourne
1 sibling, 1 reply; 6+ messages in thread
From: Cary Coutant @ 2015-12-17 0:42 UTC (permalink / raw)
To: Peter Collingbourne; +Cc: Binutils
> 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,
Please fix this routine to issue an error message, suggesting the use
of --long-plt, if the offset overflows the standard PLT.
> + 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."));
Help strings should not end with periods. (Yeah, there are some already there.)
This is OK with those changes.
-cary
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] gold: Implement --long-plt flag.
2015-12-17 0:42 ` Cary Coutant
@ 2015-12-17 20:33 ` Peter Collingbourne
2015-12-18 0:56 ` Cary Coutant
0 siblings, 1 reply; 6+ messages in thread
From: Peter Collingbourne @ 2015-12-17 20:33 UTC (permalink / raw)
To: Cary Coutant; +Cc: Binutils
[-- Attachment #1: Type: text/plain, Size: 863 bytes --]
On Wed, Dec 16, 2015 at 4:42 PM, Cary Coutant <ccoutant@gmail.com> wrote:
>
> > 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,
>
> Please fix this routine to issue an error message, suggesting the use
> of --long-plt, if the offset overflows the standard PLT.
>
> > + 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."));
>
> Help strings should not end with periods. (Yeah, there are some already there.)
>
> This is OK with those changes.
Thanks, new patch is attached. Can you please commit for me?
Peter
[-- Attachment #2: 0001-gold-Implement-long-plt-flag.patch --]
[-- Type: text/x-patch, Size: 8196 bytes --]
From 484be7b3ff7564f1c28c2058eb30015a5246267d Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <pcc@google.com>
Date: Thu, 19 Nov 2015 18:47:39 -0800
Subject: [PATCH] gold: Implement --long-plt flag.
gold/
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.
---
gold/arm.cc | 127 +++++++++++++++++++++++++++++++++++++++++++++++----------
gold/options.h | 4 ++
2 files changed, 110 insertions(+), 21 deletions(-)
diff --git a/gold/arm.cc b/gold/arm.cc
index 33e8734..fc387bb 100644
--- a/gold/arm.cc
+++ b/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;
@@ -2554,7 +2557,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);
}
@@ -7715,29 +7722,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.
@@ -7765,7 +7757,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] - .
@@ -7774,9 +7766,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
@@ -7785,7 +7807,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,
@@ -7794,8 +7816,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);
@@ -7804,6 +7827,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/gold/options.h b/gold/options.h
index ffc44e6..8b5159f 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -834,6 +834,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);
--
2.6.0.rc2.230.g3dd15c0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] gold: Implement --long-plt flag.
2015-12-17 20:33 ` Peter Collingbourne
@ 2015-12-18 0:56 ` Cary Coutant
0 siblings, 0 replies; 6+ messages in thread
From: Cary Coutant @ 2015-12-18 0:56 UTC (permalink / raw)
To: Peter Collingbourne; +Cc: Binutils
> Thanks, new patch is attached. Can you please commit for me?
Committed.
-cary
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-12-18 0:56 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-20 23:46 [PATCH] gold: Implement --long-plt flag Peter Collingbourne
2015-12-02 18:17 ` Peter Collingbourne
2015-12-14 18:28 ` Peter Collingbourne
2015-12-17 0:42 ` Cary Coutant
2015-12-17 20:33 ` Peter Collingbourne
2015-12-18 0:56 ` Cary Coutant
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).