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