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