]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/elf32-fr30.c
PR ld/13991
[thirdparty/binutils-gdb.git] / bfd / elf32-fr30.c
CommitLineData
252b5132 1/* FR30-specific support for 32-bit ELF.
dbaa2011
AM
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2010, 2012
1049f94e 4 Free Software Foundation, Inc.
252b5132 5
cd123cb7 6 This file is part of BFD, the Binary File Descriptor library.
252b5132 7
cd123cb7
NC
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.
252b5132 12
cd123cb7
NC
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.
252b5132 17
cd123cb7
NC
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. */
252b5132 22
252b5132 23#include "sysdep.h"
3db64b00 24#include "bfd.h"
252b5132
RH
25#include "libbfd.h"
26#include "elf-bfd.h"
27#include "elf/fr30.h"
28
29/* Forward declarations. */
30static bfd_reloc_status_type fr30_elf_i20_reloc
31 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
32static bfd_reloc_status_type fr30_elf_i32_reloc
33 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
34static reloc_howto_type * fr30_reloc_type_lookup
35 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
6609fa74 36static void fr30_info_to_howto_rela
947216bf 37 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
b34976b6 38static bfd_boolean fr30_elf_relocate_section
dc810e39
AM
39 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
40 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
252b5132 41static bfd_reloc_status_type fr30_final_link_relocate
dc810e39
AM
42 PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
43 Elf_Internal_Rela *, bfd_vma));
b34976b6 44static bfd_boolean fr30_elf_check_relocs
dc810e39
AM
45 PARAMS ((bfd *, struct bfd_link_info *, asection *,
46 const Elf_Internal_Rela *));
252b5132
RH
47
48static reloc_howto_type fr30_elf_howto_table [] =
49{
50 /* This reloc does nothing. */
51 HOWTO (R_FR30_NONE, /* type */
52 0, /* rightshift */
53 2, /* size (0 = byte, 1 = short, 2 = long) */
54 32, /* bitsize */
b34976b6 55 FALSE, /* pc_relative */
252b5132
RH
56 0, /* bitpos */
57 complain_overflow_bitfield, /* complain_on_overflow */
58 bfd_elf_generic_reloc, /* special_function */
59 "R_FR30_NONE", /* name */
b34976b6 60 FALSE, /* partial_inplace */
252b5132
RH
61 0, /* src_mask */
62 0, /* dst_mask */
b34976b6 63 FALSE), /* pcrel_offset */
252b5132
RH
64
65 /* An 8 bit absolute relocation. */
66 HOWTO (R_FR30_8, /* type */
67 0, /* rightshift */
68 1, /* size (0 = byte, 1 = short, 2 = long) */
69 8, /* bitsize */
b34976b6 70 FALSE, /* pc_relative */
252b5132
RH
71 4, /* bitpos */
72 complain_overflow_bitfield, /* complain_on_overflow */
73 bfd_elf_generic_reloc, /* special_function */
74 "R_FR30_8", /* name */
d2e2e649 75 FALSE, /* partial_inplace */
252b5132
RH
76 0x0000, /* src_mask */
77 0x0ff0, /* dst_mask */
b34976b6 78 FALSE), /* pcrel_offset */
252b5132
RH
79
80 /* A 20 bit absolute relocation. */
81 HOWTO (R_FR30_20, /* type */
82 0, /* rightshift */
83 2, /* size (0 = byte, 1 = short, 2 = long) */
84 20, /* bitsize */
b34976b6 85 FALSE, /* pc_relative */
252b5132
RH
86 0, /* bitpos */
87 complain_overflow_bitfield, /* complain_on_overflow */
88 fr30_elf_i20_reloc, /* special_function */
89 "R_FR30_20", /* name */
d2e2e649 90 FALSE, /* partial_inplace */
252b5132
RH
91 0x00000000, /* src_mask */
92 0x00f0ffff, /* dst_mask */
b34976b6 93 FALSE), /* pcrel_offset */
252b5132
RH
94
95 /* A 32 bit absolute relocation. */
96 HOWTO (R_FR30_32, /* type */
97 0, /* rightshift */
98 2, /* size (0 = byte, 1 = short, 2 = long) */
99 32, /* bitsize */
b34976b6 100 FALSE, /* pc_relative */
252b5132
RH
101 0, /* bitpos */
102 complain_overflow_bitfield, /* complain_on_overflow */
103 bfd_elf_generic_reloc, /* special_function */
104 "R_FR30_32", /* name */
d2e2e649 105 FALSE, /* partial_inplace */
252b5132
RH
106 0x00000000, /* src_mask */
107 0xffffffff, /* dst_mask */
b34976b6 108 FALSE), /* pcrel_offset */
252b5132
RH
109
110 /* A 32 bit into 48 bits absolute relocation. */
111 HOWTO (R_FR30_48, /* type */
112 0, /* rightshift */
113 2, /* size (0 = byte, 1 = short, 2 = long) */
114 32, /* bitsize */
b34976b6 115 FALSE, /* pc_relative */
252b5132
RH
116 0, /* bitpos */
117 complain_overflow_bitfield, /* complain_on_overflow */
118 fr30_elf_i32_reloc, /* special_function */
119 "R_FR30_48", /* name */
d2e2e649 120 FALSE, /* partial_inplace */
252b5132
RH
121 0x00000000, /* src_mask */
122 0xffffffff, /* dst_mask */
b34976b6 123 FALSE), /* pcrel_offset */
252b5132
RH
124
125 /* A 6 bit absolute relocation. */
126 HOWTO (R_FR30_6_IN_4, /* type */
127 2, /* rightshift */
128 1, /* size (0 = byte, 1 = short, 2 = long) */
129 6, /* bitsize */
b34976b6 130 FALSE, /* pc_relative */
252b5132
RH
131 4, /* bitpos */
132 complain_overflow_unsigned, /* complain_on_overflow */
133 bfd_elf_generic_reloc, /* special_function */
134 "R_FR30_6_IN_4", /* name */
d2e2e649 135 FALSE, /* partial_inplace */
252b5132
RH
136 0x0000, /* src_mask */
137 0x00f0, /* dst_mask */
b34976b6 138 FALSE), /* pcrel_offset */
6609fa74 139
252b5132
RH
140 /* An 8 bit absolute relocation. */
141 HOWTO (R_FR30_8_IN_8, /* type */
142 0, /* rightshift */
143 1, /* size (0 = byte, 1 = short, 2 = long) */
144 8, /* bitsize */
b34976b6 145 FALSE, /* pc_relative */
252b5132
RH
146 4, /* bitpos */
147 complain_overflow_signed, /* complain_on_overflow */
148 bfd_elf_generic_reloc,/* special_function */
149 "R_FR30_8_IN_8", /* name */
d2e2e649 150 FALSE, /* partial_inplace */
252b5132
RH
151 0x0000, /* src_mask */
152 0x0ff0, /* dst_mask */
b34976b6 153 FALSE), /* pcrel_offset */
6609fa74 154
252b5132
RH
155 /* A 9 bit absolute relocation. */
156 HOWTO (R_FR30_9_IN_8, /* type */
157 1, /* rightshift */
158 1, /* size (0 = byte, 1 = short, 2 = long) */
159 9, /* bitsize */
b34976b6 160 FALSE, /* pc_relative */
252b5132
RH
161 4, /* bitpos */
162 complain_overflow_signed, /* complain_on_overflow */
163 bfd_elf_generic_reloc,/* special_function */
164 "R_FR30_9_IN_8", /* name */
d2e2e649 165 FALSE, /* partial_inplace */
252b5132
RH
166 0x0000, /* src_mask */
167 0x0ff0, /* dst_mask */
b34976b6 168 FALSE), /* pcrel_offset */
6609fa74 169
252b5132
RH
170 /* A 10 bit absolute relocation. */
171 HOWTO (R_FR30_10_IN_8, /* type */
172 2, /* rightshift */
173 1, /* size (0 = byte, 1 = short, 2 = long) */
174 10, /* bitsize */
b34976b6 175 FALSE, /* pc_relative */
252b5132
RH
176 4, /* bitpos */
177 complain_overflow_signed, /* complain_on_overflow */
178 bfd_elf_generic_reloc,/* special_function */
179 "R_FR30_10_IN_8", /* name */
d2e2e649 180 FALSE, /* partial_inplace */
252b5132
RH
181 0x0000, /* src_mask */
182 0x0ff0, /* dst_mask */
b34976b6 183 FALSE), /* pcrel_offset */
252b5132
RH
184
185 /* A PC relative 9 bit relocation, right shifted by 1. */
186 HOWTO (R_FR30_9_PCREL, /* type */
187 1, /* rightshift */
188 1, /* size (0 = byte, 1 = short, 2 = long) */
189 9, /* bitsize */
b34976b6 190 TRUE, /* pc_relative */
252b5132
RH
191 0, /* bitpos */
192 complain_overflow_signed, /* complain_on_overflow */
193 bfd_elf_generic_reloc, /* special_function */
194 "R_FR30_9_PCREL", /* name */
b34976b6 195 FALSE, /* partial_inplace */
252b5132
RH
196 0x0000, /* src_mask */
197 0x00ff, /* dst_mask */
b34976b6 198 FALSE), /* pcrel_offset */
252b5132
RH
199
200 /* A PC relative 12 bit relocation, right shifted by 1. */
201 HOWTO (R_FR30_12_PCREL, /* type */
202 1, /* rightshift */
203 1, /* size (0 = byte, 1 = short, 2 = long) */
204 12, /* bitsize */
b34976b6 205 TRUE, /* pc_relative */
252b5132
RH
206 0, /* bitpos */
207 complain_overflow_signed, /* complain_on_overflow */
208 bfd_elf_generic_reloc, /* special_function */
209 "R_FR30_12_PCREL", /* name */
b34976b6 210 FALSE, /* partial_inplace */
252b5132
RH
211 0x0000, /* src_mask */
212 0x07ff, /* dst_mask */
b34976b6 213 FALSE), /* pcrel_offset */
252b5132
RH
214 /* GNU extension to record C++ vtable hierarchy */
215 HOWTO (R_FR30_GNU_VTINHERIT, /* type */
216 0, /* rightshift */
217 2, /* size (0 = byte, 1 = short, 2 = long) */
218 0, /* bitsize */
b34976b6 219 FALSE, /* pc_relative */
252b5132
RH
220 0, /* bitpos */
221 complain_overflow_dont, /* complain_on_overflow */
222 NULL, /* special_function */
223 "R_FR30_GNU_VTINHERIT", /* name */
b34976b6 224 FALSE, /* partial_inplace */
252b5132
RH
225 0, /* src_mask */
226 0, /* dst_mask */
b34976b6 227 FALSE), /* pcrel_offset */
252b5132
RH
228
229 /* GNU extension to record C++ vtable member usage */
230 HOWTO (R_FR30_GNU_VTENTRY, /* type */
231 0, /* rightshift */
232 2, /* size (0 = byte, 1 = short, 2 = long) */
233 0, /* bitsize */
b34976b6 234 FALSE, /* pc_relative */
252b5132
RH
235 0, /* bitpos */
236 complain_overflow_dont, /* complain_on_overflow */
237 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
238 "R_FR30_GNU_VTENTRY", /* name */
b34976b6 239 FALSE, /* partial_inplace */
252b5132
RH
240 0, /* src_mask */
241 0, /* dst_mask */
b34976b6 242 FALSE), /* pcrel_offset */
252b5132
RH
243};
244\f
245/* Utility to actually perform an R_FR30_20 reloc. */
246
247static bfd_reloc_status_type
248fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
249 input_section, output_bfd, error_message)
b34976b6
AM
250 bfd *abfd;
251 arelent *reloc_entry;
252 asymbol *symbol;
253 PTR data;
254 asection *input_section;
255 bfd *output_bfd;
256 char **error_message ATTRIBUTE_UNUSED;
252b5132 257{
b34976b6 258 bfd_vma relocation;
252b5132 259 unsigned long x;
6609fa74 260
252b5132
RH
261 /* This part is from bfd_elf_generic_reloc. */
262 if (output_bfd != (bfd *) NULL
263 && (symbol->flags & BSF_SECTION_SYM) == 0
264 && (! reloc_entry->howto->partial_inplace
265 || reloc_entry->addend == 0))
266 {
267 reloc_entry->address += input_section->output_offset;
268 return bfd_reloc_ok;
269 }
270
271 if (output_bfd != NULL)
272 /* FIXME: See bfd_perform_relocation. Is this right? */
273 return bfd_reloc_ok;
274
275 relocation =
276 symbol->value
277 + symbol->section->output_section->vma
278 + symbol->section->output_offset
279 + reloc_entry->addend;
280
fc633e5b 281 if (relocation > (((bfd_vma) 1 << 20) - 1))
252b5132
RH
282 return bfd_reloc_overflow;
283
23ccc829 284 x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
252b5132 285 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
dc810e39 286 bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
252b5132
RH
287
288 return bfd_reloc_ok;
289}
252b5132
RH
290\f
291/* Utility to actually perform a R_FR30_48 reloc. */
292
293static bfd_reloc_status_type
294fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
295 input_section, output_bfd, error_message)
b34976b6
AM
296 bfd *abfd;
297 arelent *reloc_entry;
298 asymbol *symbol;
299 PTR data;
300 asection *input_section;
301 bfd *output_bfd;
302 char **error_message ATTRIBUTE_UNUSED;
252b5132 303{
b34976b6 304 bfd_vma relocation;
252b5132
RH
305
306 /* This part is from bfd_elf_generic_reloc. */
307 if (output_bfd != (bfd *) NULL
308 && (symbol->flags & BSF_SECTION_SYM) == 0
309 && (! reloc_entry->howto->partial_inplace
310 || reloc_entry->addend == 0))
311 {
312 reloc_entry->address += input_section->output_offset;
313 return bfd_reloc_ok;
314 }
315
316 if (output_bfd != NULL)
317 /* FIXME: See bfd_perform_relocation. Is this right? */
318 return bfd_reloc_ok;
319
320 relocation =
321 symbol->value
322 + symbol->section->output_section->vma
323 + symbol->section->output_offset
324 + reloc_entry->addend;
325
23ccc829 326 bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
252b5132
RH
327
328 return bfd_reloc_ok;
329}
330\f
331/* Map BFD reloc types to FR30 ELF reloc types. */
332
333struct fr30_reloc_map
334{
335 bfd_reloc_code_real_type bfd_reloc_val;
336 unsigned int fr30_reloc_val;
337};
338
339static const struct fr30_reloc_map fr30_reloc_map [] =
340{
341 { BFD_RELOC_NONE, R_FR30_NONE },
342 { BFD_RELOC_8, R_FR30_8 },
343 { BFD_RELOC_FR30_20, R_FR30_20 },
344 { BFD_RELOC_32, R_FR30_32 },
345 { BFD_RELOC_FR30_48, R_FR30_48 },
346 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
347 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
348 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
349 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
350 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
351 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
352 { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
353 { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY },
354};
355
356static reloc_howto_type *
357fr30_reloc_type_lookup (abfd, code)
b34976b6 358 bfd *abfd ATTRIBUTE_UNUSED;
252b5132
RH
359 bfd_reloc_code_real_type code;
360{
361 unsigned int i;
362
363 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
364 --i;)
365 if (fr30_reloc_map [i].bfd_reloc_val == code)
366 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
6609fa74 367
252b5132
RH
368 return NULL;
369}
370
157090f7
AM
371static reloc_howto_type *
372fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
373{
374 unsigned int i;
375
376 for (i = 0;
377 i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
378 i++)
379 if (fr30_elf_howto_table[i].name != NULL
380 && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
381 return &fr30_elf_howto_table[i];
382
383 return NULL;
384}
385
252b5132
RH
386/* Set the howto pointer for an FR30 ELF reloc. */
387
388static void
389fr30_info_to_howto_rela (abfd, cache_ptr, dst)
b34976b6
AM
390 bfd *abfd ATTRIBUTE_UNUSED;
391 arelent *cache_ptr;
392 Elf_Internal_Rela *dst;
252b5132
RH
393{
394 unsigned int r_type;
395
396 r_type = ELF32_R_TYPE (dst->r_info);
397 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
398 cache_ptr->howto = & fr30_elf_howto_table [r_type];
399}
400\f
401/* Perform a single relocation. By default we use the standard BFD
402 routines, but a few relocs, we have to do them ourselves. */
403
404static bfd_reloc_status_type
b34976b6
AM
405fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel,
406 relocation)
407 reloc_howto_type *howto;
408 bfd *input_bfd;
409 asection *input_section;
410 bfd_byte *contents;
411 Elf_Internal_Rela *rel;
412 bfd_vma relocation;
252b5132
RH
413{
414 bfd_reloc_status_type r = bfd_reloc_ok;
b34976b6
AM
415 bfd_vma x;
416 bfd_signed_vma srel;
6609fa74 417
252b5132
RH
418 switch (howto->type)
419 {
420 case R_FR30_20:
421 contents += rel->r_offset;
422 relocation += rel->r_addend;
423
424 if (relocation > ((1 << 20) - 1))
425 return bfd_reloc_overflow;
6609fa74 426
252b5132
RH
427 x = bfd_get_32 (input_bfd, contents);
428 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
429 bfd_put_32 (input_bfd, x, contents);
430 break;
6609fa74 431
252b5132
RH
432 case R_FR30_48:
433 contents += rel->r_offset + 2;
434 relocation += rel->r_addend;
435 bfd_put_32 (input_bfd, relocation, contents);
436 break;
437
438 case R_FR30_9_PCREL:
439 contents += rel->r_offset + 1;
440 srel = (bfd_signed_vma) relocation;
441 srel += rel->r_addend;
442 srel -= rel->r_offset;
6609fa74 443 srel -= 2; /* Branch instructions add 2 to the PC... */
252b5132
RH
444 srel -= (input_section->output_section->vma +
445 input_section->output_offset);
6609fa74 446
252b5132
RH
447 if (srel & 1)
448 return bfd_reloc_outofrange;
449 if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
450 return bfd_reloc_overflow;
451
452 bfd_put_8 (input_bfd, srel >> 1, contents);
453 break;
454
455 case R_FR30_12_PCREL:
456 contents += rel->r_offset;
457 srel = (bfd_signed_vma) relocation;
458 srel += rel->r_addend;
459 srel -= rel->r_offset;
6609fa74 460 srel -= 2; /* Branch instructions add 2 to the PC... */
252b5132
RH
461 srel -= (input_section->output_section->vma +
462 input_section->output_offset);
6609fa74 463
252b5132
RH
464 if (srel & 1)
465 return bfd_reloc_outofrange;
466 if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
467 return bfd_reloc_overflow;
6609fa74 468
252b5132
RH
469 x = bfd_get_16 (input_bfd, contents);
470 x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
471 bfd_put_16 (input_bfd, x, contents);
472 break;
473
474 default:
475 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
476 contents, rel->r_offset,
477 relocation, rel->r_addend);
478 }
479
480 return r;
481}
252b5132
RH
482\f
483/* Relocate an FR30 ELF section.
252b5132
RH
484
485 The RELOCATE_SECTION function is called by the new ELF backend linker
486 to handle the relocations for a section.
487
488 The relocs are always passed as Rela structures; if the section
489 actually uses Rel structures, the r_addend field will always be
490 zero.
491
492 This function is responsible for adjusting the section contents as
1049f94e 493 necessary, and (if using Rela relocs and generating a relocatable
252b5132
RH
494 output file) adjusting the reloc addend as necessary.
495
496 This function does not have to worry about setting the reloc
497 address or the reloc symbol index.
498
499 LOCAL_SYMS is a pointer to the swapped in local symbols.
500
501 LOCAL_SECTIONS is an array giving the section in the input file
502 corresponding to the st_shndx field of each local symbol.
503
504 The global hash table entry for the global symbols can be found
505 via elf_sym_hashes (input_bfd).
506
1049f94e 507 When generating relocatable output, this function must handle
252b5132
RH
508 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
509 going to be the section symbol corresponding to the output
510 section, which means that the addend must be adjusted
511 accordingly. */
512
b34976b6 513static bfd_boolean
252b5132
RH
514fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
515 contents, relocs, local_syms, local_sections)
b34976b6
AM
516 bfd *output_bfd;
517 struct bfd_link_info *info;
518 bfd *input_bfd;
519 asection *input_section;
520 bfd_byte *contents;
521 Elf_Internal_Rela *relocs;
522 Elf_Internal_Sym *local_syms;
523 asection **local_sections;
252b5132 524{
b34976b6
AM
525 Elf_Internal_Shdr *symtab_hdr;
526 struct elf_link_hash_entry **sym_hashes;
527 Elf_Internal_Rela *rel;
528 Elf_Internal_Rela *relend;
252b5132
RH
529
530 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
531 sym_hashes = elf_sym_hashes (input_bfd);
532 relend = relocs + input_section->reloc_count;
533
534 for (rel = relocs; rel < relend; rel ++)
535 {
b34976b6
AM
536 reloc_howto_type *howto;
537 unsigned long r_symndx;
538 Elf_Internal_Sym *sym;
539 asection *sec;
540 struct elf_link_hash_entry *h;
541 bfd_vma relocation;
542 bfd_reloc_status_type r;
dfeffb9f 543 const char *name;
b34976b6 544 int r_type;
6609fa74 545
252b5132 546 r_type = ELF32_R_TYPE (rel->r_info);
6609fa74 547
252b5132
RH
548 if ( r_type == R_FR30_GNU_VTINHERIT
549 || r_type == R_FR30_GNU_VTENTRY)
550 continue;
6609fa74 551
252b5132
RH
552 r_symndx = ELF32_R_SYM (rel->r_info);
553
252b5132
RH
554 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
555 h = NULL;
556 sym = NULL;
557 sec = NULL;
6609fa74 558
252b5132
RH
559 if (r_symndx < symtab_hdr->sh_info)
560 {
561 sym = local_syms + r_symndx;
562 sec = local_sections [r_symndx];
8517fae7 563 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
6609fa74 564
252b5132
RH
565 name = bfd_elf_string_from_elf_section
566 (input_bfd, symtab_hdr->sh_link, sym->st_name);
567 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
252b5132
RH
568 }
569 else
570 {
59c2e50f 571 bfd_boolean unresolved_reloc, warned;
6609fa74 572
b2a8e766
AM
573 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
574 r_symndx, symtab_hdr, sym_hashes,
575 h, sec, relocation,
576 unresolved_reloc, warned);
dfeffb9f
L
577
578 name = h->root.root.string;
252b5132 579 }
6609fa74 580
dbaa2011 581 if (sec != NULL && discarded_section (sec))
e4067dbb
DJ
582 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
583 rel, relend, howto, contents);
ab96bf03
AM
584
585 if (info->relocatable)
586 continue;
587
252b5132
RH
588 r = fr30_final_link_relocate (howto, input_bfd, input_section,
589 contents, rel, relocation);
590
591 if (r != bfd_reloc_ok)
592 {
593 const char * msg = (const char *) NULL;
594
595 switch (r)
596 {
597 case bfd_reloc_overflow:
598 r = info->callbacks->reloc_overflow
dfeffb9f
L
599 (info, (h ? &h->root : NULL), name, howto->name,
600 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
252b5132 601 break;
6609fa74 602
252b5132
RH
603 case bfd_reloc_undefined:
604 r = info->callbacks->undefined_symbol
5cc7c785 605 (info, name, input_bfd, input_section, rel->r_offset,
b34976b6 606 TRUE);
252b5132 607 break;
6609fa74 608
252b5132
RH
609 case bfd_reloc_outofrange:
610 msg = _("internal error: out of range error");
611 break;
612
613 case bfd_reloc_notsupported:
614 msg = _("internal error: unsupported relocation error");
615 break;
616
617 case bfd_reloc_dangerous:
618 msg = _("internal error: dangerous relocation");
619 break;
620
621 default:
622 msg = _("internal error: unknown error");
623 break;
624 }
625
626 if (msg)
627 r = info->callbacks->warning
628 (info, msg, name, input_bfd, input_section, rel->r_offset);
629
630 if (! r)
b34976b6 631 return FALSE;
252b5132
RH
632 }
633 }
634
b34976b6 635 return TRUE;
252b5132
RH
636}
637\f
638/* Return the section that should be marked against GC for a given
639 relocation. */
640
641static asection *
07adf181
AM
642fr30_elf_gc_mark_hook (asection *sec,
643 struct bfd_link_info *info,
644 Elf_Internal_Rela *rel,
645 struct elf_link_hash_entry *h,
646 Elf_Internal_Sym *sym)
252b5132
RH
647{
648 if (h != NULL)
07adf181
AM
649 switch (ELF32_R_TYPE (rel->r_info))
650 {
651 case R_FR30_GNU_VTINHERIT:
652 case R_FR30_GNU_VTENTRY:
653 return NULL;
654 }
655
656 return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
252b5132
RH
657}
658
659/* Look through the relocs for a section during the first phase.
660 Since we don't do .gots or .plts, we just need to consider the
661 virtual table relocs for gc. */
6609fa74 662
b34976b6 663static bfd_boolean
252b5132
RH
664fr30_elf_check_relocs (abfd, info, sec, relocs)
665 bfd *abfd;
666 struct bfd_link_info *info;
667 asection *sec;
668 const Elf_Internal_Rela *relocs;
669{
670 Elf_Internal_Shdr *symtab_hdr;
5582a088 671 struct elf_link_hash_entry **sym_hashes;
252b5132
RH
672 const Elf_Internal_Rela *rel;
673 const Elf_Internal_Rela *rel_end;
6609fa74 674
1049f94e 675 if (info->relocatable)
b34976b6 676 return TRUE;
6609fa74 677
252b5132
RH
678 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
679 sym_hashes = elf_sym_hashes (abfd);
6609fa74 680
252b5132
RH
681 rel_end = relocs + sec->reloc_count;
682 for (rel = relocs; rel < rel_end; rel++)
683 {
684 struct elf_link_hash_entry *h;
685 unsigned long r_symndx;
6609fa74 686
252b5132
RH
687 r_symndx = ELF32_R_SYM (rel->r_info);
688 if (r_symndx < symtab_hdr->sh_info)
689 h = NULL;
690 else
973a3492
L
691 {
692 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
693 while (h->root.type == bfd_link_hash_indirect
694 || h->root.type == bfd_link_hash_warning)
695 h = (struct elf_link_hash_entry *) h->root.u.i.link;
696 }
6609fa74 697
252b5132
RH
698 switch (ELF32_R_TYPE (rel->r_info))
699 {
700 /* This relocation describes the C++ object vtable hierarchy.
701 Reconstruct it for later use during GC. */
702 case R_FR30_GNU_VTINHERIT:
c152c796 703 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
b34976b6 704 return FALSE;
252b5132 705 break;
6609fa74 706
252b5132
RH
707 /* This relocation describes which C++ vtable entries are actually
708 used. Record for later use during GC. */
709 case R_FR30_GNU_VTENTRY:
d17e0c6e
JB
710 BFD_ASSERT (h != NULL);
711 if (h != NULL
712 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
b34976b6 713 return FALSE;
252b5132
RH
714 break;
715 }
716 }
6609fa74 717
b34976b6 718 return TRUE;
252b5132
RH
719}
720\f
721#define ELF_ARCH bfd_arch_fr30
aa4f99bb
AO
722#define ELF_MACHINE_CODE EM_FR30
723#define ELF_MACHINE_ALT1 EM_CYGNUS_FR30
252b5132
RH
724#define ELF_MAXPAGESIZE 0x1000
725
726#define TARGET_BIG_SYM bfd_elf32_fr30_vec
727#define TARGET_BIG_NAME "elf32-fr30"
728
729#define elf_info_to_howto_rel NULL
730#define elf_info_to_howto fr30_info_to_howto_rela
731#define elf_backend_relocate_section fr30_elf_relocate_section
732#define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook
252b5132
RH
733#define elf_backend_check_relocs fr30_elf_check_relocs
734
735#define elf_backend_can_gc_sections 1
b491616a 736#define elf_backend_rela_normal 1
252b5132
RH
737
738#define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
157090f7 739#define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup
252b5132
RH
740
741#include "elf32-target.h"