Commit | Line | Data |
---|---|---|
61ba1cf9 ILT |
1 | // reloc.cc -- relocate input files for gold. |
2 | ||
6cb15b7f ILT |
3 | // Copyright 2006, 2007 Free Software Foundation, Inc. |
4 | // Written by Ian Lance Taylor <iant@google.com>. | |
5 | ||
6 | // This file is part of gold. | |
7 | ||
8 | // This program is free software; you can redistribute it and/or modify | |
9 | // it under the terms of the GNU General Public License as published by | |
10 | // the Free Software Foundation; either version 3 of the License, or | |
11 | // (at your option) any later version. | |
12 | ||
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | ||
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
21 | // MA 02110-1301, USA. | |
22 | ||
61ba1cf9 ILT |
23 | #include "gold.h" |
24 | ||
25 | #include "workqueue.h" | |
5a6f7e2d | 26 | #include "symtab.h" |
61ba1cf9 | 27 | #include "output.h" |
a9a60db6 ILT |
28 | #include "merge.h" |
29 | #include "object.h" | |
61ba1cf9 ILT |
30 | #include "reloc.h" |
31 | ||
32 | namespace gold | |
33 | { | |
34 | ||
92e059d8 ILT |
35 | // Read_relocs methods. |
36 | ||
37 | // These tasks just read the relocation information from the file. | |
38 | // After reading it, the start another task to process the | |
39 | // information. These tasks requires access to the file. | |
40 | ||
17a1d0a9 ILT |
41 | Task_token* |
42 | Read_relocs::is_runnable() | |
92e059d8 | 43 | { |
17a1d0a9 | 44 | return this->object_->is_locked() ? this->object_->token() : NULL; |
92e059d8 ILT |
45 | } |
46 | ||
47 | // Lock the file. | |
48 | ||
17a1d0a9 ILT |
49 | void |
50 | Read_relocs::locks(Task_locker* tl) | |
92e059d8 | 51 | { |
17a1d0a9 | 52 | tl->add(this, this->object_->token()); |
92e059d8 ILT |
53 | } |
54 | ||
55 | // Read the relocations and then start a Scan_relocs_task. | |
56 | ||
57 | void | |
58 | Read_relocs::run(Workqueue* workqueue) | |
59 | { | |
60 | Read_relocs_data *rd = new Read_relocs_data; | |
61 | this->object_->read_relocs(rd); | |
17a1d0a9 ILT |
62 | this->object_->release(); |
63 | ||
92e059d8 | 64 | workqueue->queue_front(new Scan_relocs(this->options_, this->symtab_, |
ead1e424 ILT |
65 | this->layout_, this->object_, rd, |
66 | this->symtab_lock_, this->blocker_)); | |
92e059d8 ILT |
67 | } |
68 | ||
c7912668 ILT |
69 | // Return a debugging name for the task. |
70 | ||
71 | std::string | |
72 | Read_relocs::get_name() const | |
73 | { | |
74 | return "Read_relocs " + this->object_->name(); | |
75 | } | |
76 | ||
92e059d8 ILT |
77 | // Scan_relocs methods. |
78 | ||
79 | // These tasks scan the relocations read by Read_relocs and mark up | |
80 | // the symbol table to indicate which relocations are required. We | |
81 | // use a lock on the symbol table to keep them from interfering with | |
82 | // each other. | |
83 | ||
17a1d0a9 ILT |
84 | Task_token* |
85 | Scan_relocs::is_runnable() | |
92e059d8 | 86 | { |
17a1d0a9 ILT |
87 | if (!this->symtab_lock_->is_writable()) |
88 | return this->symtab_lock_; | |
89 | if (this->object_->is_locked()) | |
90 | return this->object_->token(); | |
91 | return NULL; | |
92e059d8 ILT |
92 | } |
93 | ||
94 | // Return the locks we hold: one on the file, one on the symbol table | |
95 | // and one blocker. | |
96 | ||
17a1d0a9 ILT |
97 | void |
98 | Scan_relocs::locks(Task_locker* tl) | |
92e059d8 | 99 | { |
17a1d0a9 ILT |
100 | tl->add(this, this->object_->token()); |
101 | tl->add(this, this->symtab_lock_); | |
102 | tl->add(this, this->blocker_); | |
92e059d8 ILT |
103 | } |
104 | ||
105 | // Scan the relocs. | |
106 | ||
107 | void | |
108 | Scan_relocs::run(Workqueue*) | |
109 | { | |
ead1e424 ILT |
110 | this->object_->scan_relocs(this->options_, this->symtab_, this->layout_, |
111 | this->rd_); | |
17a1d0a9 | 112 | this->object_->release(); |
92e059d8 ILT |
113 | delete this->rd_; |
114 | this->rd_ = NULL; | |
115 | } | |
116 | ||
c7912668 ILT |
117 | // Return a debugging name for the task. |
118 | ||
119 | std::string | |
120 | Scan_relocs::get_name() const | |
121 | { | |
122 | return "Scan_relocs " + this->object_->name(); | |
123 | } | |
124 | ||
61ba1cf9 ILT |
125 | // Relocate_task methods. |
126 | ||
730cdc88 | 127 | // We may have to wait for the output sections to be written. |
61ba1cf9 | 128 | |
17a1d0a9 ILT |
129 | Task_token* |
130 | Relocate_task::is_runnable() | |
61ba1cf9 | 131 | { |
730cdc88 ILT |
132 | if (this->object_->relocs_must_follow_section_writes() |
133 | && this->output_sections_blocker_->is_blocked()) | |
17a1d0a9 | 134 | return this->output_sections_blocker_; |
730cdc88 | 135 | |
c7912668 | 136 | if (this->object_->is_locked()) |
17a1d0a9 | 137 | return this->object_->token(); |
c7912668 | 138 | |
17a1d0a9 | 139 | return NULL; |
61ba1cf9 ILT |
140 | } |
141 | ||
142 | // We want to lock the file while we run. We want to unblock | |
730cdc88 | 143 | // INPUT_SECTIONS_BLOCKER and FINAL_BLOCKER when we are done. |
17a1d0a9 | 144 | // INPUT_SECTIONS_BLOCKER may be NULL. |
61ba1cf9 | 145 | |
17a1d0a9 ILT |
146 | void |
147 | Relocate_task::locks(Task_locker* tl) | |
61ba1cf9 | 148 | { |
17a1d0a9 ILT |
149 | if (this->input_sections_blocker_ != NULL) |
150 | tl->add(this, this->input_sections_blocker_); | |
151 | tl->add(this, this->final_blocker_); | |
152 | tl->add(this, this->object_->token()); | |
61ba1cf9 ILT |
153 | } |
154 | ||
155 | // Run the task. | |
156 | ||
157 | void | |
158 | Relocate_task::run(Workqueue*) | |
159 | { | |
92e059d8 | 160 | this->object_->relocate(this->options_, this->symtab_, this->layout_, |
61ba1cf9 | 161 | this->of_); |
17a1d0a9 | 162 | this->object_->release(); |
61ba1cf9 ILT |
163 | } |
164 | ||
c7912668 ILT |
165 | // Return a debugging name for the task. |
166 | ||
167 | std::string | |
168 | Relocate_task::get_name() const | |
169 | { | |
170 | return "Relocate_task " + this->object_->name(); | |
171 | } | |
172 | ||
92e059d8 ILT |
173 | // Read the relocs and local symbols from the object file and store |
174 | // the information in RD. | |
175 | ||
176 | template<int size, bool big_endian> | |
177 | void | |
f6ce93d6 | 178 | Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd) |
92e059d8 ILT |
179 | { |
180 | rd->relocs.clear(); | |
181 | ||
182 | unsigned int shnum = this->shnum(); | |
183 | if (shnum == 0) | |
184 | return; | |
185 | ||
186 | rd->relocs.reserve(shnum / 2); | |
187 | ||
730cdc88 ILT |
188 | std::vector<Map_to_output>& map_sections(this->map_to_output()); |
189 | ||
645f8123 | 190 | const unsigned char *pshdrs = this->get_view(this->elf_file_.shoff(), |
9eb9fa57 ILT |
191 | shnum * This::shdr_size, |
192 | true); | |
92e059d8 ILT |
193 | // Skip the first, dummy, section. |
194 | const unsigned char *ps = pshdrs + This::shdr_size; | |
195 | for (unsigned int i = 1; i < shnum; ++i, ps += This::shdr_size) | |
196 | { | |
197 | typename This::Shdr shdr(ps); | |
198 | ||
199 | unsigned int sh_type = shdr.get_sh_type(); | |
200 | if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA) | |
201 | continue; | |
202 | ||
203 | unsigned int shndx = shdr.get_sh_info(); | |
204 | if (shndx >= shnum) | |
205 | { | |
75f2446e ILT |
206 | this->error(_("relocation section %u has bad info %u"), |
207 | i, shndx); | |
208 | continue; | |
92e059d8 ILT |
209 | } |
210 | ||
730cdc88 ILT |
211 | Output_section* os = map_sections[shndx].output_section; |
212 | if (os == NULL) | |
92e059d8 ILT |
213 | continue; |
214 | ||
ead1e424 ILT |
215 | // We are scanning relocations in order to fill out the GOT and |
216 | // PLT sections. Relocations for sections which are not | |
217 | // allocated (typically debugging sections) should not add new | |
218 | // GOT and PLT entries. So we skip them. | |
219 | typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size); | |
220 | if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) | |
221 | continue; | |
222 | ||
645f8123 | 223 | if (shdr.get_sh_link() != this->symtab_shndx_) |
92e059d8 | 224 | { |
75f2446e ILT |
225 | this->error(_("relocation section %u uses unexpected " |
226 | "symbol table %u"), | |
227 | i, shdr.get_sh_link()); | |
228 | continue; | |
92e059d8 ILT |
229 | } |
230 | ||
231 | off_t sh_size = shdr.get_sh_size(); | |
232 | ||
233 | unsigned int reloc_size; | |
234 | if (sh_type == elfcpp::SHT_REL) | |
235 | reloc_size = elfcpp::Elf_sizes<size>::rel_size; | |
236 | else | |
237 | reloc_size = elfcpp::Elf_sizes<size>::rela_size; | |
238 | if (reloc_size != shdr.get_sh_entsize()) | |
239 | { | |
75f2446e ILT |
240 | this->error(_("unexpected entsize for reloc section %u: %lu != %u"), |
241 | i, static_cast<unsigned long>(shdr.get_sh_entsize()), | |
242 | reloc_size); | |
243 | continue; | |
92e059d8 ILT |
244 | } |
245 | ||
246 | size_t reloc_count = sh_size / reloc_size; | |
f5c3f225 | 247 | if (static_cast<off_t>(reloc_count * reloc_size) != sh_size) |
92e059d8 | 248 | { |
75f2446e ILT |
249 | this->error(_("reloc section %u size %lu uneven"), |
250 | i, static_cast<unsigned long>(sh_size)); | |
251 | continue; | |
92e059d8 ILT |
252 | } |
253 | ||
254 | rd->relocs.push_back(Section_relocs()); | |
255 | Section_relocs& sr(rd->relocs.back()); | |
256 | sr.reloc_shndx = i; | |
257 | sr.data_shndx = shndx; | |
9eb9fa57 ILT |
258 | sr.contents = this->get_lasting_view(shdr.get_sh_offset(), sh_size, |
259 | true); | |
92e059d8 ILT |
260 | sr.sh_type = sh_type; |
261 | sr.reloc_count = reloc_count; | |
730cdc88 ILT |
262 | sr.output_section = os; |
263 | sr.needs_special_offset_handling = map_sections[shndx].offset == -1; | |
92e059d8 ILT |
264 | } |
265 | ||
266 | // Read the local symbols. | |
a3ad94ed | 267 | gold_assert(this->symtab_shndx_ != -1U); |
645f8123 | 268 | if (this->symtab_shndx_ == 0 || this->local_symbol_count_ == 0) |
92e059d8 ILT |
269 | rd->local_symbols = NULL; |
270 | else | |
271 | { | |
272 | typename This::Shdr symtabshdr(pshdrs | |
645f8123 | 273 | + this->symtab_shndx_ * This::shdr_size); |
a3ad94ed | 274 | gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); |
92e059d8 ILT |
275 | const int sym_size = This::sym_size; |
276 | const unsigned int loccount = this->local_symbol_count_; | |
a3ad94ed | 277 | gold_assert(loccount == symtabshdr.get_sh_info()); |
92e059d8 ILT |
278 | off_t locsize = loccount * sym_size; |
279 | rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(), | |
9eb9fa57 | 280 | locsize, true); |
92e059d8 ILT |
281 | } |
282 | } | |
283 | ||
284 | // Scan the relocs and adjust the symbol table. This looks for | |
285 | // relocations which require GOT/PLT/COPY relocations. | |
286 | ||
287 | template<int size, bool big_endian> | |
288 | void | |
f6ce93d6 | 289 | Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options, |
92e059d8 | 290 | Symbol_table* symtab, |
ead1e424 | 291 | Layout* layout, |
92e059d8 ILT |
292 | Read_relocs_data* rd) |
293 | { | |
294 | Sized_target<size, big_endian>* target = this->sized_target(); | |
295 | ||
296 | const unsigned char* local_symbols; | |
297 | if (rd->local_symbols == NULL) | |
298 | local_symbols = NULL; | |
299 | else | |
300 | local_symbols = rd->local_symbols->data(); | |
301 | ||
302 | for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin(); | |
303 | p != rd->relocs.end(); | |
304 | ++p) | |
305 | { | |
a3ad94ed ILT |
306 | target->scan_relocs(options, symtab, layout, this, p->data_shndx, |
307 | p->sh_type, p->contents->data(), p->reloc_count, | |
730cdc88 | 308 | p->output_section, p->needs_special_offset_handling, |
92e059d8 | 309 | this->local_symbol_count_, |
730cdc88 | 310 | local_symbols); |
92e059d8 ILT |
311 | delete p->contents; |
312 | p->contents = NULL; | |
313 | } | |
314 | ||
315 | if (rd->local_symbols != NULL) | |
316 | { | |
317 | delete rd->local_symbols; | |
318 | rd->local_symbols = NULL; | |
319 | } | |
320 | } | |
321 | ||
61ba1cf9 ILT |
322 | // Relocate the input sections and write out the local symbols. |
323 | ||
324 | template<int size, bool big_endian> | |
325 | void | |
f6ce93d6 | 326 | Sized_relobj<size, big_endian>::do_relocate(const General_options& options, |
61ba1cf9 | 327 | const Symbol_table* symtab, |
92e059d8 | 328 | const Layout* layout, |
61ba1cf9 ILT |
329 | Output_file* of) |
330 | { | |
331 | unsigned int shnum = this->shnum(); | |
332 | ||
333 | // Read the section headers. | |
645f8123 | 334 | const unsigned char* pshdrs = this->get_view(this->elf_file_.shoff(), |
9eb9fa57 ILT |
335 | shnum * This::shdr_size, |
336 | true); | |
61ba1cf9 ILT |
337 | |
338 | Views views; | |
339 | views.resize(shnum); | |
340 | ||
341 | // Make two passes over the sections. The first one copies the | |
342 | // section data to the output file. The second one applies | |
343 | // relocations. | |
344 | ||
345 | this->write_sections(pshdrs, of, &views); | |
346 | ||
a9a60db6 ILT |
347 | // To speed up relocations, we set up hash tables for fast lookup of |
348 | // input offsets to output addresses. | |
349 | this->initialize_input_to_output_maps(); | |
350 | ||
61ba1cf9 ILT |
351 | // Apply relocations. |
352 | ||
92e059d8 | 353 | this->relocate_sections(options, symtab, layout, pshdrs, &views); |
61ba1cf9 | 354 | |
a9a60db6 ILT |
355 | // After we've done the relocations, we release the hash tables, |
356 | // since we no longer need them. | |
357 | this->free_input_to_output_maps(); | |
358 | ||
61ba1cf9 ILT |
359 | // Write out the accumulated views. |
360 | for (unsigned int i = 1; i < shnum; ++i) | |
361 | { | |
362 | if (views[i].view != NULL) | |
730cdc88 | 363 | { |
96803768 ILT |
364 | if (!views[i].is_postprocessing_view) |
365 | { | |
366 | if (views[i].is_input_output_view) | |
367 | of->write_input_output_view(views[i].offset, | |
368 | views[i].view_size, | |
369 | views[i].view); | |
370 | else | |
371 | of->write_output_view(views[i].offset, views[i].view_size, | |
372 | views[i].view); | |
373 | } | |
730cdc88 | 374 | } |
61ba1cf9 ILT |
375 | } |
376 | ||
377 | // Write out the local symbols. | |
7bf1f802 | 378 | this->write_local_symbols(of, layout->sympool(), layout->dynpool()); |
61ba1cf9 ILT |
379 | } |
380 | ||
381 | // Write section data to the output file. PSHDRS points to the | |
382 | // section headers. Record the views in *PVIEWS for use when | |
383 | // relocating. | |
384 | ||
385 | template<int size, bool big_endian> | |
386 | void | |
f6ce93d6 | 387 | Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs, |
61ba1cf9 | 388 | Output_file* of, |
17a1d0a9 | 389 | Views* pviews) const |
61ba1cf9 ILT |
390 | { |
391 | unsigned int shnum = this->shnum(); | |
17a1d0a9 | 392 | const std::vector<Map_to_output>& map_sections(this->map_to_output()); |
61ba1cf9 ILT |
393 | |
394 | const unsigned char* p = pshdrs + This::shdr_size; | |
395 | for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size) | |
396 | { | |
397 | View_size* pvs = &(*pviews)[i]; | |
398 | ||
399 | pvs->view = NULL; | |
400 | ||
401 | const Output_section* os = map_sections[i].output_section; | |
402 | if (os == NULL) | |
403 | continue; | |
730cdc88 | 404 | off_t output_offset = map_sections[i].offset; |
61ba1cf9 ILT |
405 | |
406 | typename This::Shdr shdr(p); | |
407 | ||
408 | if (shdr.get_sh_type() == elfcpp::SHT_NOBITS) | |
409 | continue; | |
410 | ||
96803768 ILT |
411 | // In the normal case, this input section is simply mapped to |
412 | // the output section at offset OUTPUT_OFFSET. | |
413 | ||
414 | // However, if OUTPUT_OFFSET == -1, then input data is handled | |
415 | // specially--e.g., a .eh_frame section. The relocation | |
416 | // routines need to check for each reloc where it should be | |
417 | // applied. For this case, we need an input/output view for the | |
418 | // entire contents of the section in the output file. We don't | |
419 | // want to copy the contents of the input section to the output | |
420 | // section; the output section contents were already written, | |
421 | // and we waited for them in Relocate_task::is_runnable because | |
422 | // relocs_must_follow_section_writes is set for the object. | |
423 | ||
424 | // Regardless of which of the above cases is true, we have to | |
425 | // check requires_postprocessing of the output section. If that | |
426 | // is false, then we work with views of the output file | |
427 | // directly. If it is true, then we work with a separate | |
428 | // buffer, and the output section is responsible for writing the | |
429 | // final data to the output file. | |
430 | ||
431 | off_t output_section_offset; | |
432 | off_t output_section_size; | |
433 | if (!os->requires_postprocessing()) | |
434 | { | |
435 | output_section_offset = os->offset(); | |
436 | output_section_size = os->data_size(); | |
437 | } | |
438 | else | |
439 | { | |
440 | output_section_offset = 0; | |
441 | output_section_size = os->postprocessing_buffer_size(); | |
442 | } | |
443 | ||
730cdc88 | 444 | off_t view_start; |
fe8718a4 | 445 | section_size_type view_size; |
730cdc88 ILT |
446 | if (output_offset != -1) |
447 | { | |
96803768 | 448 | view_start = output_section_offset + output_offset; |
fe8718a4 | 449 | view_size = convert_to_section_size_type(shdr.get_sh_size()); |
730cdc88 ILT |
450 | } |
451 | else | |
452 | { | |
96803768 | 453 | view_start = output_section_offset; |
fe8718a4 | 454 | view_size = convert_to_section_size_type(output_section_size); |
730cdc88 | 455 | } |
61ba1cf9 | 456 | |
730cdc88 | 457 | if (view_size == 0) |
ead1e424 ILT |
458 | continue; |
459 | ||
730cdc88 ILT |
460 | gold_assert(output_offset == -1 |
461 | || (output_offset >= 0 | |
8d32f935 ILT |
462 | && (output_offset + static_cast<off_t>(view_size) |
463 | <= output_section_size))); | |
ead1e424 | 464 | |
730cdc88 | 465 | unsigned char* view; |
96803768 ILT |
466 | if (os->requires_postprocessing()) |
467 | { | |
468 | unsigned char* buffer = os->postprocessing_buffer(); | |
469 | view = buffer + view_start; | |
470 | if (output_offset != -1) | |
471 | this->read(shdr.get_sh_offset(), view_size, view); | |
472 | } | |
730cdc88 ILT |
473 | else |
474 | { | |
96803768 ILT |
475 | if (output_offset == -1) |
476 | view = of->get_input_output_view(view_start, view_size); | |
477 | else | |
478 | { | |
479 | view = of->get_output_view(view_start, view_size); | |
480 | this->read(shdr.get_sh_offset(), view_size, view); | |
481 | } | |
730cdc88 | 482 | } |
92e059d8 | 483 | |
61ba1cf9 | 484 | pvs->view = view; |
730cdc88 ILT |
485 | pvs->address = os->address(); |
486 | if (output_offset != -1) | |
487 | pvs->address += output_offset; | |
488 | pvs->offset = view_start; | |
489 | pvs->view_size = view_size; | |
490 | pvs->is_input_output_view = output_offset == -1; | |
96803768 | 491 | pvs->is_postprocessing_view = os->requires_postprocessing(); |
61ba1cf9 ILT |
492 | } |
493 | } | |
494 | ||
495 | // Relocate section data. VIEWS points to the section data as views | |
496 | // in the output file. | |
497 | ||
498 | template<int size, bool big_endian> | |
499 | void | |
f6ce93d6 | 500 | Sized_relobj<size, big_endian>::relocate_sections( |
92e059d8 ILT |
501 | const General_options& options, |
502 | const Symbol_table* symtab, | |
503 | const Layout* layout, | |
504 | const unsigned char* pshdrs, | |
505 | Views* pviews) | |
61ba1cf9 ILT |
506 | { |
507 | unsigned int shnum = this->shnum(); | |
61ba1cf9 ILT |
508 | Sized_target<size, big_endian>* target = this->sized_target(); |
509 | ||
17a1d0a9 | 510 | const std::vector<Map_to_output>& map_sections(this->map_to_output()); |
730cdc88 | 511 | |
92e059d8 ILT |
512 | Relocate_info<size, big_endian> relinfo; |
513 | relinfo.options = &options; | |
514 | relinfo.symtab = symtab; | |
515 | relinfo.layout = layout; | |
516 | relinfo.object = this; | |
92e059d8 | 517 | |
61ba1cf9 ILT |
518 | const unsigned char* p = pshdrs + This::shdr_size; |
519 | for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size) | |
520 | { | |
521 | typename This::Shdr shdr(p); | |
522 | ||
523 | unsigned int sh_type = shdr.get_sh_type(); | |
524 | if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA) | |
525 | continue; | |
526 | ||
527 | unsigned int index = shdr.get_sh_info(); | |
528 | if (index >= this->shnum()) | |
529 | { | |
75f2446e ILT |
530 | this->error(_("relocation section %u has bad info %u"), |
531 | i, index); | |
532 | continue; | |
61ba1cf9 ILT |
533 | } |
534 | ||
730cdc88 ILT |
535 | Output_section* os = map_sections[index].output_section; |
536 | if (os == NULL) | |
61ba1cf9 ILT |
537 | { |
538 | // This relocation section is against a section which we | |
539 | // discarded. | |
540 | continue; | |
541 | } | |
730cdc88 | 542 | off_t output_offset = map_sections[index].offset; |
61ba1cf9 | 543 | |
a3ad94ed | 544 | gold_assert((*pviews)[index].view != NULL); |
61ba1cf9 | 545 | |
645f8123 | 546 | if (shdr.get_sh_link() != this->symtab_shndx_) |
61ba1cf9 | 547 | { |
75f2446e ILT |
548 | gold_error(_("relocation section %u uses unexpected " |
549 | "symbol table %u"), | |
550 | i, shdr.get_sh_link()); | |
551 | continue; | |
61ba1cf9 ILT |
552 | } |
553 | ||
554 | off_t sh_size = shdr.get_sh_size(); | |
555 | const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(), | |
9eb9fa57 | 556 | sh_size, false); |
61ba1cf9 ILT |
557 | |
558 | unsigned int reloc_size; | |
559 | if (sh_type == elfcpp::SHT_REL) | |
560 | reloc_size = elfcpp::Elf_sizes<size>::rel_size; | |
561 | else | |
562 | reloc_size = elfcpp::Elf_sizes<size>::rela_size; | |
563 | ||
564 | if (reloc_size != shdr.get_sh_entsize()) | |
565 | { | |
75f2446e ILT |
566 | gold_error(_("unexpected entsize for reloc section %u: %lu != %u"), |
567 | i, static_cast<unsigned long>(shdr.get_sh_entsize()), | |
730cdc88 | 568 | reloc_size); |
75f2446e | 569 | continue; |
61ba1cf9 ILT |
570 | } |
571 | ||
572 | size_t reloc_count = sh_size / reloc_size; | |
f5c3f225 | 573 | if (static_cast<off_t>(reloc_count * reloc_size) != sh_size) |
61ba1cf9 | 574 | { |
75f2446e ILT |
575 | gold_error(_("reloc section %u size %lu uneven"), |
576 | i, static_cast<unsigned long>(sh_size)); | |
577 | continue; | |
61ba1cf9 ILT |
578 | } |
579 | ||
96803768 ILT |
580 | gold_assert(output_offset != -1 |
581 | || this->relocs_must_follow_section_writes()); | |
582 | ||
92e059d8 ILT |
583 | relinfo.reloc_shndx = i; |
584 | relinfo.data_shndx = index; | |
585 | target->relocate_section(&relinfo, | |
586 | sh_type, | |
587 | prelocs, | |
588 | reloc_count, | |
730cdc88 ILT |
589 | os, |
590 | output_offset == -1, | |
61ba1cf9 ILT |
591 | (*pviews)[index].view, |
592 | (*pviews)[index].address, | |
593 | (*pviews)[index].view_size); | |
594 | } | |
595 | } | |
596 | ||
a9a60db6 ILT |
597 | // Create merge hash tables for the local symbols. These are used to |
598 | // speed up relocations. | |
599 | ||
600 | template<int size, bool big_endian> | |
601 | void | |
602 | Sized_relobj<size, big_endian>::initialize_input_to_output_maps() | |
603 | { | |
604 | const unsigned int loccount = this->local_symbol_count_; | |
605 | for (unsigned int i = 1; i < loccount; ++i) | |
606 | { | |
607 | Symbol_value<size>& lv(this->local_values_[i]); | |
608 | lv.initialize_input_to_output_map(this); | |
609 | } | |
610 | } | |
611 | ||
612 | // Free merge hash tables for the local symbols. | |
613 | ||
614 | template<int size, bool big_endian> | |
615 | void | |
616 | Sized_relobj<size, big_endian>::free_input_to_output_maps() | |
617 | { | |
618 | const unsigned int loccount = this->local_symbol_count_; | |
619 | for (unsigned int i = 1; i < loccount; ++i) | |
620 | { | |
621 | Symbol_value<size>& lv(this->local_values_[i]); | |
622 | lv.free_input_to_output_map(); | |
623 | } | |
624 | } | |
625 | ||
626 | // Class Merged_symbol_value. | |
627 | ||
628 | template<int size> | |
629 | void | |
630 | Merged_symbol_value<size>::initialize_input_to_output_map( | |
631 | const Relobj* object, | |
632 | unsigned int input_shndx) | |
633 | { | |
634 | Object_merge_map* map = object->merge_map(); | |
635 | map->initialize_input_to_output_map<size>(input_shndx, | |
636 | this->output_start_address_, | |
637 | &this->output_addresses_); | |
638 | } | |
639 | ||
640 | // Get the output value corresponding to an input offset if we | |
641 | // couldn't find it in the hash table. | |
642 | ||
643 | template<int size> | |
644 | typename elfcpp::Elf_types<size>::Elf_Addr | |
645 | Merged_symbol_value<size>::value_from_output_section( | |
646 | const Relobj* object, | |
647 | unsigned int input_shndx, | |
648 | typename elfcpp::Elf_types<size>::Elf_Addr input_offset) const | |
649 | { | |
650 | section_offset_type output_offset; | |
651 | bool found = object->merge_map()->get_output_offset(NULL, input_shndx, | |
652 | input_offset, | |
653 | &output_offset); | |
654 | ||
655 | // If this assertion fails, it means that some relocation was | |
656 | // against a portion of an input merge section which we didn't map | |
657 | // to the output file and we didn't explicitly discard. We should | |
658 | // always map all portions of input merge sections. | |
659 | gold_assert(found); | |
660 | ||
661 | if (output_offset == -1) | |
662 | return 0; | |
663 | else | |
664 | return this->output_start_address_ + output_offset; | |
665 | } | |
666 | ||
5a6f7e2d ILT |
667 | // Copy_relocs::Copy_reloc_entry methods. |
668 | ||
669 | // Return whether we should emit this reloc. We should emit it if the | |
670 | // symbol is still defined in a dynamic object. If we should not emit | |
671 | // it, we clear it, to save ourselves the test next time. | |
672 | ||
673 | template<int size, bool big_endian> | |
674 | bool | |
675 | Copy_relocs<size, big_endian>::Copy_reloc_entry::should_emit() | |
676 | { | |
677 | if (this->sym_ == NULL) | |
678 | return false; | |
14b31740 | 679 | if (this->sym_->is_from_dynobj()) |
5a6f7e2d ILT |
680 | return true; |
681 | this->sym_ = NULL; | |
682 | return false; | |
683 | } | |
684 | ||
685 | // Emit a reloc into a SHT_REL section. | |
686 | ||
687 | template<int size, bool big_endian> | |
688 | void | |
689 | Copy_relocs<size, big_endian>::Copy_reloc_entry::emit( | |
690 | Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>* reloc_data) | |
691 | { | |
16649710 | 692 | this->sym_->set_needs_dynsym_entry(); |
4f4c5f80 ILT |
693 | reloc_data->add_global(this->sym_, this->reloc_type_, this->output_section_, |
694 | this->relobj_, this->shndx_, this->address_); | |
5a6f7e2d ILT |
695 | } |
696 | ||
697 | // Emit a reloc into a SHT_RELA section. | |
698 | ||
699 | template<int size, bool big_endian> | |
700 | void | |
701 | Copy_relocs<size, big_endian>::Copy_reloc_entry::emit( | |
702 | Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>* reloc_data) | |
703 | { | |
16649710 | 704 | this->sym_->set_needs_dynsym_entry(); |
4f4c5f80 ILT |
705 | reloc_data->add_global(this->sym_, this->reloc_type_, this->output_section_, |
706 | this->relobj_, this->shndx_, this->address_, | |
707 | this->addend_); | |
5a6f7e2d ILT |
708 | } |
709 | ||
710 | // Copy_relocs methods. | |
a3ad94ed ILT |
711 | |
712 | // Return whether we need a COPY reloc for a relocation against GSYM. | |
713 | // The relocation is being applied to section SHNDX in OBJECT. | |
714 | ||
715 | template<int size, bool big_endian> | |
716 | bool | |
5a6f7e2d | 717 | Copy_relocs<size, big_endian>::need_copy_reloc( |
a3ad94ed ILT |
718 | const General_options*, |
719 | Relobj* object, | |
720 | unsigned int shndx, | |
5a6f7e2d | 721 | Sized_symbol<size>* sym) |
a3ad94ed ILT |
722 | { |
723 | // FIXME: Handle -z nocopyrelocs. | |
724 | ||
5a6f7e2d ILT |
725 | if (sym->symsize() == 0) |
726 | return false; | |
727 | ||
a3ad94ed ILT |
728 | // If this is a readonly section, then we need a COPY reloc. |
729 | // Otherwise we can use a dynamic reloc. | |
730 | if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) | |
731 | return true; | |
732 | ||
733 | return false; | |
734 | } | |
735 | ||
5a6f7e2d ILT |
736 | // Save a Rel reloc. |
737 | ||
738 | template<int size, bool big_endian> | |
739 | void | |
740 | Copy_relocs<size, big_endian>::save( | |
741 | Symbol* sym, | |
742 | Relobj* relobj, | |
743 | unsigned int shndx, | |
4f4c5f80 | 744 | Output_section* output_section, |
5a6f7e2d ILT |
745 | const elfcpp::Rel<size, big_endian>& rel) |
746 | { | |
747 | unsigned int reloc_type = elfcpp::elf_r_type<size>(rel.get_r_info()); | |
748 | this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx, | |
4f4c5f80 ILT |
749 | output_section, |
750 | rel.get_r_offset(), 0)); | |
5a6f7e2d ILT |
751 | } |
752 | ||
753 | // Save a Rela reloc. | |
754 | ||
755 | template<int size, bool big_endian> | |
756 | void | |
757 | Copy_relocs<size, big_endian>::save( | |
758 | Symbol* sym, | |
759 | Relobj* relobj, | |
760 | unsigned int shndx, | |
4f4c5f80 | 761 | Output_section* output_section, |
5a6f7e2d ILT |
762 | const elfcpp::Rela<size, big_endian>& rela) |
763 | { | |
764 | unsigned int reloc_type = elfcpp::elf_r_type<size>(rela.get_r_info()); | |
765 | this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx, | |
4f4c5f80 | 766 | output_section, |
5a6f7e2d ILT |
767 | rela.get_r_offset(), |
768 | rela.get_r_addend())); | |
769 | } | |
770 | ||
771 | // Return whether there are any relocs to emit. We don't want to emit | |
772 | // a reloc if the symbol is no longer defined in a dynamic object. | |
773 | ||
774 | template<int size, bool big_endian> | |
775 | bool | |
776 | Copy_relocs<size, big_endian>::any_to_emit() | |
777 | { | |
778 | for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); | |
779 | p != this->entries_.end(); | |
780 | ++p) | |
781 | { | |
782 | if (p->should_emit()) | |
783 | return true; | |
784 | } | |
785 | return false; | |
786 | } | |
787 | ||
788 | // Emit relocs. | |
789 | ||
790 | template<int size, bool big_endian> | |
791 | template<int sh_type> | |
792 | void | |
793 | Copy_relocs<size, big_endian>::emit( | |
794 | Output_data_reloc<sh_type, true, size, big_endian>* reloc_data) | |
795 | { | |
796 | for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); | |
797 | p != this->entries_.end(); | |
798 | ++p) | |
799 | { | |
800 | if (p->should_emit()) | |
801 | p->emit(reloc_data); | |
802 | } | |
803 | } | |
804 | ||
730cdc88 ILT |
805 | // Track_relocs methods. |
806 | ||
807 | // Initialize the class to track the relocs. This gets the object, | |
808 | // the reloc section index, and the type of the relocs. This returns | |
809 | // false if something goes wrong. | |
810 | ||
811 | template<int size, bool big_endian> | |
812 | bool | |
813 | Track_relocs<size, big_endian>::initialize( | |
b696e6d4 | 814 | Object* object, |
730cdc88 ILT |
815 | unsigned int reloc_shndx, |
816 | unsigned int reloc_type) | |
817 | { | |
730cdc88 ILT |
818 | // If RELOC_SHNDX is -1U, it means there is more than one reloc |
819 | // section for the .eh_frame section. We can't handle that case. | |
820 | if (reloc_shndx == -1U) | |
821 | return false; | |
822 | ||
823 | // If RELOC_SHNDX is 0, there is no reloc section. | |
824 | if (reloc_shndx == 0) | |
825 | return true; | |
826 | ||
827 | // Get the contents of the reloc section. | |
828 | this->prelocs_ = object->section_contents(reloc_shndx, &this->len_, false); | |
829 | ||
830 | if (reloc_type == elfcpp::SHT_REL) | |
831 | this->reloc_size_ = elfcpp::Elf_sizes<size>::rel_size; | |
832 | else if (reloc_type == elfcpp::SHT_RELA) | |
833 | this->reloc_size_ = elfcpp::Elf_sizes<size>::rela_size; | |
834 | else | |
835 | gold_unreachable(); | |
836 | ||
837 | if (this->len_ % this->reloc_size_ != 0) | |
838 | { | |
839 | object->error(_("reloc section size %zu is not a multiple of " | |
840 | "reloc size %d\n"), | |
841 | static_cast<size_t>(this->len_), | |
842 | this->reloc_size_); | |
843 | return false; | |
844 | } | |
845 | ||
846 | return true; | |
847 | } | |
848 | ||
849 | // Return the offset of the next reloc, or -1 if there isn't one. | |
850 | ||
851 | template<int size, bool big_endian> | |
852 | off_t | |
853 | Track_relocs<size, big_endian>::next_offset() const | |
854 | { | |
855 | if (this->pos_ >= this->len_) | |
856 | return -1; | |
857 | ||
858 | // Rel and Rela start out the same, so we can always use Rel to find | |
859 | // the r_offset value. | |
860 | elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_); | |
861 | return rel.get_r_offset(); | |
862 | } | |
863 | ||
864 | // Return the index of the symbol referenced by the next reloc, or -1U | |
865 | // if there aren't any more relocs. | |
866 | ||
867 | template<int size, bool big_endian> | |
868 | unsigned int | |
869 | Track_relocs<size, big_endian>::next_symndx() const | |
870 | { | |
871 | if (this->pos_ >= this->len_) | |
872 | return -1U; | |
873 | ||
874 | // Rel and Rela start out the same, so we can use Rel to find the | |
875 | // symbol index. | |
876 | elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_); | |
877 | return elfcpp::elf_r_sym<size>(rel.get_r_info()); | |
878 | } | |
879 | ||
880 | // Advance to the next reloc whose r_offset is greater than or equal | |
881 | // to OFFSET. Return the number of relocs we skip. | |
882 | ||
883 | template<int size, bool big_endian> | |
884 | int | |
885 | Track_relocs<size, big_endian>::advance(off_t offset) | |
886 | { | |
887 | int ret = 0; | |
888 | while (this->pos_ < this->len_) | |
889 | { | |
890 | // Rel and Rela start out the same, so we can always use Rel to | |
891 | // find the r_offset value. | |
892 | elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_); | |
893 | if (static_cast<off_t>(rel.get_r_offset()) >= offset) | |
894 | break; | |
895 | ++ret; | |
896 | this->pos_ += this->reloc_size_; | |
897 | } | |
898 | return ret; | |
899 | } | |
900 | ||
61ba1cf9 ILT |
901 | // Instantiate the templates we need. We could use the configure |
902 | // script to restrict this to only the ones for implemented targets. | |
903 | ||
193a53d9 | 904 | #ifdef HAVE_TARGET_32_LITTLE |
92e059d8 ILT |
905 | template |
906 | void | |
f6ce93d6 | 907 | Sized_relobj<32, false>::do_read_relocs(Read_relocs_data* rd); |
193a53d9 | 908 | #endif |
92e059d8 | 909 | |
193a53d9 | 910 | #ifdef HAVE_TARGET_32_BIG |
92e059d8 ILT |
911 | template |
912 | void | |
f6ce93d6 | 913 | Sized_relobj<32, true>::do_read_relocs(Read_relocs_data* rd); |
193a53d9 | 914 | #endif |
92e059d8 | 915 | |
193a53d9 | 916 | #ifdef HAVE_TARGET_64_LITTLE |
92e059d8 ILT |
917 | template |
918 | void | |
f6ce93d6 | 919 | Sized_relobj<64, false>::do_read_relocs(Read_relocs_data* rd); |
193a53d9 | 920 | #endif |
92e059d8 | 921 | |
193a53d9 | 922 | #ifdef HAVE_TARGET_64_BIG |
92e059d8 ILT |
923 | template |
924 | void | |
f6ce93d6 | 925 | Sized_relobj<64, true>::do_read_relocs(Read_relocs_data* rd); |
193a53d9 | 926 | #endif |
92e059d8 | 927 | |
193a53d9 | 928 | #ifdef HAVE_TARGET_32_LITTLE |
92e059d8 ILT |
929 | template |
930 | void | |
f6ce93d6 | 931 | Sized_relobj<32, false>::do_scan_relocs(const General_options& options, |
92e059d8 | 932 | Symbol_table* symtab, |
ead1e424 | 933 | Layout* layout, |
92e059d8 | 934 | Read_relocs_data* rd); |
193a53d9 | 935 | #endif |
92e059d8 | 936 | |
193a53d9 | 937 | #ifdef HAVE_TARGET_32_BIG |
92e059d8 ILT |
938 | template |
939 | void | |
f6ce93d6 | 940 | Sized_relobj<32, true>::do_scan_relocs(const General_options& options, |
92e059d8 | 941 | Symbol_table* symtab, |
ead1e424 | 942 | Layout* layout, |
92e059d8 | 943 | Read_relocs_data* rd); |
193a53d9 | 944 | #endif |
92e059d8 | 945 | |
193a53d9 | 946 | #ifdef HAVE_TARGET_64_LITTLE |
92e059d8 ILT |
947 | template |
948 | void | |
f6ce93d6 | 949 | Sized_relobj<64, false>::do_scan_relocs(const General_options& options, |
92e059d8 | 950 | Symbol_table* symtab, |
ead1e424 | 951 | Layout* layout, |
92e059d8 | 952 | Read_relocs_data* rd); |
193a53d9 | 953 | #endif |
92e059d8 | 954 | |
193a53d9 | 955 | #ifdef HAVE_TARGET_64_BIG |
92e059d8 ILT |
956 | template |
957 | void | |
f6ce93d6 | 958 | Sized_relobj<64, true>::do_scan_relocs(const General_options& options, |
92e059d8 | 959 | Symbol_table* symtab, |
ead1e424 | 960 | Layout* layout, |
92e059d8 | 961 | Read_relocs_data* rd); |
193a53d9 | 962 | #endif |
92e059d8 | 963 | |
193a53d9 | 964 | #ifdef HAVE_TARGET_32_LITTLE |
61ba1cf9 ILT |
965 | template |
966 | void | |
f6ce93d6 | 967 | Sized_relobj<32, false>::do_relocate(const General_options& options, |
61ba1cf9 | 968 | const Symbol_table* symtab, |
92e059d8 | 969 | const Layout* layout, |
61ba1cf9 | 970 | Output_file* of); |
193a53d9 | 971 | #endif |
61ba1cf9 | 972 | |
193a53d9 | 973 | #ifdef HAVE_TARGET_32_BIG |
61ba1cf9 ILT |
974 | template |
975 | void | |
f6ce93d6 | 976 | Sized_relobj<32, true>::do_relocate(const General_options& options, |
61ba1cf9 | 977 | const Symbol_table* symtab, |
92e059d8 | 978 | const Layout* layout, |
61ba1cf9 | 979 | Output_file* of); |
193a53d9 | 980 | #endif |
61ba1cf9 | 981 | |
193a53d9 | 982 | #ifdef HAVE_TARGET_64_LITTLE |
61ba1cf9 ILT |
983 | template |
984 | void | |
f6ce93d6 | 985 | Sized_relobj<64, false>::do_relocate(const General_options& options, |
61ba1cf9 | 986 | const Symbol_table* symtab, |
92e059d8 | 987 | const Layout* layout, |
61ba1cf9 | 988 | Output_file* of); |
193a53d9 | 989 | #endif |
61ba1cf9 | 990 | |
193a53d9 | 991 | #ifdef HAVE_TARGET_64_BIG |
61ba1cf9 ILT |
992 | template |
993 | void | |
f6ce93d6 | 994 | Sized_relobj<64, true>::do_relocate(const General_options& options, |
61ba1cf9 | 995 | const Symbol_table* symtab, |
92e059d8 | 996 | const Layout* layout, |
61ba1cf9 | 997 | Output_file* of); |
193a53d9 | 998 | #endif |
61ba1cf9 | 999 | |
a9a60db6 ILT |
1000 | #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) |
1001 | template | |
1002 | class Merged_symbol_value<32>; | |
1003 | #endif | |
1004 | ||
1005 | #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) | |
1006 | template | |
1007 | class Merged_symbol_value<64>; | |
1008 | #endif | |
1009 | ||
1010 | #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) | |
1011 | template | |
1012 | class Symbol_value<32>; | |
1013 | #endif | |
1014 | ||
1015 | #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) | |
1016 | template | |
1017 | class Symbol_value<64>; | |
1018 | #endif | |
1019 | ||
193a53d9 | 1020 | #ifdef HAVE_TARGET_32_LITTLE |
a3ad94ed | 1021 | template |
5a6f7e2d | 1022 | class Copy_relocs<32, false>; |
193a53d9 | 1023 | #endif |
a3ad94ed | 1024 | |
193a53d9 | 1025 | #ifdef HAVE_TARGET_32_BIG |
a3ad94ed | 1026 | template |
5a6f7e2d | 1027 | class Copy_relocs<32, true>; |
193a53d9 | 1028 | #endif |
a3ad94ed | 1029 | |
193a53d9 | 1030 | #ifdef HAVE_TARGET_64_LITTLE |
a3ad94ed | 1031 | template |
5a6f7e2d | 1032 | class Copy_relocs<64, false>; |
193a53d9 | 1033 | #endif |
a3ad94ed | 1034 | |
193a53d9 | 1035 | #ifdef HAVE_TARGET_64_BIG |
a3ad94ed | 1036 | template |
5a6f7e2d | 1037 | class Copy_relocs<64, true>; |
193a53d9 | 1038 | #endif |
5a6f7e2d | 1039 | |
193a53d9 | 1040 | #ifdef HAVE_TARGET_32_LITTLE |
5a6f7e2d ILT |
1041 | template |
1042 | void | |
1043 | Copy_relocs<32, false>::emit<elfcpp::SHT_REL>( | |
1044 | Output_data_reloc<elfcpp::SHT_REL, true, 32, false>*); | |
193a53d9 | 1045 | #endif |
5a6f7e2d | 1046 | |
193a53d9 | 1047 | #ifdef HAVE_TARGET_32_BIG |
5a6f7e2d ILT |
1048 | template |
1049 | void | |
1050 | Copy_relocs<32, true>::emit<elfcpp::SHT_REL>( | |
1051 | Output_data_reloc<elfcpp::SHT_REL, true, 32, true>*); | |
193a53d9 | 1052 | #endif |
5a6f7e2d | 1053 | |
193a53d9 | 1054 | #ifdef HAVE_TARGET_64_LITTLE |
5a6f7e2d ILT |
1055 | template |
1056 | void | |
1057 | Copy_relocs<64, false>::emit<elfcpp::SHT_REL>( | |
1058 | Output_data_reloc<elfcpp::SHT_REL, true, 64, false>*); | |
193a53d9 | 1059 | #endif |
5a6f7e2d | 1060 | |
193a53d9 | 1061 | #ifdef HAVE_TARGET_64_BIG |
5a6f7e2d ILT |
1062 | template |
1063 | void | |
1064 | Copy_relocs<64, true>::emit<elfcpp::SHT_REL>( | |
1065 | Output_data_reloc<elfcpp::SHT_REL, true, 64, true>*); | |
193a53d9 | 1066 | #endif |
5a6f7e2d | 1067 | |
193a53d9 | 1068 | #ifdef HAVE_TARGET_32_LITTLE |
5a6f7e2d ILT |
1069 | template |
1070 | void | |
1071 | Copy_relocs<32, false>::emit<elfcpp::SHT_RELA>( | |
1072 | Output_data_reloc<elfcpp::SHT_RELA , true, 32, false>*); | |
193a53d9 | 1073 | #endif |
5a6f7e2d | 1074 | |
193a53d9 | 1075 | #ifdef HAVE_TARGET_32_BIG |
5a6f7e2d ILT |
1076 | template |
1077 | void | |
1078 | Copy_relocs<32, true>::emit<elfcpp::SHT_RELA>( | |
1079 | Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>*); | |
193a53d9 | 1080 | #endif |
5a6f7e2d | 1081 | |
193a53d9 | 1082 | #ifdef HAVE_TARGET_64_LITTLE |
5a6f7e2d ILT |
1083 | template |
1084 | void | |
1085 | Copy_relocs<64, false>::emit<elfcpp::SHT_RELA>( | |
1086 | Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>*); | |
193a53d9 | 1087 | #endif |
5a6f7e2d | 1088 | |
193a53d9 | 1089 | #ifdef HAVE_TARGET_64_BIG |
5a6f7e2d ILT |
1090 | template |
1091 | void | |
1092 | Copy_relocs<64, true>::emit<elfcpp::SHT_RELA>( | |
1093 | Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>*); | |
193a53d9 | 1094 | #endif |
61ba1cf9 | 1095 | |
730cdc88 ILT |
1096 | #ifdef HAVE_TARGET_32_LITTLE |
1097 | template | |
1098 | class Track_relocs<32, false>; | |
1099 | #endif | |
1100 | ||
1101 | #ifdef HAVE_TARGET_32_BIG | |
1102 | template | |
1103 | class Track_relocs<32, true>; | |
1104 | #endif | |
1105 | ||
1106 | #ifdef HAVE_TARGET_64_LITTLE | |
1107 | template | |
1108 | class Track_relocs<64, false>; | |
1109 | #endif | |
1110 | ||
1111 | #ifdef HAVE_TARGET_64_BIG | |
1112 | template | |
1113 | class Track_relocs<64, true>; | |
1114 | #endif | |
1115 | ||
61ba1cf9 | 1116 | } // End namespace gold. |