1 /* FR30-specific support for 32-bit ELF.
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 /* Forward declarations. */
28 static bfd_reloc_status_type fr30_elf_i20_reloc
29 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
30 static bfd_reloc_status_type fr30_elf_i32_reloc
31 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
32 static reloc_howto_type * fr30_reloc_type_lookup
33 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
34 static void fr30_info_to_howto_rela
35 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
36 static bfd_boolean fr30_elf_relocate_section
37 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
38 Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
39 static bfd_reloc_status_type fr30_final_link_relocate
40 PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
41 Elf_Internal_Rela *, bfd_vma));
42 static bfd_boolean fr30_elf_gc_sweep_hook
43 PARAMS ((bfd *, struct bfd_link_info *, asection *,
44 const Elf_Internal_Rela *));
45 static asection * fr30_elf_gc_mark_hook
46 PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
47 struct elf_link_hash_entry *, Elf_Internal_Sym *));
48 static bfd_boolean fr30_elf_check_relocs
49 PARAMS ((bfd *, struct bfd_link_info *, asection *,
50 const Elf_Internal_Rela *));
52 static reloc_howto_type fr30_elf_howto_table [] =
54 /* This reloc does nothing. */
55 HOWTO (R_FR30_NONE, /* type */
57 2, /* size (0 = byte, 1 = short, 2 = long) */
59 FALSE, /* pc_relative */
61 complain_overflow_bitfield, /* complain_on_overflow */
62 bfd_elf_generic_reloc, /* special_function */
63 "R_FR30_NONE", /* name */
64 FALSE, /* partial_inplace */
67 FALSE), /* pcrel_offset */
69 /* An 8 bit absolute relocation. */
70 HOWTO (R_FR30_8, /* type */
72 1, /* size (0 = byte, 1 = short, 2 = long) */
74 FALSE, /* pc_relative */
76 complain_overflow_bitfield, /* complain_on_overflow */
77 bfd_elf_generic_reloc, /* special_function */
78 "R_FR30_8", /* name */
79 TRUE, /* partial_inplace */
80 0x0000, /* src_mask */
81 0x0ff0, /* dst_mask */
82 FALSE), /* pcrel_offset */
84 /* A 20 bit absolute relocation. */
85 HOWTO (R_FR30_20, /* type */
87 2, /* size (0 = byte, 1 = short, 2 = long) */
89 FALSE, /* pc_relative */
91 complain_overflow_bitfield, /* complain_on_overflow */
92 fr30_elf_i20_reloc, /* special_function */
93 "R_FR30_20", /* name */
94 TRUE, /* partial_inplace */
95 0x00000000, /* src_mask */
96 0x00f0ffff, /* dst_mask */
97 FALSE), /* pcrel_offset */
99 /* A 32 bit absolute relocation. */
100 HOWTO (R_FR30_32, /* type */
102 2, /* size (0 = byte, 1 = short, 2 = long) */
104 FALSE, /* pc_relative */
106 complain_overflow_bitfield, /* complain_on_overflow */
107 bfd_elf_generic_reloc, /* special_function */
108 "R_FR30_32", /* name */
109 TRUE, /* partial_inplace */
110 0x00000000, /* src_mask */
111 0xffffffff, /* dst_mask */
112 FALSE), /* pcrel_offset */
114 /* A 32 bit into 48 bits absolute relocation. */
115 HOWTO (R_FR30_48, /* type */
117 2, /* size (0 = byte, 1 = short, 2 = long) */
119 FALSE, /* pc_relative */
121 complain_overflow_bitfield, /* complain_on_overflow */
122 fr30_elf_i32_reloc, /* special_function */
123 "R_FR30_48", /* name */
124 TRUE, /* partial_inplace */
125 0x00000000, /* src_mask */
126 0xffffffff, /* dst_mask */
127 FALSE), /* pcrel_offset */
129 /* A 6 bit absolute relocation. */
130 HOWTO (R_FR30_6_IN_4, /* type */
132 1, /* size (0 = byte, 1 = short, 2 = long) */
134 FALSE, /* pc_relative */
136 complain_overflow_unsigned, /* complain_on_overflow */
137 bfd_elf_generic_reloc, /* special_function */
138 "R_FR30_6_IN_4", /* name */
139 TRUE, /* partial_inplace */
140 0x0000, /* src_mask */
141 0x00f0, /* dst_mask */
142 FALSE), /* pcrel_offset */
144 /* An 8 bit absolute relocation. */
145 HOWTO (R_FR30_8_IN_8, /* type */
147 1, /* size (0 = byte, 1 = short, 2 = long) */
149 FALSE, /* pc_relative */
151 complain_overflow_signed, /* complain_on_overflow */
152 bfd_elf_generic_reloc,/* special_function */
153 "R_FR30_8_IN_8", /* name */
154 TRUE, /* partial_inplace */
155 0x0000, /* src_mask */
156 0x0ff0, /* dst_mask */
157 FALSE), /* pcrel_offset */
159 /* A 9 bit absolute relocation. */
160 HOWTO (R_FR30_9_IN_8, /* type */
162 1, /* size (0 = byte, 1 = short, 2 = long) */
164 FALSE, /* pc_relative */
166 complain_overflow_signed, /* complain_on_overflow */
167 bfd_elf_generic_reloc,/* special_function */
168 "R_FR30_9_IN_8", /* name */
169 TRUE, /* partial_inplace */
170 0x0000, /* src_mask */
171 0x0ff0, /* dst_mask */
172 FALSE), /* pcrel_offset */
174 /* A 10 bit absolute relocation. */
175 HOWTO (R_FR30_10_IN_8, /* type */
177 1, /* size (0 = byte, 1 = short, 2 = long) */
179 FALSE, /* pc_relative */
181 complain_overflow_signed, /* complain_on_overflow */
182 bfd_elf_generic_reloc,/* special_function */
183 "R_FR30_10_IN_8", /* name */
184 TRUE, /* partial_inplace */
185 0x0000, /* src_mask */
186 0x0ff0, /* dst_mask */
187 FALSE), /* pcrel_offset */
189 /* A PC relative 9 bit relocation, right shifted by 1. */
190 HOWTO (R_FR30_9_PCREL, /* type */
192 1, /* size (0 = byte, 1 = short, 2 = long) */
194 TRUE, /* pc_relative */
196 complain_overflow_signed, /* complain_on_overflow */
197 bfd_elf_generic_reloc, /* special_function */
198 "R_FR30_9_PCREL", /* name */
199 FALSE, /* partial_inplace */
200 0x0000, /* src_mask */
201 0x00ff, /* dst_mask */
202 FALSE), /* pcrel_offset */
204 /* A PC relative 12 bit relocation, right shifted by 1. */
205 HOWTO (R_FR30_12_PCREL, /* type */
207 1, /* size (0 = byte, 1 = short, 2 = long) */
209 TRUE, /* pc_relative */
211 complain_overflow_signed, /* complain_on_overflow */
212 bfd_elf_generic_reloc, /* special_function */
213 "R_FR30_12_PCREL", /* name */
214 FALSE, /* partial_inplace */
215 0x0000, /* src_mask */
216 0x07ff, /* dst_mask */
217 FALSE), /* pcrel_offset */
218 /* GNU extension to record C++ vtable hierarchy */
219 HOWTO (R_FR30_GNU_VTINHERIT, /* type */
221 2, /* size (0 = byte, 1 = short, 2 = long) */
223 FALSE, /* pc_relative */
225 complain_overflow_dont, /* complain_on_overflow */
226 NULL, /* special_function */
227 "R_FR30_GNU_VTINHERIT", /* name */
228 FALSE, /* partial_inplace */
231 FALSE), /* pcrel_offset */
233 /* GNU extension to record C++ vtable member usage */
234 HOWTO (R_FR30_GNU_VTENTRY, /* type */
236 2, /* size (0 = byte, 1 = short, 2 = long) */
238 FALSE, /* pc_relative */
240 complain_overflow_dont, /* complain_on_overflow */
241 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
242 "R_FR30_GNU_VTENTRY", /* name */
243 FALSE, /* partial_inplace */
246 FALSE), /* pcrel_offset */
249 /* Utility to actually perform an R_FR30_20 reloc. */
251 static bfd_reloc_status_type
252 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
253 input_section, output_bfd, error_message)
255 arelent *reloc_entry;
258 asection *input_section;
260 char **error_message ATTRIBUTE_UNUSED;
265 /* This part is from bfd_elf_generic_reloc. */
266 if (output_bfd != (bfd *) NULL
267 && (symbol->flags & BSF_SECTION_SYM) == 0
268 && (! reloc_entry->howto->partial_inplace
269 || reloc_entry->addend == 0))
271 reloc_entry->address += input_section->output_offset;
275 if (output_bfd != NULL)
276 /* FIXME: See bfd_perform_relocation. Is this right? */
281 + symbol->section->output_section->vma
282 + symbol->section->output_offset
283 + reloc_entry->addend;
285 if (relocation > (((bfd_vma) 1 << 20) - 1))
286 return bfd_reloc_overflow;
288 x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
289 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
290 bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
295 /* Utility to actually perform a R_FR30_48 reloc. */
297 static bfd_reloc_status_type
298 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
299 input_section, output_bfd, error_message)
301 arelent *reloc_entry;
304 asection *input_section;
306 char **error_message ATTRIBUTE_UNUSED;
310 /* This part is from bfd_elf_generic_reloc. */
311 if (output_bfd != (bfd *) NULL
312 && (symbol->flags & BSF_SECTION_SYM) == 0
313 && (! reloc_entry->howto->partial_inplace
314 || reloc_entry->addend == 0))
316 reloc_entry->address += input_section->output_offset;
320 if (output_bfd != NULL)
321 /* FIXME: See bfd_perform_relocation. Is this right? */
326 + symbol->section->output_section->vma
327 + symbol->section->output_offset
328 + reloc_entry->addend;
330 bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
335 /* Map BFD reloc types to FR30 ELF reloc types. */
337 struct fr30_reloc_map
339 bfd_reloc_code_real_type bfd_reloc_val;
340 unsigned int fr30_reloc_val;
343 static const struct fr30_reloc_map fr30_reloc_map [] =
345 { BFD_RELOC_NONE, R_FR30_NONE },
346 { BFD_RELOC_8, R_FR30_8 },
347 { BFD_RELOC_FR30_20, R_FR30_20 },
348 { BFD_RELOC_32, R_FR30_32 },
349 { BFD_RELOC_FR30_48, R_FR30_48 },
350 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
351 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
352 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
353 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
354 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
355 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
356 { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
357 { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY },
360 static reloc_howto_type *
361 fr30_reloc_type_lookup (abfd, code)
362 bfd *abfd ATTRIBUTE_UNUSED;
363 bfd_reloc_code_real_type code;
367 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
369 if (fr30_reloc_map [i].bfd_reloc_val == code)
370 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
375 /* Set the howto pointer for an FR30 ELF reloc. */
378 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
379 bfd *abfd ATTRIBUTE_UNUSED;
381 Elf_Internal_Rela *dst;
385 r_type = ELF32_R_TYPE (dst->r_info);
386 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
387 cache_ptr->howto = & fr30_elf_howto_table [r_type];
390 /* Perform a single relocation. By default we use the standard BFD
391 routines, but a few relocs, we have to do them ourselves. */
393 static bfd_reloc_status_type
394 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel,
396 reloc_howto_type *howto;
398 asection *input_section;
400 Elf_Internal_Rela *rel;
403 bfd_reloc_status_type r = bfd_reloc_ok;
410 contents += rel->r_offset;
411 relocation += rel->r_addend;
413 if (relocation > ((1 << 20) - 1))
414 return bfd_reloc_overflow;
416 x = bfd_get_32 (input_bfd, contents);
417 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
418 bfd_put_32 (input_bfd, x, contents);
422 contents += rel->r_offset + 2;
423 relocation += rel->r_addend;
424 bfd_put_32 (input_bfd, relocation, contents);
428 contents += rel->r_offset + 1;
429 srel = (bfd_signed_vma) relocation;
430 srel += rel->r_addend;
431 srel -= rel->r_offset;
432 srel -= 2; /* Branch instructions add 2 to the PC... */
433 srel -= (input_section->output_section->vma +
434 input_section->output_offset);
437 return bfd_reloc_outofrange;
438 if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
439 return bfd_reloc_overflow;
441 bfd_put_8 (input_bfd, srel >> 1, contents);
444 case R_FR30_12_PCREL:
445 contents += rel->r_offset;
446 srel = (bfd_signed_vma) relocation;
447 srel += rel->r_addend;
448 srel -= rel->r_offset;
449 srel -= 2; /* Branch instructions add 2 to the PC... */
450 srel -= (input_section->output_section->vma +
451 input_section->output_offset);
454 return bfd_reloc_outofrange;
455 if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
456 return bfd_reloc_overflow;
458 x = bfd_get_16 (input_bfd, contents);
459 x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
460 bfd_put_16 (input_bfd, x, contents);
464 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
465 contents, rel->r_offset,
466 relocation, rel->r_addend);
472 /* Relocate an FR30 ELF section.
474 The RELOCATE_SECTION function is called by the new ELF backend linker
475 to handle the relocations for a section.
477 The relocs are always passed as Rela structures; if the section
478 actually uses Rel structures, the r_addend field will always be
481 This function is responsible for adjusting the section contents as
482 necessary, and (if using Rela relocs and generating a relocatable
483 output file) adjusting the reloc addend as necessary.
485 This function does not have to worry about setting the reloc
486 address or the reloc symbol index.
488 LOCAL_SYMS is a pointer to the swapped in local symbols.
490 LOCAL_SECTIONS is an array giving the section in the input file
491 corresponding to the st_shndx field of each local symbol.
493 The global hash table entry for the global symbols can be found
494 via elf_sym_hashes (input_bfd).
496 When generating relocatable output, this function must handle
497 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
498 going to be the section symbol corresponding to the output
499 section, which means that the addend must be adjusted
503 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
504 contents, relocs, local_syms, local_sections)
506 struct bfd_link_info *info;
508 asection *input_section;
510 Elf_Internal_Rela *relocs;
511 Elf_Internal_Sym *local_syms;
512 asection **local_sections;
514 Elf_Internal_Shdr *symtab_hdr;
515 struct elf_link_hash_entry **sym_hashes;
516 Elf_Internal_Rela *rel;
517 Elf_Internal_Rela *relend;
519 if (info->relocatable)
522 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
523 sym_hashes = elf_sym_hashes (input_bfd);
524 relend = relocs + input_section->reloc_count;
526 for (rel = relocs; rel < relend; rel ++)
528 reloc_howto_type *howto;
529 unsigned long r_symndx;
530 Elf_Internal_Sym *sym;
532 struct elf_link_hash_entry *h;
534 bfd_reloc_status_type r;
535 const char *name = NULL;
538 r_type = ELF32_R_TYPE (rel->r_info);
540 if ( r_type == R_FR30_GNU_VTINHERIT
541 || r_type == R_FR30_GNU_VTENTRY)
544 r_symndx = ELF32_R_SYM (rel->r_info);
546 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
551 if (r_symndx < symtab_hdr->sh_info)
553 sym = local_syms + r_symndx;
554 sec = local_sections [r_symndx];
555 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
557 name = bfd_elf_string_from_elf_section
558 (input_bfd, symtab_hdr->sh_link, sym->st_name);
559 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
561 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
562 sec->name, name, sym->st_name,
563 sec->output_section->vma, sec->output_offset,
564 sym->st_value, rel->r_addend);
569 bfd_boolean unresolved_reloc, warned;
571 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
572 r_symndx, symtab_hdr, sym_hashes,
574 unresolved_reloc, warned);
577 r = fr30_final_link_relocate (howto, input_bfd, input_section,
578 contents, rel, relocation);
580 if (r != bfd_reloc_ok)
582 const char * msg = (const char *) NULL;
586 case bfd_reloc_overflow:
587 r = info->callbacks->reloc_overflow
588 (info, name, howto->name, (bfd_vma) 0,
589 input_bfd, input_section, rel->r_offset);
592 case bfd_reloc_undefined:
593 r = info->callbacks->undefined_symbol
594 (info, name, input_bfd, input_section, rel->r_offset,
598 case bfd_reloc_outofrange:
599 msg = _("internal error: out of range error");
602 case bfd_reloc_notsupported:
603 msg = _("internal error: unsupported relocation error");
606 case bfd_reloc_dangerous:
607 msg = _("internal error: dangerous relocation");
611 msg = _("internal error: unknown error");
616 r = info->callbacks->warning
617 (info, msg, name, input_bfd, input_section, rel->r_offset);
627 /* Return the section that should be marked against GC for a given
631 fr30_elf_gc_mark_hook (sec, info, rel, h, sym)
633 struct bfd_link_info *info ATTRIBUTE_UNUSED;
634 Elf_Internal_Rela *rel;
635 struct elf_link_hash_entry *h;
636 Elf_Internal_Sym * sym;
640 switch (ELF32_R_TYPE (rel->r_info))
642 case R_FR30_GNU_VTINHERIT:
643 case R_FR30_GNU_VTENTRY:
647 switch (h->root.type)
649 case bfd_link_hash_defined:
650 case bfd_link_hash_defweak:
651 return h->root.u.def.section;
653 case bfd_link_hash_common:
654 return h->root.u.c.p->section;
662 return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
667 /* Update the got entry reference counts for the section being removed. */
670 fr30_elf_gc_sweep_hook (abfd, info, sec, relocs)
671 bfd *abfd ATTRIBUTE_UNUSED;
672 struct bfd_link_info *info ATTRIBUTE_UNUSED;
673 asection *sec ATTRIBUTE_UNUSED;
674 const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
679 /* Look through the relocs for a section during the first phase.
680 Since we don't do .gots or .plts, we just need to consider the
681 virtual table relocs for gc. */
684 fr30_elf_check_relocs (abfd, info, sec, relocs)
686 struct bfd_link_info *info;
688 const Elf_Internal_Rela *relocs;
690 Elf_Internal_Shdr *symtab_hdr;
691 struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
692 const Elf_Internal_Rela *rel;
693 const Elf_Internal_Rela *rel_end;
695 if (info->relocatable)
698 symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
699 sym_hashes = elf_sym_hashes (abfd);
700 sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
701 if (!elf_bad_symtab (abfd))
702 sym_hashes_end -= symtab_hdr->sh_info;
704 rel_end = relocs + sec->reloc_count;
705 for (rel = relocs; rel < rel_end; rel++)
707 struct elf_link_hash_entry *h;
708 unsigned long r_symndx;
710 r_symndx = ELF32_R_SYM (rel->r_info);
711 if (r_symndx < symtab_hdr->sh_info)
714 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
716 switch (ELF32_R_TYPE (rel->r_info))
718 /* This relocation describes the C++ object vtable hierarchy.
719 Reconstruct it for later use during GC. */
720 case R_FR30_GNU_VTINHERIT:
721 if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
725 /* This relocation describes which C++ vtable entries are actually
726 used. Record for later use during GC. */
727 case R_FR30_GNU_VTENTRY:
728 if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
737 #define ELF_ARCH bfd_arch_fr30
738 #define ELF_MACHINE_CODE EM_FR30
739 #define ELF_MACHINE_ALT1 EM_CYGNUS_FR30
740 #define ELF_MAXPAGESIZE 0x1000
742 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
743 #define TARGET_BIG_NAME "elf32-fr30"
745 #define elf_info_to_howto_rel NULL
746 #define elf_info_to_howto fr30_info_to_howto_rela
747 #define elf_backend_relocate_section fr30_elf_relocate_section
748 #define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook
749 #define elf_backend_gc_sweep_hook fr30_elf_gc_sweep_hook
750 #define elf_backend_check_relocs fr30_elf_check_relocs
752 #define elf_backend_can_gc_sections 1
753 #define elf_backend_rela_normal 1
755 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
757 #include "elf32-target.h"