Commit | Line | Data |
---|---|---|
14bfc3f5 ILT |
1 | // i386.cc -- i386 target support for gold. |
2 | ||
3 | #include "gold.h" | |
4 | #include "elfcpp.h" | |
92e059d8 | 5 | #include "reloc.h" |
61ba1cf9 ILT |
6 | #include "i386.h" |
7 | #include "object.h" | |
92e059d8 ILT |
8 | #include "layout.h" |
9 | #include "output.h" | |
14bfc3f5 | 10 | #include "target.h" |
61ba1cf9 | 11 | #include "target-reloc.h" |
14bfc3f5 ILT |
12 | #include "target-select.h" |
13 | ||
14 | namespace | |
15 | { | |
16 | ||
17 | using namespace gold; | |
18 | ||
19 | // The i386 target class. | |
20 | ||
21 | class Target_i386 : public Sized_target<32, false> | |
22 | { | |
23 | public: | |
24 | Target_i386() | |
75f65a3e | 25 | : Sized_target<32, false>(&i386_info) |
14bfc3f5 | 26 | { } |
75f65a3e | 27 | |
92e059d8 | 28 | // Scan the relocations to look for symbol adjustments. |
61ba1cf9 | 29 | void |
92e059d8 ILT |
30 | scan_relocs(const General_options& options, |
31 | Symbol_table* symtab, | |
32 | Sized_object<32, false>* object, | |
33 | unsigned int sh_type, | |
34 | const unsigned char* prelocs, | |
35 | size_t reloc_count, | |
36 | size_t local_symbol_count, | |
37 | const unsigned char* plocal_symbols, | |
38 | Symbol** global_symbols); | |
61ba1cf9 | 39 | |
92e059d8 ILT |
40 | // Relocate a section. |
41 | void | |
42 | relocate_section(const Relocate_info<32, false>*, | |
43 | unsigned int sh_type, | |
44 | const unsigned char* prelocs, | |
45 | size_t reloc_count, | |
46 | unsigned char* view, | |
47 | elfcpp::Elf_types<32>::Elf_Addr view_address, | |
48 | off_t view_size); | |
49 | ||
50 | private: | |
51 | // The class which scans relocations. | |
52 | struct Scan | |
61ba1cf9 ILT |
53 | { |
54 | inline void | |
92e059d8 ILT |
55 | local(const General_options& options, Sized_object<32, false>* object, |
56 | const elfcpp::Rel<32, false>& reloc, unsigned int r_type, | |
57 | const elfcpp::Sym<32, false>& lsym); | |
61ba1cf9 | 58 | |
92e059d8 ILT |
59 | inline void |
60 | global(const General_options& options, Sized_object<32, false>* object, | |
61 | const elfcpp::Rel<32, false>& reloc, unsigned int r_type, | |
62 | Symbol* gsym); | |
61ba1cf9 ILT |
63 | }; |
64 | ||
92e059d8 ILT |
65 | // The class which implements relocation. |
66 | class Relocate | |
67 | { | |
68 | public: | |
69 | // Do a relocation. | |
70 | static inline void | |
71 | relocate(const Relocate_info<32, false>*, size_t relnum, | |
72 | const elfcpp::Rel<32, false>&, | |
73 | unsigned int r_type, Sized_symbol<32>*, | |
74 | elfcpp::Elf_types<32>::Elf_Addr, | |
75 | unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, | |
76 | off_t); | |
77 | ||
78 | private: | |
79 | // Do a TLS relocation. | |
80 | static inline void | |
81 | relocate_tls(const Relocate_info<32, false>*, size_t relnum, | |
82 | const elfcpp::Rel<32, false>&, | |
83 | unsigned int r_type, Sized_symbol<32>*, | |
84 | elfcpp::Elf_types<32>::Elf_Addr, | |
85 | unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); | |
86 | ||
87 | // Do a TLS Initial-Exec to Local-Exec transition. | |
88 | static inline void | |
89 | tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum, | |
90 | Output_segment* tls_segment, | |
91 | const elfcpp::Rel<32, false>&, unsigned int r_type, | |
92 | elfcpp::Elf_types<32>::Elf_Addr value, | |
93 | unsigned char* view, | |
94 | off_t view_size); | |
95 | ||
96 | // Check the range for a TLS relocation. | |
97 | static inline void | |
98 | check_range(const Relocate_info<32, false>*, size_t relnum, | |
99 | const elfcpp::Rel<32, false>&, off_t, off_t); | |
100 | ||
101 | // Check the validity of a TLS relocation. This is like assert. | |
102 | static inline void | |
103 | check_tls(const Relocate_info<32, false>*, size_t relnum, | |
104 | const elfcpp::Rel<32, false>&, bool); | |
105 | }; | |
106 | ||
107 | // Adjust TLS relocation type based on the options and whether this | |
108 | // is a local symbol. | |
109 | static unsigned int | |
110 | optimize_tls_reloc(const General_options*, bool is_local, int r_type); | |
111 | ||
112 | // Information about this specific target which we pass to the | |
113 | // general Target structure. | |
75f65a3e ILT |
114 | static const Target::Target_info i386_info; |
115 | }; | |
116 | ||
117 | const Target::Target_info Target_i386::i386_info = | |
118 | { | |
61ba1cf9 ILT |
119 | 32, // size |
120 | false, // is_big_endian | |
121 | elfcpp::EM_386, // machine_code | |
122 | false, // has_make_symbol | |
123 | false, // has_resolve, | |
124 | 0x08048000, // text_segment_address, | |
125 | 0x1000, // abi_pagesize | |
126 | 0x1000 // common_pagesize | |
14bfc3f5 ILT |
127 | }; |
128 | ||
92e059d8 ILT |
129 | // Optimize the TLS relocation type based on what we know about the |
130 | // symbol. IS_LOCAL is true if this symbol can be resolved entirely | |
131 | // locally--i.e., does not have to be in the dynamic symbol table. | |
132 | ||
133 | unsigned int | |
134 | Target_i386::optimize_tls_reloc(const General_options* options, bool is_local, | |
135 | int r_type) | |
136 | { | |
137 | // If we are generating a shared library, then we can't do anything | |
138 | // in the linker. | |
139 | if (options->is_shared()) | |
140 | return r_type; | |
141 | ||
142 | switch (r_type) | |
143 | { | |
144 | case elfcpp::R_386_TLS_GD: | |
145 | case elfcpp::R_386_TLS_GOTDESC: | |
146 | case elfcpp::R_386_TLS_DESC_CALL: | |
147 | // These are Global-Dynamic which permits fully general TLS | |
148 | // access. Since we know that we are generating an executable, | |
149 | // we can convert this to Initial-Exec. If we also know that | |
150 | // this is a local symbol, we can further switch to Local-Exec. | |
151 | if (is_local) | |
152 | return elfcpp::R_386_TLS_LE_32; | |
153 | return elfcpp::R_386_TLS_IE_32; | |
154 | ||
155 | case elfcpp::R_386_TLS_LDM: | |
156 | // This is Local-Dynamic, which refers to a local symbol in the | |
157 | // dynamic TLS block. Since we know that we generating an | |
158 | // executable, we can switch to Local-Exec. | |
159 | return elfcpp::R_386_TLS_LE_32; | |
160 | ||
161 | case elfcpp::R_386_TLS_LDO_32: | |
162 | // Another type of Local-Dynamic relocation. | |
163 | return elfcpp::R_386_TLS_LE; | |
164 | ||
165 | case elfcpp::R_386_TLS_IE: | |
166 | case elfcpp::R_386_TLS_GOTIE: | |
167 | case elfcpp::R_386_TLS_IE_32: | |
168 | // These are Initial-Exec relocs which get the thread offset | |
169 | // from the GOT. If we know that we are linking against the | |
170 | // local symbol, we can switch to Local-Exec, which links the | |
171 | // thread offset into the instruction. | |
172 | if (is_local) | |
173 | return elfcpp::R_386_TLS_LE_32; | |
174 | return r_type; | |
175 | ||
176 | case elfcpp::R_386_TLS_LE: | |
177 | case elfcpp::R_386_TLS_LE_32: | |
178 | // When we already have Local-Exec, there is nothing further we | |
179 | // can do. | |
180 | return r_type; | |
181 | ||
182 | default: | |
183 | abort(); | |
184 | } | |
185 | } | |
186 | ||
187 | // Scan a relocation for a local symbol. | |
188 | ||
189 | inline void | |
190 | Target_i386::Scan::local(const General_options& options, | |
191 | Sized_object<32, false>* object, | |
192 | const elfcpp::Rel<32, false>&, unsigned int r_type, | |
193 | const elfcpp::Sym<32, false>&) | |
194 | { | |
195 | switch (r_type) | |
196 | { | |
197 | case elfcpp::R_386_NONE: | |
198 | case elfcpp::R_386_GNU_VTINHERIT: | |
199 | case elfcpp::R_386_GNU_VTENTRY: | |
200 | break; | |
201 | ||
202 | case elfcpp::R_386_32: | |
203 | case elfcpp::R_386_16: | |
204 | case elfcpp::R_386_8: | |
205 | // FIXME: If we are generating a shared object we need to copy | |
206 | // this relocation into the object. | |
207 | break; | |
208 | ||
209 | case elfcpp::R_386_PC32: | |
210 | case elfcpp::R_386_PC16: | |
211 | case elfcpp::R_386_PC8: | |
212 | break; | |
213 | ||
214 | case elfcpp::R_386_COPY: | |
215 | case elfcpp::R_386_GLOB_DAT: | |
216 | case elfcpp::R_386_JUMP_SLOT: | |
217 | case elfcpp::R_386_RELATIVE: | |
218 | case elfcpp::R_386_TLS_TPOFF: | |
219 | case elfcpp::R_386_TLS_DTPMOD32: | |
220 | case elfcpp::R_386_TLS_DTPOFF32: | |
221 | case elfcpp::R_386_TLS_TPOFF32: | |
222 | case elfcpp::R_386_TLS_DESC: | |
223 | fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"), | |
224 | program_name, object->name().c_str(), r_type); | |
225 | gold_exit(false); | |
226 | break; | |
227 | ||
228 | case elfcpp::R_386_TLS_IE: | |
229 | case elfcpp::R_386_TLS_GOTIE: | |
230 | case elfcpp::R_386_TLS_LE: | |
231 | case elfcpp::R_386_TLS_GD: | |
232 | case elfcpp::R_386_TLS_LDM: | |
233 | case elfcpp::R_386_TLS_LDO_32: | |
234 | case elfcpp::R_386_TLS_IE_32: | |
235 | case elfcpp::R_386_TLS_LE_32: | |
236 | case elfcpp::R_386_TLS_GOTDESC: | |
237 | case elfcpp::R_386_TLS_DESC_CALL: | |
238 | r_type = Target_i386::optimize_tls_reloc(&options, true, r_type); | |
239 | switch (r_type) | |
240 | { | |
241 | case elfcpp::R_386_TLS_LE: | |
242 | case elfcpp::R_386_TLS_LE_32: | |
243 | // FIXME: If generating a shared object, we need to copy | |
244 | // this relocation into the object. | |
245 | break; | |
246 | ||
247 | case elfcpp::R_386_TLS_IE: | |
248 | case elfcpp::R_386_TLS_GOTIE: | |
249 | case elfcpp::R_386_TLS_GD: | |
250 | case elfcpp::R_386_TLS_LDM: | |
251 | case elfcpp::R_386_TLS_LDO_32: | |
252 | case elfcpp::R_386_TLS_IE_32: | |
253 | case elfcpp::R_386_TLS_GOTDESC: | |
254 | case elfcpp::R_386_TLS_DESC_CALL: | |
255 | fprintf(stderr, | |
256 | _("%s: %s: unsupported reloc %u against local symbol\n"), | |
257 | program_name, object->name().c_str(), r_type); | |
258 | break; | |
259 | } | |
260 | break; | |
261 | ||
262 | case elfcpp::R_386_GOT32: | |
263 | case elfcpp::R_386_PLT32: | |
264 | case elfcpp::R_386_GOTOFF: | |
265 | case elfcpp::R_386_GOTPC: | |
266 | case elfcpp::R_386_32PLT: | |
267 | case elfcpp::R_386_TLS_GD_32: | |
268 | case elfcpp::R_386_TLS_GD_PUSH: | |
269 | case elfcpp::R_386_TLS_GD_CALL: | |
270 | case elfcpp::R_386_TLS_GD_POP: | |
271 | case elfcpp::R_386_TLS_LDM_32: | |
272 | case elfcpp::R_386_TLS_LDM_PUSH: | |
273 | case elfcpp::R_386_TLS_LDM_CALL: | |
274 | case elfcpp::R_386_TLS_LDM_POP: | |
275 | case elfcpp::R_386_USED_BY_INTEL_200: | |
276 | default: | |
277 | fprintf(stderr, _("%s: %s: unsupported reloc %u against local symbol\n"), | |
278 | program_name, object->name().c_str(), r_type); | |
279 | break; | |
280 | } | |
281 | } | |
282 | ||
283 | // Scan a relocation for a global symbol. | |
284 | ||
285 | inline void | |
286 | Target_i386::Scan::global(const General_options& options, | |
287 | Sized_object<32, false>* object, | |
288 | const elfcpp::Rel<32, false>&, unsigned int r_type, | |
289 | Symbol* gsym) | |
290 | { | |
291 | switch (r_type) | |
292 | { | |
293 | case elfcpp::R_386_NONE: | |
294 | case elfcpp::R_386_GNU_VTINHERIT: | |
295 | case elfcpp::R_386_GNU_VTENTRY: | |
296 | break; | |
297 | ||
298 | case elfcpp::R_386_32: | |
299 | case elfcpp::R_386_PC32: | |
300 | case elfcpp::R_386_16: | |
301 | case elfcpp::R_386_PC16: | |
302 | case elfcpp::R_386_8: | |
303 | case elfcpp::R_386_PC8: | |
304 | // FIXME: If we are generating a shared object we may need to | |
305 | // copy this relocation into the object. If this symbol is | |
306 | // defined in a shared object, we may need to copy this | |
307 | // relocation in order to avoid a COPY relocation. | |
308 | break; | |
309 | ||
310 | case elfcpp::R_386_COPY: | |
311 | case elfcpp::R_386_GLOB_DAT: | |
312 | case elfcpp::R_386_JUMP_SLOT: | |
313 | case elfcpp::R_386_RELATIVE: | |
314 | case elfcpp::R_386_TLS_TPOFF: | |
315 | case elfcpp::R_386_TLS_DTPMOD32: | |
316 | case elfcpp::R_386_TLS_DTPOFF32: | |
317 | case elfcpp::R_386_TLS_TPOFF32: | |
318 | case elfcpp::R_386_TLS_DESC: | |
319 | fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"), | |
320 | program_name, object->name().c_str(), r_type); | |
321 | gold_exit(false); | |
322 | break; | |
323 | ||
324 | case elfcpp::R_386_TLS_IE: | |
325 | case elfcpp::R_386_TLS_GOTIE: | |
326 | case elfcpp::R_386_TLS_LE: | |
327 | case elfcpp::R_386_TLS_GD: | |
328 | case elfcpp::R_386_TLS_LDM: | |
329 | case elfcpp::R_386_TLS_LDO_32: | |
330 | case elfcpp::R_386_TLS_IE_32: | |
331 | case elfcpp::R_386_TLS_LE_32: | |
332 | case elfcpp::R_386_TLS_GOTDESC: | |
333 | case elfcpp::R_386_TLS_DESC_CALL: | |
334 | r_type = Target_i386::optimize_tls_reloc(&options, | |
335 | !gsym->in_dynsym(), | |
336 | r_type); | |
337 | switch (r_type) | |
338 | { | |
339 | case elfcpp::R_386_TLS_LE: | |
340 | case elfcpp::R_386_TLS_LE_32: | |
341 | // FIXME: If generating a shared object, we need to copy | |
342 | // this relocation into the object. | |
343 | break; | |
344 | ||
345 | case elfcpp::R_386_TLS_IE: | |
346 | case elfcpp::R_386_TLS_GOTIE: | |
347 | case elfcpp::R_386_TLS_GD: | |
348 | case elfcpp::R_386_TLS_LDM: | |
349 | case elfcpp::R_386_TLS_LDO_32: | |
350 | case elfcpp::R_386_TLS_IE_32: | |
351 | case elfcpp::R_386_TLS_GOTDESC: | |
352 | case elfcpp::R_386_TLS_DESC_CALL: | |
353 | fprintf(stderr, | |
354 | _("%s: %s: unsupported reloc %u against global symbol %s\n"), | |
355 | program_name, object->name().c_str(), r_type, gsym->name()); | |
356 | break; | |
357 | } | |
358 | break; | |
359 | ||
360 | case elfcpp::R_386_GOT32: | |
361 | case elfcpp::R_386_PLT32: | |
362 | case elfcpp::R_386_GOTOFF: | |
363 | case elfcpp::R_386_GOTPC: | |
364 | case elfcpp::R_386_32PLT: | |
365 | case elfcpp::R_386_TLS_GD_32: | |
366 | case elfcpp::R_386_TLS_GD_PUSH: | |
367 | case elfcpp::R_386_TLS_GD_CALL: | |
368 | case elfcpp::R_386_TLS_GD_POP: | |
369 | case elfcpp::R_386_TLS_LDM_32: | |
370 | case elfcpp::R_386_TLS_LDM_PUSH: | |
371 | case elfcpp::R_386_TLS_LDM_CALL: | |
372 | case elfcpp::R_386_TLS_LDM_POP: | |
373 | case elfcpp::R_386_USED_BY_INTEL_200: | |
374 | default: | |
375 | fprintf(stderr, | |
376 | _("%s: %s: unsupported reloc %u against global symbol %s\n"), | |
377 | program_name, object->name().c_str(), r_type, gsym->name()); | |
378 | break; | |
379 | } | |
380 | } | |
381 | ||
382 | // Scan relocations for a section. | |
383 | ||
384 | void | |
385 | Target_i386::scan_relocs(const General_options& options, | |
386 | Symbol_table* symtab, | |
387 | Sized_object<32, false>* object, | |
388 | unsigned int sh_type, | |
389 | const unsigned char* prelocs, | |
390 | size_t reloc_count, | |
391 | size_t local_symbol_count, | |
392 | const unsigned char* plocal_symbols, | |
393 | Symbol** global_symbols) | |
394 | { | |
395 | if (sh_type == elfcpp::SHT_RELA) | |
396 | { | |
397 | fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"), | |
398 | program_name, object->name().c_str()); | |
399 | gold_exit(false); | |
400 | } | |
401 | ||
402 | gold::scan_relocs<32, false, elfcpp::SHT_REL, Target_i386::Scan>( | |
403 | options, | |
404 | symtab, | |
405 | object, | |
406 | prelocs, | |
407 | reloc_count, | |
408 | local_symbol_count, | |
409 | plocal_symbols, | |
410 | global_symbols); | |
411 | } | |
412 | ||
61ba1cf9 ILT |
413 | // Perform a relocation. |
414 | ||
415 | inline void | |
92e059d8 ILT |
416 | Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, |
417 | size_t relnum, | |
418 | const elfcpp::Rel<32, false>& rel, | |
419 | unsigned int r_type, | |
420 | Sized_symbol<32>* gsym, | |
421 | elfcpp::Elf_types<32>::Elf_Addr value, | |
422 | unsigned char* view, | |
423 | elfcpp::Elf_types<32>::Elf_Addr address, | |
424 | off_t view_size) | |
61ba1cf9 ILT |
425 | { |
426 | switch (r_type) | |
427 | { | |
428 | case elfcpp::R_386_NONE: | |
92e059d8 ILT |
429 | case elfcpp::R_386_GNU_VTINHERIT: |
430 | case elfcpp::R_386_GNU_VTENTRY: | |
61ba1cf9 ILT |
431 | break; |
432 | ||
433 | case elfcpp::R_386_32: | |
92e059d8 | 434 | Relocate_functions<32, false>::rel32(view, value); |
61ba1cf9 ILT |
435 | break; |
436 | ||
437 | case elfcpp::R_386_PC32: | |
92e059d8 ILT |
438 | Relocate_functions<32, false>::pcrel32(view, value, address); |
439 | break; | |
440 | ||
441 | case elfcpp::R_386_16: | |
442 | Relocate_functions<32, false>::rel16(view, value); | |
443 | break; | |
444 | ||
445 | case elfcpp::R_386_PC16: | |
446 | Relocate_functions<32, false>::pcrel16(view, value, address); | |
61ba1cf9 ILT |
447 | break; |
448 | ||
92e059d8 ILT |
449 | case elfcpp::R_386_8: |
450 | Relocate_functions<32, false>::rel8(view, value); | |
451 | break; | |
452 | ||
453 | case elfcpp::R_386_PC8: | |
454 | Relocate_functions<32, false>::pcrel8(view, value, address); | |
455 | break; | |
456 | ||
457 | case elfcpp::R_386_COPY: | |
458 | case elfcpp::R_386_GLOB_DAT: | |
459 | case elfcpp::R_386_JUMP_SLOT: | |
460 | case elfcpp::R_386_RELATIVE: | |
461 | case elfcpp::R_386_TLS_TPOFF: | |
462 | case elfcpp::R_386_TLS_DTPMOD32: | |
463 | case elfcpp::R_386_TLS_DTPOFF32: | |
464 | case elfcpp::R_386_TLS_TPOFF32: | |
465 | case elfcpp::R_386_TLS_DESC: | |
466 | fprintf(stderr, _("%s: %s: unexpected reloc %u in object file\n"), | |
467 | program_name, | |
468 | relinfo->location(relnum, rel.get_r_offset()).c_str(), | |
469 | r_type); | |
470 | gold_exit(false); | |
471 | break; | |
472 | ||
473 | case elfcpp::R_386_TLS_IE: | |
474 | case elfcpp::R_386_TLS_GOTIE: | |
475 | case elfcpp::R_386_TLS_LE: | |
476 | case elfcpp::R_386_TLS_GD: | |
477 | case elfcpp::R_386_TLS_LDM: | |
478 | case elfcpp::R_386_TLS_LDO_32: | |
479 | case elfcpp::R_386_TLS_IE_32: | |
480 | case elfcpp::R_386_TLS_LE_32: | |
481 | case elfcpp::R_386_TLS_GOTDESC: | |
482 | case elfcpp::R_386_TLS_DESC_CALL: | |
483 | Target_i386::Relocate::relocate_tls(relinfo, relnum, rel, r_type, | |
484 | gsym, value, view, address, | |
485 | view_size); | |
486 | break; | |
487 | ||
488 | case elfcpp::R_386_GOT32: | |
489 | case elfcpp::R_386_PLT32: | |
490 | case elfcpp::R_386_GOTOFF: | |
491 | case elfcpp::R_386_GOTPC: | |
492 | case elfcpp::R_386_32PLT: | |
493 | case elfcpp::R_386_TLS_GD_32: | |
494 | case elfcpp::R_386_TLS_GD_PUSH: | |
495 | case elfcpp::R_386_TLS_GD_CALL: | |
496 | case elfcpp::R_386_TLS_GD_POP: | |
497 | case elfcpp::R_386_TLS_LDM_32: | |
498 | case elfcpp::R_386_TLS_LDM_PUSH: | |
499 | case elfcpp::R_386_TLS_LDM_CALL: | |
500 | case elfcpp::R_386_TLS_LDM_POP: | |
501 | case elfcpp::R_386_USED_BY_INTEL_200: | |
61ba1cf9 ILT |
502 | default: |
503 | fprintf(stderr, _("%s: %s: unsupported reloc %u\n"), | |
92e059d8 ILT |
504 | program_name, |
505 | relinfo->location(relnum, rel.get_r_offset()).c_str(), | |
506 | r_type); | |
61ba1cf9 | 507 | // gold_exit(false); |
92e059d8 ILT |
508 | break; |
509 | } | |
510 | } | |
511 | ||
512 | // Perform a TLS relocation. | |
513 | ||
514 | inline void | |
515 | Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, | |
516 | size_t relnum, | |
517 | const elfcpp::Rel<32, false>& rel, | |
518 | unsigned int r_type, | |
519 | Sized_symbol<32>* gsym, | |
520 | elfcpp::Elf_types<32>::Elf_Addr value, | |
521 | unsigned char* view, | |
522 | elfcpp::Elf_types<32>::Elf_Addr, | |
523 | off_t view_size) | |
524 | { | |
525 | Output_segment* tls_segment = relinfo->layout->tls_segment(); | |
526 | if (tls_segment == NULL) | |
527 | { | |
528 | fprintf(stderr, _("%s: %s: TLS reloc but no TLS segment\n"), | |
529 | program_name, | |
530 | relinfo->location(relnum, rel.get_r_offset()).c_str()); | |
531 | gold_exit(false); | |
532 | } | |
533 | ||
534 | const bool is_local = gsym == NULL || !gsym->in_dynsym(); | |
535 | const unsigned int opt_r_type = | |
536 | Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type); | |
537 | switch (r_type) | |
538 | { | |
539 | case elfcpp::R_386_TLS_LE_32: | |
540 | value = tls_segment->vaddr() + tls_segment->memsz() - value; | |
541 | Relocate_functions<32, false>::rel32(view, value); | |
542 | break; | |
543 | ||
544 | case elfcpp::R_386_TLS_LE: | |
545 | value = value - (tls_segment->vaddr() + tls_segment->memsz()); | |
546 | Relocate_functions<32, false>::rel32(view, value); | |
547 | break; | |
548 | ||
549 | case elfcpp::R_386_TLS_IE: | |
550 | case elfcpp::R_386_TLS_GOTIE: | |
551 | case elfcpp::R_386_TLS_IE_32: | |
552 | if (opt_r_type == elfcpp::R_386_TLS_LE_32) | |
553 | { | |
554 | Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, | |
555 | rel, r_type, value, view, | |
556 | view_size); | |
557 | break; | |
558 | } | |
559 | fprintf(stderr, _("%s: %s: unsupported reloc type %u\n"), | |
560 | program_name, | |
561 | relinfo->location(relnum, rel.get_r_offset()).c_str(), | |
562 | r_type); | |
563 | // gold_exit(false); | |
564 | break; | |
565 | ||
566 | case elfcpp::R_386_TLS_GD: | |
567 | case elfcpp::R_386_TLS_LDM: | |
568 | case elfcpp::R_386_TLS_LDO_32: | |
569 | case elfcpp::R_386_TLS_GOTDESC: | |
570 | case elfcpp::R_386_TLS_DESC_CALL: | |
571 | fprintf(stderr, _("%s: %s: unsupported reloc %u\n"), | |
572 | program_name, | |
573 | relinfo->location(relnum, rel.get_r_offset()).c_str(), | |
574 | r_type); | |
575 | // gold_exit(false); | |
576 | break; | |
577 | } | |
578 | } | |
579 | ||
580 | // Do a relocation in which we convert a TLS Initial-Exec to a | |
581 | // Local-Exec. | |
582 | ||
583 | inline void | |
584 | Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, | |
585 | size_t relnum, | |
586 | Output_segment* tls_segment, | |
587 | const elfcpp::Rel<32, false>& rel, | |
588 | unsigned int r_type, | |
589 | elfcpp::Elf_types<32>::Elf_Addr value, | |
590 | unsigned char* view, | |
591 | off_t view_size) | |
592 | { | |
593 | // We have to actually change the instructions, which means that we | |
594 | // need to examine the opcodes to figure out which instruction we | |
595 | // are looking at. | |
596 | if (r_type == elfcpp::R_386_TLS_IE) | |
597 | { | |
598 | // movl %gs:XX,%eax ==> movl $YY,%eax | |
599 | // movl %gs:XX,%reg ==> movl $YY,%reg | |
600 | // addl %gs:XX,%reg ==> addl $YY,%reg | |
601 | Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -1); | |
602 | Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4); | |
603 | ||
604 | unsigned char op1 = view[-1]; | |
605 | if (op1 == 0xa1) | |
606 | { | |
607 | // movl XX,%eax ==> movl $YY,%eax | |
608 | view[-1] = 0xb8; | |
609 | } | |
610 | else | |
611 | { | |
612 | Target_i386::Relocate::check_range(relinfo, relnum, rel, | |
613 | view_size, -2); | |
614 | ||
615 | unsigned char op2 = view[-2]; | |
616 | if (op2 == 0x8b) | |
617 | { | |
618 | // movl XX,%reg ==> movl $YY,%reg | |
619 | Target_i386::Relocate::check_tls(relinfo, relnum, rel, | |
620 | (op1 & 0xc7) == 0x05); | |
621 | view[-2] = 0xc7; | |
622 | view[-1] = 0xc0 | ((op1 >> 3) & 7); | |
623 | } | |
624 | else if (op2 == 0x03) | |
625 | { | |
626 | // addl XX,%reg ==> addl $YY,%reg | |
627 | Target_i386::Relocate::check_tls(relinfo, relnum, rel, | |
628 | (op1 & 0xc7) == 0x05); | |
629 | view[-2] = 0x81; | |
630 | view[-1] = 0xc0 | ((op1 >> 3) & 7); | |
631 | } | |
632 | else | |
633 | Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0); | |
634 | } | |
635 | } | |
636 | else | |
637 | { | |
638 | // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 | |
639 | // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 | |
640 | // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 | |
641 | Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, -2); | |
642 | Target_i386::Relocate::check_range(relinfo, relnum, rel, view_size, 4); | |
643 | ||
644 | unsigned char op1 = view[-1]; | |
645 | unsigned char op2 = view[-2]; | |
646 | Target_i386::Relocate::check_tls(relinfo, relnum, rel, | |
647 | (op1 & 0xc0) == 0x80 && (op1 & 7) != 4); | |
648 | if (op2 == 0x8b) | |
649 | { | |
650 | // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 | |
651 | view[-2] = 0xc7; | |
652 | view[-1] = 0xc0 | ((op1 >> 3) & 7); | |
653 | } | |
654 | else if (op2 == 0x2b) | |
655 | { | |
656 | // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 | |
657 | view[-2] = 0x81; | |
658 | view[-1] = 0xe8 | ((op1 >> 3) & 7); | |
659 | } | |
660 | else if (op2 == 0x03) | |
661 | { | |
662 | // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 | |
663 | view[-2] = 0x81; | |
664 | view[-1] = 0xc0 | ((op1 >> 3) & 7); | |
665 | } | |
666 | else | |
667 | Target_i386::Relocate::check_tls(relinfo, relnum, rel, 0); | |
668 | } | |
669 | ||
670 | if (r_type == elfcpp::R_386_TLS_IE_32) | |
671 | value = tls_segment->vaddr() + tls_segment->memsz() - value; | |
672 | else // elfcpp::R_386_TLS_IE, elfcpp::R_386_TLS_GOTIE | |
673 | value = value - (tls_segment->vaddr() + tls_segment->memsz()); | |
674 | ||
675 | Relocate_functions<32, false>::rel32(view, value); | |
676 | } | |
677 | ||
678 | // Check the range for a TLS relocation. | |
679 | ||
680 | inline void | |
681 | Target_i386::Relocate::check_range(const Relocate_info<32, false>* relinfo, | |
682 | size_t relnum, | |
683 | const elfcpp::Rel<32, false>& rel, | |
684 | off_t view_size, off_t off) | |
685 | { | |
686 | off_t offset = rel.get_r_offset() + off; | |
687 | if (offset < 0 || offset > view_size) | |
688 | { | |
689 | fprintf(stderr, _("%s: %s: TLS relocation out of range\n"), | |
690 | program_name, | |
691 | relinfo->location(relnum, rel.get_r_offset()).c_str()); | |
692 | gold_exit(false); | |
693 | } | |
694 | } | |
695 | ||
696 | // Check the validity of a TLS relocation. This is like assert. | |
697 | ||
698 | inline void | |
699 | Target_i386::Relocate::check_tls(const Relocate_info<32, false>* relinfo, | |
700 | size_t relnum, | |
701 | const elfcpp::Rel<32, false>& rel, | |
702 | bool valid) | |
703 | { | |
704 | if (!valid) | |
705 | { | |
706 | fprintf(stderr, | |
707 | _("%s: %s: TLS relocation against invalid instruction\n"), | |
708 | program_name, | |
709 | relinfo->location(relnum, rel.get_r_offset()).c_str()); | |
710 | gold_exit(false); | |
61ba1cf9 ILT |
711 | } |
712 | } | |
713 | ||
714 | // Relocate section data. | |
715 | ||
716 | void | |
92e059d8 | 717 | Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, |
61ba1cf9 ILT |
718 | unsigned int sh_type, |
719 | const unsigned char* prelocs, | |
720 | size_t reloc_count, | |
61ba1cf9 ILT |
721 | unsigned char* view, |
722 | elfcpp::Elf_types<32>::Elf_Addr address, | |
723 | off_t view_size) | |
724 | { | |
92e059d8 | 725 | assert(sh_type == elfcpp::SHT_REL); |
61ba1cf9 ILT |
726 | |
727 | gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>( | |
92e059d8 | 728 | relinfo, |
61ba1cf9 ILT |
729 | prelocs, |
730 | reloc_count, | |
61ba1cf9 ILT |
731 | view, |
732 | address, | |
733 | view_size); | |
734 | } | |
735 | ||
736 | // The i386 target. | |
737 | ||
738 | Target_i386 target_i386; | |
739 | ||
14bfc3f5 ILT |
740 | // The selector for i386 object files. |
741 | ||
742 | class Target_selector_i386 : public Target_selector | |
743 | { | |
744 | public: | |
745 | Target_selector_i386() | |
746 | : Target_selector(elfcpp::EM_386, 32, false) | |
747 | { } | |
748 | ||
749 | Target* | |
750 | recognize(int machine, int osabi, int abiversion) const; | |
751 | }; | |
752 | ||
753 | // Recognize an i386 object file when we already know that the machine | |
754 | // number is EM_386. | |
755 | ||
756 | Target* | |
757 | Target_selector_i386::recognize(int, int, int) const | |
758 | { | |
61ba1cf9 | 759 | return &target_i386; |
14bfc3f5 ILT |
760 | } |
761 | ||
762 | Target_selector_i386 target_selector_i386; | |
763 | ||
764 | } // End anonymous namespace. |