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 |