1 /* FR30-specific support for 32-bit ELF.
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
28 /* Forward declarations. */
29 static bfd_reloc_status_type fr30_elf_i20_reloc
30 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
31 static bfd_reloc_status_type fr30_elf_i32_reloc
32 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
33 static reloc_howto_type * fr30_reloc_type_lookup
34 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
35 static void fr30_info_to_howto_rela
36 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
37 static bfd_boolean fr30_elf_relocate_section
38 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
39 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
40 static bfd_reloc_status_type fr30_final_link_relocate
41 PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
42 Elf_Internal_Rela *, bfd_vma));
43 static bfd_boolean fr30_elf_check_relocs
44 PARAMS ((bfd *, struct bfd_link_info *, asection *,
45 const Elf_Internal_Rela *));
47 static reloc_howto_type fr30_elf_howto_table [] =
49 /* This reloc does nothing. */
50 HOWTO (R_FR30_NONE, /* type */
52 2, /* size (0 = byte, 1 = short, 2 = long) */
54 FALSE, /* pc_relative */
56 complain_overflow_bitfield, /* complain_on_overflow */
57 bfd_elf_generic_reloc, /* special_function */
58 "R_FR30_NONE", /* name */
59 FALSE, /* partial_inplace */
62 FALSE), /* pcrel_offset */
64 /* An 8 bit absolute relocation. */
65 HOWTO (R_FR30_8, /* type */
67 1, /* size (0 = byte, 1 = short, 2 = long) */
69 FALSE, /* pc_relative */
71 complain_overflow_bitfield, /* complain_on_overflow */
72 bfd_elf_generic_reloc, /* special_function */
73 "R_FR30_8", /* name */
74 FALSE, /* partial_inplace */
75 0x0000, /* src_mask */
76 0x0ff0, /* dst_mask */
77 FALSE), /* pcrel_offset */
79 /* A 20 bit absolute relocation. */
80 HOWTO (R_FR30_20, /* type */
82 2, /* size (0 = byte, 1 = short, 2 = long) */
84 FALSE, /* pc_relative */
86 complain_overflow_bitfield, /* complain_on_overflow */
87 fr30_elf_i20_reloc, /* special_function */
88 "R_FR30_20", /* name */
89 FALSE, /* partial_inplace */
90 0x00000000, /* src_mask */
91 0x00f0ffff, /* dst_mask */
92 FALSE), /* pcrel_offset */
94 /* A 32 bit absolute relocation. */
95 HOWTO (R_FR30_32, /* type */
97 2, /* size (0 = byte, 1 = short, 2 = long) */
99 FALSE, /* pc_relative */
101 complain_overflow_bitfield, /* complain_on_overflow */
102 bfd_elf_generic_reloc, /* special_function */
103 "R_FR30_32", /* name */
104 FALSE, /* partial_inplace */
105 0x00000000, /* src_mask */
106 0xffffffff, /* dst_mask */
107 FALSE), /* pcrel_offset */
109 /* A 32 bit into 48 bits absolute relocation. */
110 HOWTO (R_FR30_48, /* type */
112 2, /* size (0 = byte, 1 = short, 2 = long) */
114 FALSE, /* pc_relative */
116 complain_overflow_bitfield, /* complain_on_overflow */
117 fr30_elf_i32_reloc, /* special_function */
118 "R_FR30_48", /* name */
119 FALSE, /* partial_inplace */
120 0x00000000, /* src_mask */
121 0xffffffff, /* dst_mask */
122 FALSE), /* pcrel_offset */
124 /* A 6 bit absolute relocation. */
125 HOWTO (R_FR30_6_IN_4, /* type */
127 1, /* size (0 = byte, 1 = short, 2 = long) */
129 FALSE, /* pc_relative */
131 complain_overflow_unsigned, /* complain_on_overflow */
132 bfd_elf_generic_reloc, /* special_function */
133 "R_FR30_6_IN_4", /* name */
134 FALSE, /* partial_inplace */
135 0x0000, /* src_mask */
136 0x00f0, /* dst_mask */
137 FALSE), /* pcrel_offset */
139 /* An 8 bit absolute relocation. */
140 HOWTO (R_FR30_8_IN_8, /* type */
142 1, /* size (0 = byte, 1 = short, 2 = long) */
144 FALSE, /* pc_relative */
146 complain_overflow_signed, /* complain_on_overflow */
147 bfd_elf_generic_reloc,/* special_function */
148 "R_FR30_8_IN_8", /* name */
149 FALSE, /* partial_inplace */
150 0x0000, /* src_mask */
151 0x0ff0, /* dst_mask */
152 FALSE), /* pcrel_offset */
154 /* A 9 bit absolute relocation. */
155 HOWTO (R_FR30_9_IN_8, /* type */
157 1, /* size (0 = byte, 1 = short, 2 = long) */
159 FALSE, /* pc_relative */
161 complain_overflow_signed, /* complain_on_overflow */
162 bfd_elf_generic_reloc,/* special_function */
163 "R_FR30_9_IN_8", /* name */
164 FALSE, /* partial_inplace */
165 0x0000, /* src_mask */
166 0x0ff0, /* dst_mask */
167 FALSE), /* pcrel_offset */
169 /* A 10 bit absolute relocation. */
170 HOWTO (R_FR30_10_IN_8, /* type */
172 1, /* size (0 = byte, 1 = short, 2 = long) */
174 FALSE, /* pc_relative */
176 complain_overflow_signed, /* complain_on_overflow */
177 bfd_elf_generic_reloc,/* special_function */
178 "R_FR30_10_IN_8", /* name */
179 FALSE, /* partial_inplace */
180 0x0000, /* src_mask */
181 0x0ff0, /* dst_mask */
182 FALSE), /* pcrel_offset */
184 /* A PC relative 9 bit relocation, right shifted by 1. */
185 HOWTO (R_FR30_9_PCREL, /* type */
187 1, /* size (0 = byte, 1 = short, 2 = long) */
189 TRUE, /* pc_relative */
191 complain_overflow_signed, /* complain_on_overflow */
192 bfd_elf_generic_reloc, /* special_function */
193 "R_FR30_9_PCREL", /* name */
194 FALSE, /* partial_inplace */
195 0x0000, /* src_mask */
196 0x00ff, /* dst_mask */
197 FALSE), /* pcrel_offset */
199 /* A PC relative 12 bit relocation, right shifted by 1. */
200 HOWTO (R_FR30_12_PCREL, /* type */
202 1, /* size (0 = byte, 1 = short, 2 = long) */
204 TRUE, /* pc_relative */
206 complain_overflow_signed, /* complain_on_overflow */
207 bfd_elf_generic_reloc, /* special_function */
208 "R_FR30_12_PCREL", /* name */
209 FALSE, /* partial_inplace */
210 0x0000, /* src_mask */
211 0x07ff, /* dst_mask */
212 FALSE), /* pcrel_offset */
213 /* GNU extension to record C++ vtable hierarchy */
214 HOWTO (R_FR30_GNU_VTINHERIT, /* type */
216 2, /* size (0 = byte, 1 = short, 2 = long) */
218 FALSE, /* pc_relative */
220 complain_overflow_dont, /* complain_on_overflow */
221 NULL, /* special_function */
222 "R_FR30_GNU_VTINHERIT", /* name */
223 FALSE, /* partial_inplace */
226 FALSE), /* pcrel_offset */
228 /* GNU extension to record C++ vtable member usage */
229 HOWTO (R_FR30_GNU_VTENTRY, /* type */
231 2, /* size (0 = byte, 1 = short, 2 = long) */
233 FALSE, /* pc_relative */
235 complain_overflow_dont, /* complain_on_overflow */
236 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
237 "R_FR30_GNU_VTENTRY", /* name */
238 FALSE, /* partial_inplace */
241 FALSE), /* pcrel_offset */
244 /* Utility to actually perform an R_FR30_20 reloc. */
246 static bfd_reloc_status_type
247 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
248 input_section, output_bfd, error_message)
250 arelent *reloc_entry;
253 asection *input_section;
255 char **error_message ATTRIBUTE_UNUSED;
260 /* This part is from bfd_elf_generic_reloc. */
261 if (output_bfd != (bfd *) NULL
262 && (symbol->flags & BSF_SECTION_SYM) == 0
263 && (! reloc_entry->howto->partial_inplace
264 || reloc_entry->addend == 0))
266 reloc_entry->address += input_section->output_offset;
270 if (output_bfd != NULL)
271 /* FIXME: See bfd_perform_relocation. Is this right? */
276 + symbol->section->output_section->vma
277 + symbol->section->output_offset
278 + reloc_entry->addend;
280 if (relocation > (((bfd_vma) 1 << 20) - 1))
281 return bfd_reloc_overflow;
283 x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
284 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
285 bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
290 /* Utility to actually perform a R_FR30_48 reloc. */
292 static bfd_reloc_status_type
293 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
294 input_section, output_bfd, error_message)
296 arelent *reloc_entry;
299 asection *input_section;
301 char **error_message ATTRIBUTE_UNUSED;
305 /* This part is from bfd_elf_generic_reloc. */
306 if (output_bfd != (bfd *) NULL
307 && (symbol->flags & BSF_SECTION_SYM) == 0
308 && (! reloc_entry->howto->partial_inplace
309 || reloc_entry->addend == 0))
311 reloc_entry->address += input_section->output_offset;
315 if (output_bfd != NULL)
316 /* FIXME: See bfd_perform_relocation. Is this right? */
321 + symbol->section->output_section->vma
322 + symbol->section->output_offset
323 + reloc_entry->addend;
325 bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
330 /* Map BFD reloc types to FR30 ELF reloc types. */
332 struct fr30_reloc_map
334 bfd_reloc_code_real_type bfd_reloc_val;
335 unsigned int fr30_reloc_val;
338 static const struct fr30_reloc_map fr30_reloc_map [] =
340 { BFD_RELOC_NONE, R_FR30_NONE },
341 { BFD_RELOC_8, R_FR30_8 },
342 { BFD_RELOC_FR30_20, R_FR30_20 },
343 { BFD_RELOC_32, R_FR30_32 },
344 { BFD_RELOC_FR30_48, R_FR30_48 },
345 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
346 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
347 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
348 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
349 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
350 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
351 { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
352 { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY },
355 static reloc_howto_type *
356 fr30_reloc_type_lookup (abfd, code)
357 bfd *abfd ATTRIBUTE_UNUSED;
358 bfd_reloc_code_real_type code;
362 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
364 if (fr30_reloc_map [i].bfd_reloc_val == code)
365 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
370 static reloc_howto_type *
371 fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
376 i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
378 if (fr30_elf_howto_table[i].name != NULL
379 && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
380 return &fr30_elf_howto_table[i];
385 /* Set the howto pointer for an FR30 ELF reloc. */
388 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
389 bfd *abfd ATTRIBUTE_UNUSED;
391 Elf_Internal_Rela *dst;
395 r_type = ELF32_R_TYPE (dst->r_info);
396 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
397 cache_ptr->howto = & fr30_elf_howto_table [r_type];
400 /* Perform a single relocation. By default we use the standard BFD
401 routines, but a few relocs, we have to do them ourselves. */
403 static bfd_reloc_status_type
404 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel,
406 reloc_howto_type *howto;
408 asection *input_section;
410 Elf_Internal_Rela *rel;
413 bfd_reloc_status_type r = bfd_reloc_ok;
420 contents += rel->r_offset;
421 relocation += rel->r_addend;
423 if (relocation > ((1 << 20) - 1))
424 return bfd_reloc_overflow;
426 x = bfd_get_32 (input_bfd, contents);
427 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
428 bfd_put_32 (input_bfd, x, contents);
432 contents += rel->r_offset + 2;
433 relocation += rel->r_addend;
434 bfd_put_32 (input_bfd, relocation, contents);
438 contents += rel->r_offset + 1;
439 srel = (bfd_signed_vma) relocation;
440 srel += rel->r_addend;
441 srel -= rel->r_offset;
442 srel -= 2; /* Branch instructions add 2 to the PC... */
443 srel -= (input_section->output_section->vma +
444 input_section->output_offset);
447 return bfd_reloc_outofrange;
448 if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
449 return bfd_reloc_overflow;
451 bfd_put_8 (input_bfd, srel >> 1, contents);
454 case R_FR30_12_PCREL:
455 contents += rel->r_offset;
456 srel = (bfd_signed_vma) relocation;
457 srel += rel->r_addend;
458 srel -= rel->r_offset;
459 srel -= 2; /* Branch instructions add 2 to the PC... */
460 srel -= (input_section->output_section->vma +
461 input_section->output_offset);
464 return bfd_reloc_outofrange;
465 if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
466 return bfd_reloc_overflow;
468 x = bfd_get_16 (input_bfd, contents);
469 x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
470 bfd_put_16 (input_bfd, x, contents);
474 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
475 contents, rel->r_offset,
476 relocation, rel->r_addend);
482 /* Relocate an FR30 ELF section.
484 The RELOCATE_SECTION function is called by the new ELF backend linker
485 to handle the relocations for a section.
487 The relocs are always passed as Rela structures; if the section
488 actually uses Rel structures, the r_addend field will always be
491 This function is responsible for adjusting the section contents as
492 necessary, and (if using Rela relocs and generating a relocatable
493 output file) adjusting the reloc addend as necessary.
495 This function does not have to worry about setting the reloc
496 address or the reloc symbol index.
498 LOCAL_SYMS is a pointer to the swapped in local symbols.
500 LOCAL_SECTIONS is an array giving the section in the input file
501 corresponding to the st_shndx field of each local symbol.
503 The global hash table entry for the global symbols can be found
504 via elf_sym_hashes (input_bfd).
506 When generating relocatable output, this function must handle
507 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
508 going to be the section symbol corresponding to the output
509 section, which means that the addend must be adjusted
513 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
514 contents, relocs, local_syms, local_sections)
516 struct bfd_link_info *info;
518 asection *input_section;
520 Elf_Internal_Rela *relocs;
521 Elf_Internal_Sym *local_syms;
522 asection **local_sections;
524 Elf_Internal_Shdr *symtab_hdr;
525 struct elf_link_hash_entry **sym_hashes;
526 Elf_Internal_Rela *rel;
527 Elf_Internal_Rela *relend;
529 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
530 sym_hashes = elf_sym_hashes (input_bfd);
531 relend = relocs + input_section->reloc_count;
533 for (rel = relocs; rel < relend; rel ++)
535 reloc_howto_type *howto;
536 unsigned long r_symndx;
537 Elf_Internal_Sym *sym;
539 struct elf_link_hash_entry *h;
541 bfd_reloc_status_type r;
545 r_type = ELF32_R_TYPE (rel->r_info);
547 if ( r_type == R_FR30_GNU_VTINHERIT
548 || r_type == R_FR30_GNU_VTENTRY)
551 r_symndx = ELF32_R_SYM (rel->r_info);
553 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
558 if (r_symndx < symtab_hdr->sh_info)
560 sym = local_syms + r_symndx;
561 sec = local_sections [r_symndx];
562 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
564 name = bfd_elf_string_from_elf_section
565 (input_bfd, symtab_hdr->sh_link, sym->st_name);
566 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
570 bfd_boolean unresolved_reloc, warned;
572 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
573 r_symndx, symtab_hdr, sym_hashes,
575 unresolved_reloc, warned);
577 name = h->root.root.string;
580 if (sec != NULL && elf_discarded_section (sec))
582 /* For relocs against symbols from removed linkonce sections,
583 or sections discarded by a linker script, we just want the
584 section contents zeroed. Avoid any special processing. */
585 _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
591 if (info->relocatable)
594 r = fr30_final_link_relocate (howto, input_bfd, input_section,
595 contents, rel, relocation);
597 if (r != bfd_reloc_ok)
599 const char * msg = (const char *) NULL;
603 case bfd_reloc_overflow:
604 r = info->callbacks->reloc_overflow
605 (info, (h ? &h->root : NULL), name, howto->name,
606 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
609 case bfd_reloc_undefined:
610 r = info->callbacks->undefined_symbol
611 (info, name, input_bfd, input_section, rel->r_offset,
615 case bfd_reloc_outofrange:
616 msg = _("internal error: out of range error");
619 case bfd_reloc_notsupported:
620 msg = _("internal error: unsupported relocation error");
623 case bfd_reloc_dangerous:
624 msg = _("internal error: dangerous relocation");
628 msg = _("internal error: unknown error");
633 r = info->callbacks->warning
634 (info, msg, name, input_bfd, input_section, rel->r_offset);
644 /* Return the section that should be marked against GC for a given
648 fr30_elf_gc_mark_hook (asection *sec,
649 struct bfd_link_info *info,
650 Elf_Internal_Rela *rel,
651 struct elf_link_hash_entry *h,
652 Elf_Internal_Sym *sym)
655 switch (ELF32_R_TYPE (rel->r_info))
657 case R_FR30_GNU_VTINHERIT:
658 case R_FR30_GNU_VTENTRY:
662 return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
665 /* Look through the relocs for a section during the first phase.
666 Since we don't do .gots or .plts, we just need to consider the
667 virtual table relocs for gc. */
670 fr30_elf_check_relocs (abfd, info, sec, relocs)
672 struct bfd_link_info *info;
674 const Elf_Internal_Rela *relocs;
676 Elf_Internal_Shdr *symtab_hdr;
677 struct elf_link_hash_entry **sym_hashes;
678 const Elf_Internal_Rela *rel;
679 const Elf_Internal_Rela *rel_end;
681 if (info->relocatable)
684 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
685 sym_hashes = elf_sym_hashes (abfd);
687 rel_end = relocs + sec->reloc_count;
688 for (rel = relocs; rel < rel_end; rel++)
690 struct elf_link_hash_entry *h;
691 unsigned long r_symndx;
693 r_symndx = ELF32_R_SYM (rel->r_info);
694 if (r_symndx < symtab_hdr->sh_info)
698 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
699 while (h->root.type == bfd_link_hash_indirect
700 || h->root.type == bfd_link_hash_warning)
701 h = (struct elf_link_hash_entry *) h->root.u.i.link;
704 switch (ELF32_R_TYPE (rel->r_info))
706 /* This relocation describes the C++ object vtable hierarchy.
707 Reconstruct it for later use during GC. */
708 case R_FR30_GNU_VTINHERIT:
709 if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
713 /* This relocation describes which C++ vtable entries are actually
714 used. Record for later use during GC. */
715 case R_FR30_GNU_VTENTRY:
716 BFD_ASSERT (h != NULL);
718 && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
727 #define ELF_ARCH bfd_arch_fr30
728 #define ELF_MACHINE_CODE EM_FR30
729 #define ELF_MACHINE_ALT1 EM_CYGNUS_FR30
730 #define ELF_MAXPAGESIZE 0x1000
732 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
733 #define TARGET_BIG_NAME "elf32-fr30"
735 #define elf_info_to_howto_rel NULL
736 #define elf_info_to_howto fr30_info_to_howto_rela
737 #define elf_backend_relocate_section fr30_elf_relocate_section
738 #define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook
739 #define elf_backend_check_relocs fr30_elf_check_relocs
741 #define elf_backend_can_gc_sections 1
742 #define elf_backend_rela_normal 1
744 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
745 #define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup
747 #include "elf32-target.h"