1 /* FR30-specific support for 32-bit ELF.
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
4 Free Software Foundation, Inc.
6 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
29 /* Forward declarations. */
30 static bfd_reloc_status_type fr30_elf_i20_reloc
31 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
32 static bfd_reloc_status_type fr30_elf_i32_reloc
33 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
34 static reloc_howto_type * fr30_reloc_type_lookup
35 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
36 static void fr30_info_to_howto_rela
37 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
38 static bfd_boolean fr30_elf_relocate_section
39 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
40 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
41 static bfd_reloc_status_type fr30_final_link_relocate
42 PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
43 Elf_Internal_Rela *, bfd_vma));
44 static bfd_boolean fr30_elf_check_relocs
45 PARAMS ((bfd *, struct bfd_link_info *, asection *,
46 const Elf_Internal_Rela *));
48 static reloc_howto_type fr30_elf_howto_table [] =
50 /* This reloc does nothing. */
51 HOWTO (R_FR30_NONE, /* type */
53 2, /* size (0 = byte, 1 = short, 2 = long) */
55 FALSE, /* pc_relative */
57 complain_overflow_bitfield, /* complain_on_overflow */
58 bfd_elf_generic_reloc, /* special_function */
59 "R_FR30_NONE", /* name */
60 FALSE, /* partial_inplace */
63 FALSE), /* pcrel_offset */
65 /* An 8 bit absolute relocation. */
66 HOWTO (R_FR30_8, /* type */
68 1, /* size (0 = byte, 1 = short, 2 = long) */
70 FALSE, /* pc_relative */
72 complain_overflow_bitfield, /* complain_on_overflow */
73 bfd_elf_generic_reloc, /* special_function */
74 "R_FR30_8", /* name */
75 FALSE, /* partial_inplace */
76 0x0000, /* src_mask */
77 0x0ff0, /* dst_mask */
78 FALSE), /* pcrel_offset */
80 /* A 20 bit absolute relocation. */
81 HOWTO (R_FR30_20, /* type */
83 2, /* size (0 = byte, 1 = short, 2 = long) */
85 FALSE, /* pc_relative */
87 complain_overflow_bitfield, /* complain_on_overflow */
88 fr30_elf_i20_reloc, /* special_function */
89 "R_FR30_20", /* name */
90 FALSE, /* partial_inplace */
91 0x00000000, /* src_mask */
92 0x00f0ffff, /* dst_mask */
93 FALSE), /* pcrel_offset */
95 /* A 32 bit absolute relocation. */
96 HOWTO (R_FR30_32, /* type */
98 2, /* size (0 = byte, 1 = short, 2 = long) */
100 FALSE, /* pc_relative */
102 complain_overflow_bitfield, /* complain_on_overflow */
103 bfd_elf_generic_reloc, /* special_function */
104 "R_FR30_32", /* name */
105 FALSE, /* partial_inplace */
106 0x00000000, /* src_mask */
107 0xffffffff, /* dst_mask */
108 FALSE), /* pcrel_offset */
110 /* A 32 bit into 48 bits absolute relocation. */
111 HOWTO (R_FR30_48, /* type */
113 2, /* size (0 = byte, 1 = short, 2 = long) */
115 FALSE, /* pc_relative */
117 complain_overflow_bitfield, /* complain_on_overflow */
118 fr30_elf_i32_reloc, /* special_function */
119 "R_FR30_48", /* name */
120 FALSE, /* partial_inplace */
121 0x00000000, /* src_mask */
122 0xffffffff, /* dst_mask */
123 FALSE), /* pcrel_offset */
125 /* A 6 bit absolute relocation. */
126 HOWTO (R_FR30_6_IN_4, /* type */
128 1, /* size (0 = byte, 1 = short, 2 = long) */
130 FALSE, /* pc_relative */
132 complain_overflow_unsigned, /* complain_on_overflow */
133 bfd_elf_generic_reloc, /* special_function */
134 "R_FR30_6_IN_4", /* name */
135 FALSE, /* partial_inplace */
136 0x0000, /* src_mask */
137 0x00f0, /* dst_mask */
138 FALSE), /* pcrel_offset */
140 /* An 8 bit absolute relocation. */
141 HOWTO (R_FR30_8_IN_8, /* type */
143 1, /* size (0 = byte, 1 = short, 2 = long) */
145 FALSE, /* pc_relative */
147 complain_overflow_signed, /* complain_on_overflow */
148 bfd_elf_generic_reloc,/* special_function */
149 "R_FR30_8_IN_8", /* name */
150 FALSE, /* partial_inplace */
151 0x0000, /* src_mask */
152 0x0ff0, /* dst_mask */
153 FALSE), /* pcrel_offset */
155 /* A 9 bit absolute relocation. */
156 HOWTO (R_FR30_9_IN_8, /* type */
158 1, /* size (0 = byte, 1 = short, 2 = long) */
160 FALSE, /* pc_relative */
162 complain_overflow_signed, /* complain_on_overflow */
163 bfd_elf_generic_reloc,/* special_function */
164 "R_FR30_9_IN_8", /* name */
165 FALSE, /* partial_inplace */
166 0x0000, /* src_mask */
167 0x0ff0, /* dst_mask */
168 FALSE), /* pcrel_offset */
170 /* A 10 bit absolute relocation. */
171 HOWTO (R_FR30_10_IN_8, /* type */
173 1, /* size (0 = byte, 1 = short, 2 = long) */
175 FALSE, /* pc_relative */
177 complain_overflow_signed, /* complain_on_overflow */
178 bfd_elf_generic_reloc,/* special_function */
179 "R_FR30_10_IN_8", /* name */
180 FALSE, /* partial_inplace */
181 0x0000, /* src_mask */
182 0x0ff0, /* dst_mask */
183 FALSE), /* pcrel_offset */
185 /* A PC relative 9 bit relocation, right shifted by 1. */
186 HOWTO (R_FR30_9_PCREL, /* type */
188 1, /* size (0 = byte, 1 = short, 2 = long) */
190 TRUE, /* pc_relative */
192 complain_overflow_signed, /* complain_on_overflow */
193 bfd_elf_generic_reloc, /* special_function */
194 "R_FR30_9_PCREL", /* name */
195 FALSE, /* partial_inplace */
196 0x0000, /* src_mask */
197 0x00ff, /* dst_mask */
198 FALSE), /* pcrel_offset */
200 /* A PC relative 12 bit relocation, right shifted by 1. */
201 HOWTO (R_FR30_12_PCREL, /* type */
203 1, /* size (0 = byte, 1 = short, 2 = long) */
205 TRUE, /* pc_relative */
207 complain_overflow_signed, /* complain_on_overflow */
208 bfd_elf_generic_reloc, /* special_function */
209 "R_FR30_12_PCREL", /* name */
210 FALSE, /* partial_inplace */
211 0x0000, /* src_mask */
212 0x07ff, /* dst_mask */
213 FALSE), /* pcrel_offset */
214 /* GNU extension to record C++ vtable hierarchy */
215 HOWTO (R_FR30_GNU_VTINHERIT, /* type */
217 2, /* size (0 = byte, 1 = short, 2 = long) */
219 FALSE, /* pc_relative */
221 complain_overflow_dont, /* complain_on_overflow */
222 NULL, /* special_function */
223 "R_FR30_GNU_VTINHERIT", /* name */
224 FALSE, /* partial_inplace */
227 FALSE), /* pcrel_offset */
229 /* GNU extension to record C++ vtable member usage */
230 HOWTO (R_FR30_GNU_VTENTRY, /* type */
232 2, /* size (0 = byte, 1 = short, 2 = long) */
234 FALSE, /* pc_relative */
236 complain_overflow_dont, /* complain_on_overflow */
237 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
238 "R_FR30_GNU_VTENTRY", /* name */
239 FALSE, /* partial_inplace */
242 FALSE), /* pcrel_offset */
245 /* Utility to actually perform an R_FR30_20 reloc. */
247 static bfd_reloc_status_type
248 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
249 input_section, output_bfd, error_message)
251 arelent *reloc_entry;
254 asection *input_section;
256 char **error_message ATTRIBUTE_UNUSED;
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))
267 reloc_entry->address += input_section->output_offset;
271 if (output_bfd != NULL)
272 /* FIXME: See bfd_perform_relocation. Is this right? */
277 + symbol->section->output_section->vma
278 + symbol->section->output_offset
279 + reloc_entry->addend;
281 if (relocation > (((bfd_vma) 1 << 20) - 1))
282 return bfd_reloc_overflow;
284 x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
285 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
286 bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
291 /* Utility to actually perform a R_FR30_48 reloc. */
293 static bfd_reloc_status_type
294 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
295 input_section, output_bfd, error_message)
297 arelent *reloc_entry;
300 asection *input_section;
302 char **error_message ATTRIBUTE_UNUSED;
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))
312 reloc_entry->address += input_section->output_offset;
316 if (output_bfd != NULL)
317 /* FIXME: See bfd_perform_relocation. Is this right? */
322 + symbol->section->output_section->vma
323 + symbol->section->output_offset
324 + reloc_entry->addend;
326 bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
331 /* Map BFD reloc types to FR30 ELF reloc types. */
333 struct fr30_reloc_map
335 bfd_reloc_code_real_type bfd_reloc_val;
336 unsigned int fr30_reloc_val;
339 static const struct fr30_reloc_map fr30_reloc_map [] =
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 },
356 static reloc_howto_type *
357 fr30_reloc_type_lookup (abfd, code)
358 bfd *abfd ATTRIBUTE_UNUSED;
359 bfd_reloc_code_real_type code;
363 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
365 if (fr30_reloc_map [i].bfd_reloc_val == code)
366 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
371 static reloc_howto_type *
372 fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
377 i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
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];
386 /* Set the howto pointer for an FR30 ELF reloc. */
389 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
390 bfd *abfd ATTRIBUTE_UNUSED;
392 Elf_Internal_Rela *dst;
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];
401 /* Perform a single relocation. By default we use the standard BFD
402 routines, but a few relocs, we have to do them ourselves. */
404 static bfd_reloc_status_type
405 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel,
407 reloc_howto_type *howto;
409 asection *input_section;
411 Elf_Internal_Rela *rel;
414 bfd_reloc_status_type r = bfd_reloc_ok;
421 contents += rel->r_offset;
422 relocation += rel->r_addend;
424 if (relocation > ((1 << 20) - 1))
425 return bfd_reloc_overflow;
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);
433 contents += rel->r_offset + 2;
434 relocation += rel->r_addend;
435 bfd_put_32 (input_bfd, relocation, contents);
439 contents += rel->r_offset + 1;
440 srel = (bfd_signed_vma) relocation;
441 srel += rel->r_addend;
442 srel -= rel->r_offset;
443 srel -= 2; /* Branch instructions add 2 to the PC... */
444 srel -= (input_section->output_section->vma +
445 input_section->output_offset);
448 return bfd_reloc_outofrange;
449 if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
450 return bfd_reloc_overflow;
452 bfd_put_8 (input_bfd, srel >> 1, contents);
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;
460 srel -= 2; /* Branch instructions add 2 to the PC... */
461 srel -= (input_section->output_section->vma +
462 input_section->output_offset);
465 return bfd_reloc_outofrange;
466 if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
467 return bfd_reloc_overflow;
469 x = bfd_get_16 (input_bfd, contents);
470 x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
471 bfd_put_16 (input_bfd, x, contents);
475 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
476 contents, rel->r_offset,
477 relocation, rel->r_addend);
483 /* Relocate an FR30 ELF section.
485 The RELOCATE_SECTION function is called by the new ELF backend linker
486 to handle the relocations for a section.
488 The relocs are always passed as Rela structures; if the section
489 actually uses Rel structures, the r_addend field will always be
492 This function is responsible for adjusting the section contents as
493 necessary, and (if using Rela relocs and generating a relocatable
494 output file) adjusting the reloc addend as necessary.
496 This function does not have to worry about setting the reloc
497 address or the reloc symbol index.
499 LOCAL_SYMS is a pointer to the swapped in local symbols.
501 LOCAL_SECTIONS is an array giving the section in the input file
502 corresponding to the st_shndx field of each local symbol.
504 The global hash table entry for the global symbols can be found
505 via elf_sym_hashes (input_bfd).
507 When generating relocatable output, this function must handle
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
514 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
515 contents, relocs, local_syms, local_sections)
517 struct bfd_link_info *info;
519 asection *input_section;
521 Elf_Internal_Rela *relocs;
522 Elf_Internal_Sym *local_syms;
523 asection **local_sections;
525 Elf_Internal_Shdr *symtab_hdr;
526 struct elf_link_hash_entry **sym_hashes;
527 Elf_Internal_Rela *rel;
528 Elf_Internal_Rela *relend;
530 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
531 sym_hashes = elf_sym_hashes (input_bfd);
532 relend = relocs + input_section->reloc_count;
534 for (rel = relocs; rel < relend; rel ++)
536 reloc_howto_type *howto;
537 unsigned long r_symndx;
538 Elf_Internal_Sym *sym;
540 struct elf_link_hash_entry *h;
542 bfd_reloc_status_type r;
546 r_type = ELF32_R_TYPE (rel->r_info);
548 if ( r_type == R_FR30_GNU_VTINHERIT
549 || r_type == R_FR30_GNU_VTENTRY)
552 r_symndx = ELF32_R_SYM (rel->r_info);
554 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
559 if (r_symndx < symtab_hdr->sh_info)
561 sym = local_syms + r_symndx;
562 sec = local_sections [r_symndx];
563 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
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;
571 bfd_boolean unresolved_reloc, warned;
573 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
574 r_symndx, symtab_hdr, sym_hashes,
576 unresolved_reloc, warned);
578 name = h->root.root.string;
581 if (sec != NULL && discarded_section (sec))
582 RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
583 rel, 1, relend, howto, 0, contents);
585 if (info->relocatable)
588 r = fr30_final_link_relocate (howto, input_bfd, input_section,
589 contents, rel, relocation);
591 if (r != bfd_reloc_ok)
593 const char * msg = (const char *) NULL;
597 case bfd_reloc_overflow:
598 r = info->callbacks->reloc_overflow
599 (info, (h ? &h->root : NULL), name, howto->name,
600 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
603 case bfd_reloc_undefined:
604 r = info->callbacks->undefined_symbol
605 (info, name, input_bfd, input_section, rel->r_offset,
609 case bfd_reloc_outofrange:
610 msg = _("internal error: out of range error");
613 case bfd_reloc_notsupported:
614 msg = _("internal error: unsupported relocation error");
617 case bfd_reloc_dangerous:
618 msg = _("internal error: dangerous relocation");
622 msg = _("internal error: unknown error");
627 r = info->callbacks->warning
628 (info, msg, name, input_bfd, input_section, rel->r_offset);
638 /* Return the section that should be marked against GC for a given
642 fr30_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)
649 switch (ELF32_R_TYPE (rel->r_info))
651 case R_FR30_GNU_VTINHERIT:
652 case R_FR30_GNU_VTENTRY:
656 return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
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. */
664 fr30_elf_check_relocs (abfd, info, sec, relocs)
666 struct bfd_link_info *info;
668 const Elf_Internal_Rela *relocs;
670 Elf_Internal_Shdr *symtab_hdr;
671 struct elf_link_hash_entry **sym_hashes;
672 const Elf_Internal_Rela *rel;
673 const Elf_Internal_Rela *rel_end;
675 if (info->relocatable)
678 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
679 sym_hashes = elf_sym_hashes (abfd);
681 rel_end = relocs + sec->reloc_count;
682 for (rel = relocs; rel < rel_end; rel++)
684 struct elf_link_hash_entry *h;
685 unsigned long r_symndx;
687 r_symndx = ELF32_R_SYM (rel->r_info);
688 if (r_symndx < symtab_hdr->sh_info)
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;
698 switch (ELF32_R_TYPE (rel->r_info))
700 /* This relocation describes the C++ object vtable hierarchy.
701 Reconstruct it for later use during GC. */
702 case R_FR30_GNU_VTINHERIT:
703 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
707 /* This relocation describes which C++ vtable entries are actually
708 used. Record for later use during GC. */
709 case R_FR30_GNU_VTENTRY:
710 BFD_ASSERT (h != NULL);
712 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
721 #define ELF_ARCH bfd_arch_fr30
722 #define ELF_MACHINE_CODE EM_FR30
723 #define ELF_MACHINE_ALT1 EM_CYGNUS_FR30
724 #define ELF_MAXPAGESIZE 0x1000
726 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
727 #define TARGET_BIG_NAME "elf32-fr30"
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
733 #define elf_backend_check_relocs fr30_elf_check_relocs
735 #define elf_backend_can_gc_sections 1
736 #define elf_backend_rela_normal 1
738 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
739 #define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup
741 #include "elf32-target.h"