| OLD | NEW |
| (Empty) |
| 1 commit ee8713f5cfc38be0e92d78f2afbc77d701ef189d | |
| 2 Author: Peter Collingbourne <pcc@google.com> | |
| 3 Date: Thu Dec 17 16:50:35 2015 -0800 | |
| 4 | |
| 5 Implement --long-plt flag (ARM only). | |
| 6 | |
| 7 gold/ | |
| 8 PR gold/18780 | |
| 9 * arm.cc (Target_arm::do_make_data_plt): Choose PLT generator based | |
| 10 on value of --long-plt flag. | |
| 11 (Output_data_plt_arm_standard::do_get_plt_entry_size): Moved to | |
| 12 Output_data_plt_arm_short. | |
| 13 (Output_data_plt_arm_standard::do_fill_plt_entry): Likewise. | |
| 14 (Output_data_plt_arm_standard::plt_entry): Likewise. | |
| 15 (Output_data_plt_arm_standard::do_fill_first_plt_entry): Fix | |
| 16 variable reference. | |
| 17 (Output_data_plt_arm_short): New class. | |
| 18 (Output_data_plt_arm_short::do_fill_plt_entry): Error out on too large | |
| 19 PLT offsets instead of asserting. | |
| 20 (Output_data_plt_arm_long): New class. | |
| 21 * options.h (General_options): Define --long-plt flag. | |
| 22 | |
| 23 diff --git a/gold/arm.cc b/gold/arm.cc | |
| 24 index 6c472bb..a10d785 100644 | |
| 25 --- a/gold/arm.cc | |
| 26 +++ b/gold/arm.cc | |
| 27 @@ -62,7 +62,10 @@ template<bool big_endian> | |
| 28 class Output_data_plt_arm; | |
| 29 | |
| 30 template<bool big_endian> | |
| 31 -class Output_data_plt_arm_standard; | |
| 32 +class Output_data_plt_arm_short; | |
| 33 + | |
| 34 +template<bool big_endian> | |
| 35 +class Output_data_plt_arm_long; | |
| 36 | |
| 37 template<bool big_endian> | |
| 38 class Stub_table; | |
| 39 @@ -2532,7 +2535,12 @@ class Target_arm : public Sized_target<32, big_endian> | |
| 40 virtual Output_data_plt_arm<big_endian>* | |
| 41 do_make_data_plt(Layout* layout, Output_data_space* got_plt) | |
| 42 { | |
| 43 - return new Output_data_plt_arm_standard<big_endian>(layout, got_plt); | |
| 44 + if (parameters->options().long_plt()) | |
| 45 + return new Output_data_plt_arm_long<big_endian>( | |
| 46 + layout, got_plt); | |
| 47 + else | |
| 48 + return new Output_data_plt_arm_short<big_endian>( | |
| 49 + layout, got_plt); | |
| 50 } | |
| 51 | |
| 52 private: | |
| 53 @@ -7382,29 +7390,14 @@ class Output_data_plt_arm_standard : public Output_data_
plt_arm<big_endian> | |
| 54 do_first_plt_entry_offset() const | |
| 55 { return sizeof(first_plt_entry); } | |
| 56 | |
| 57 - // Return the size of a PLT entry. | |
| 58 - virtual unsigned int | |
| 59 - do_get_plt_entry_size() const | |
| 60 - { return sizeof(plt_entry); } | |
| 61 - | |
| 62 virtual void | |
| 63 do_fill_first_plt_entry(unsigned char* pov, | |
| 64 Arm_address got_address, | |
| 65 Arm_address plt_address); | |
| 66 | |
| 67 - virtual void | |
| 68 - do_fill_plt_entry(unsigned char* pov, | |
| 69 - Arm_address got_address, | |
| 70 - Arm_address plt_address, | |
| 71 - unsigned int got_offset, | |
| 72 - unsigned int plt_offset); | |
| 73 - | |
| 74 private: | |
| 75 // Template for the first PLT entry. | |
| 76 static const uint32_t first_plt_entry[5]; | |
| 77 - | |
| 78 - // Template for subsequent PLT entries. | |
| 79 - static const uint32_t plt_entry[3]; | |
| 80 }; | |
| 81 | |
| 82 // ARM PLTs. | |
| 83 @@ -7432,7 +7425,7 @@ Output_data_plt_arm_standard<big_endian>::do_fill_first_pl
t_entry( | |
| 84 { | |
| 85 // Write first PLT entry. All but the last word are constants. | |
| 86 const size_t num_first_plt_words = (sizeof(first_plt_entry) | |
| 87 - / sizeof(plt_entry[0])); | |
| 88 + / sizeof(first_plt_entry[0])); | |
| 89 for (size_t i = 0; i < num_first_plt_words - 1; i++) | |
| 90 elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]); | |
| 91 // Last word in first PLT entry is &GOT[0] - . | |
| 92 @@ -7441,9 +7434,37 @@ Output_data_plt_arm_standard<big_endian>::do_fill_first_p
lt_entry( | |
| 93 } | |
| 94 | |
| 95 // Subsequent entries in the PLT. | |
| 96 +// This class generates short (12-byte) entries, for displacements up to 2^28. | |
| 97 + | |
| 98 +template<bool big_endian> | |
| 99 +class Output_data_plt_arm_short : public Output_data_plt_arm_standard<big_endia
n> | |
| 100 +{ | |
| 101 + public: | |
| 102 + Output_data_plt_arm_short(Layout* layout, | |
| 103 + Output_data_space* got_plt) | |
| 104 + : Output_data_plt_arm_standard<big_endian>(layout, got_plt) | |
| 105 + { } | |
| 106 + | |
| 107 + protected: | |
| 108 + // Return the size of a PLT entry. | |
| 109 + virtual unsigned int | |
| 110 + do_get_plt_entry_size() const | |
| 111 + { return sizeof(plt_entry); } | |
| 112 + | |
| 113 + virtual void | |
| 114 + do_fill_plt_entry(unsigned char* pov, | |
| 115 + Arm_address got_address, | |
| 116 + Arm_address plt_address, | |
| 117 + unsigned int got_offset, | |
| 118 + unsigned int plt_offset); | |
| 119 + | |
| 120 + private: | |
| 121 + // Template for subsequent PLT entries. | |
| 122 + static const uint32_t plt_entry[3]; | |
| 123 +}; | |
| 124 | |
| 125 template<bool big_endian> | |
| 126 -const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] = | |
| 127 +const uint32_t Output_data_plt_arm_short<big_endian>::plt_entry[3] = | |
| 128 { | |
| 129 0xe28fc600, // add ip, pc, #0xNN00000 | |
| 130 0xe28cca00, // add ip, ip, #0xNN000 | |
| 131 @@ -7452,7 +7473,7 @@ const uint32_t Output_data_plt_arm_standard<big_endian>::p
lt_entry[3] = | |
| 132 | |
| 133 template<bool big_endian> | |
| 134 void | |
| 135 -Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry( | |
| 136 +Output_data_plt_arm_short<big_endian>::do_fill_plt_entry( | |
| 137 unsigned char* pov, | |
| 138 Arm_address got_address, | |
| 139 Arm_address plt_address, | |
| 140 @@ -7461,8 +7482,9 @@ Output_data_plt_arm_standard<big_endian>::do_fill_plt_entr
y( | |
| 141 { | |
| 142 int32_t offset = ((got_address + got_offset) | |
| 143 - (plt_address + plt_offset + 8)); | |
| 144 + if (offset < 0 || offset > 0x0fffffff) | |
| 145 + gold_error(_("PLT offset too large, try linking with --long-plt")); | |
| 146 | |
| 147 - gold_assert(offset >= 0 && offset < 0x0fffffff); | |
| 148 uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff); | |
| 149 elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); | |
| 150 uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff); | |
| 151 @@ -7471,6 +7493,66 @@ Output_data_plt_arm_standard<big_endian>::do_fill_plt_ent
ry( | |
| 152 elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); | |
| 153 } | |
| 154 | |
| 155 +// This class generates long (16-byte) entries, for arbitrary displacements. | |
| 156 + | |
| 157 +template<bool big_endian> | |
| 158 +class Output_data_plt_arm_long : public Output_data_plt_arm_standard<big_endian
> | |
| 159 +{ | |
| 160 + public: | |
| 161 + Output_data_plt_arm_long(Layout* layout, | |
| 162 + Output_data_space* got_plt) | |
| 163 + : Output_data_plt_arm_standard<big_endian>(layout, got_plt) | |
| 164 + { } | |
| 165 + | |
| 166 + protected: | |
| 167 + // Return the size of a PLT entry. | |
| 168 + virtual unsigned int | |
| 169 + do_get_plt_entry_size() const | |
| 170 + { return sizeof(plt_entry); } | |
| 171 + | |
| 172 + virtual void | |
| 173 + do_fill_plt_entry(unsigned char* pov, | |
| 174 + Arm_address got_address, | |
| 175 + Arm_address plt_address, | |
| 176 + unsigned int got_offset, | |
| 177 + unsigned int plt_offset); | |
| 178 + | |
| 179 + private: | |
| 180 + // Template for subsequent PLT entries. | |
| 181 + static const uint32_t plt_entry[4]; | |
| 182 +}; | |
| 183 + | |
| 184 +template<bool big_endian> | |
| 185 +const uint32_t Output_data_plt_arm_long<big_endian>::plt_entry[4] = | |
| 186 +{ | |
| 187 + 0xe28fc200, // add ip, pc, #0xN0000000 | |
| 188 + 0xe28cc600, // add ip, ip, #0xNN00000 | |
| 189 + 0xe28cca00, // add ip, ip, #0xNN000 | |
| 190 + 0xe5bcf000, // ldr pc, [ip, #0xNNN]! | |
| 191 +}; | |
| 192 + | |
| 193 +template<bool big_endian> | |
| 194 +void | |
| 195 +Output_data_plt_arm_long<big_endian>::do_fill_plt_entry( | |
| 196 + unsigned char* pov, | |
| 197 + Arm_address got_address, | |
| 198 + Arm_address plt_address, | |
| 199 + unsigned int got_offset, | |
| 200 + unsigned int plt_offset) | |
| 201 +{ | |
| 202 + int32_t offset = ((got_address + got_offset) | |
| 203 + - (plt_address + plt_offset + 8)); | |
| 204 + | |
| 205 + uint32_t plt_insn0 = plt_entry[0] | (offset >> 28); | |
| 206 + elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); | |
| 207 + uint32_t plt_insn1 = plt_entry[1] | ((offset >> 20) & 0xff); | |
| 208 + elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); | |
| 209 + uint32_t plt_insn2 = plt_entry[2] | ((offset >> 12) & 0xff); | |
| 210 + elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); | |
| 211 + uint32_t plt_insn3 = plt_entry[3] | (offset & 0xfff); | |
| 212 + elfcpp::Swap<32, big_endian>::writeval(pov + 12, plt_insn3); | |
| 213 +} | |
| 214 + | |
| 215 // Write out the PLT. This uses the hand-coded instructions above, | |
| 216 // and adjusts them as needed. This is all specified by the arm ELF | |
| 217 // Processor Supplement. | |
| 218 diff --git a/gold/options.h b/gold/options.h | |
| 219 index cf3b705..5bd93b1e 100644 | |
| 220 --- a/gold/options.h | |
| 221 +++ b/gold/options.h | |
| 222 @@ -826,6 +826,10 @@ class General_options | |
| 223 "veneer"), | |
| 224 NULL); | |
| 225 | |
| 226 + DEFINE_bool(long_plt, options::TWO_DASHES, '\0', false, | |
| 227 + N_("(ARM only) Generate long PLT entries"), | |
| 228 + N_("(ARM only) Do not generate long PLT entries")); | |
| 229 + | |
| 230 DEFINE_bool(g, options::EXACTLY_ONE_DASH, '\0', false, | |
| 231 N_("Ignored"), NULL); | |
| 232 | |
| OLD | NEW |