1 /* FR30-specific support for 32-bit ELF.
2 Copyright (C) 1998 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 /* Forward declarations. */
27 static bfd_reloc_status_type fr30_elf_i20_reloc
28 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
29 static bfd_reloc_status_type fr30_elf_i32_reloc
30 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
31 static reloc_howto_type * fr30_reloc_type_lookup
32 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
33 static void fr30_info_to_howto_rela
34 PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
35 static boolean fr30_elf_relocate_section
36 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
37 static bfd_reloc_status_type fr30_final_link_relocate
38 PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma));
40 static reloc_howto_type fr30_elf_howto_table [] =
42 /* This reloc does nothing. */
43 HOWTO (R_FR30_NONE, /* type */
45 2, /* size (0 = byte, 1 = short, 2 = long) */
47 false, /* pc_relative */
49 complain_overflow_bitfield, /* complain_on_overflow */
50 bfd_elf_generic_reloc, /* special_function */
51 "R_FR30_NONE", /* name */
52 false, /* partial_inplace */
55 false), /* pcrel_offset */
57 /* An 8 bit absolute relocation. */
58 HOWTO (R_FR30_8, /* type */
60 1, /* size (0 = byte, 1 = short, 2 = long) */
62 false, /* pc_relative */
64 complain_overflow_bitfield, /* complain_on_overflow */
65 bfd_elf_generic_reloc, /* special_function */
66 "R_FR30_8", /* name */
67 true, /* partial_inplace */
68 0x0000, /* src_mask */
69 0x0ff0, /* dst_mask */
70 false), /* pcrel_offset */
72 /* A 20 bit absolute relocation. */
73 HOWTO (R_FR30_20, /* type */
75 2, /* size (0 = byte, 1 = short, 2 = long) */
77 false, /* pc_relative */
79 complain_overflow_bitfield, /* complain_on_overflow */
80 fr30_elf_i20_reloc, /* special_function */
81 "R_FR30_20", /* name */
82 true, /* partial_inplace */
83 0x00000000, /* src_mask */
84 0x00f0ffff, /* dst_mask */
85 false), /* pcrel_offset */
87 /* A 32 bit absolute relocation. */
88 HOWTO (R_FR30_32, /* type */
90 2, /* size (0 = byte, 1 = short, 2 = long) */
92 false, /* pc_relative */
94 complain_overflow_bitfield, /* complain_on_overflow */
95 bfd_elf_generic_reloc, /* special_function */
96 "R_FR30_32", /* name */
97 true, /* partial_inplace */
98 0x00000000, /* src_mask */
99 0xffffffff, /* dst_mask */
100 false), /* pcrel_offset */
102 /* A 32 bit into 48 bits absolute relocation. */
103 HOWTO (R_FR30_48, /* type */
105 2, /* size (0 = byte, 1 = short, 2 = long) */
107 false, /* pc_relative */
109 complain_overflow_bitfield, /* complain_on_overflow */
110 fr30_elf_i32_reloc, /* special_function */
111 "R_FR30_48", /* name */
112 true, /* partial_inplace */
113 0x00000000, /* src_mask */
114 0xffffffff, /* dst_mask */
115 false), /* pcrel_offset */
117 /* A 6 bit absolute relocation. */
118 HOWTO (R_FR30_6_IN_4, /* type */
120 1, /* size (0 = byte, 1 = short, 2 = long) */
122 false, /* pc_relative */
124 complain_overflow_unsigned, /* complain_on_overflow */
125 bfd_elf_generic_reloc, /* special_function */
126 "R_FR30_6_IN_4", /* name */
127 true, /* partial_inplace */
128 0x0000, /* src_mask */
129 0x00f0, /* dst_mask */
130 false), /* pcrel_offset */
132 /* An 8 bit absolute relocation. */
133 HOWTO (R_FR30_8_IN_8, /* type */
135 1, /* size (0 = byte, 1 = short, 2 = long) */
137 false, /* pc_relative */
139 complain_overflow_signed, /* complain_on_overflow */
140 bfd_elf_generic_reloc,/* special_function */
141 "R_FR30_8_IN_8", /* name */
142 true, /* partial_inplace */
143 0x0000, /* src_mask */
144 0x0ff0, /* dst_mask */
145 false), /* pcrel_offset */
147 /* A 9 bit absolute relocation. */
148 HOWTO (R_FR30_9_IN_8, /* type */
150 1, /* size (0 = byte, 1 = short, 2 = long) */
152 false, /* pc_relative */
154 complain_overflow_signed, /* complain_on_overflow */
155 bfd_elf_generic_reloc,/* special_function */
156 "R_FR30_9_IN_8", /* name */
157 true, /* partial_inplace */
158 0x0000, /* src_mask */
159 0x0ff0, /* dst_mask */
160 false), /* pcrel_offset */
162 /* A 10 bit absolute relocation. */
163 HOWTO (R_FR30_10_IN_8, /* type */
165 1, /* size (0 = byte, 1 = short, 2 = long) */
167 false, /* pc_relative */
169 complain_overflow_signed, /* complain_on_overflow */
170 bfd_elf_generic_reloc,/* special_function */
171 "R_FR30_10_IN_8", /* name */
172 true, /* partial_inplace */
173 0x0000, /* src_mask */
174 0x0ff0, /* dst_mask */
175 false), /* pcrel_offset */
177 /* A PC relative 9 bit relocation, right shifted by 1. */
178 HOWTO (R_FR30_9_PCREL, /* type */
180 1, /* size (0 = byte, 1 = short, 2 = long) */
182 true, /* pc_relative */
184 complain_overflow_signed, /* complain_on_overflow */
185 bfd_elf_generic_reloc, /* special_function */
186 "R_FR30_9_PCREL", /* name */
187 false, /* partial_inplace */
188 0x0000, /* src_mask */
189 0x00ff, /* dst_mask */
190 false), /* pcrel_offset */
192 /* A PC relative 12 bit relocation, right shifted by 1. */
193 HOWTO (R_FR30_12_PCREL, /* type */
195 1, /* size (0 = byte, 1 = short, 2 = long) */
197 true, /* pc_relative */
199 complain_overflow_signed, /* complain_on_overflow */
200 bfd_elf_generic_reloc, /* special_function */
201 "R_FR30_12_PCREL", /* name */
202 false, /* partial_inplace */
203 0x0000, /* src_mask */
204 0x07ff, /* dst_mask */
205 false), /* pcrel_offset */
206 /* GNU extension to record C++ vtable hierarchy */
207 HOWTO (R_FR30_GNU_VTINHERIT, /* type */
209 2, /* size (0 = byte, 1 = short, 2 = long) */
211 false, /* pc_relative */
213 complain_overflow_dont, /* complain_on_overflow */
214 NULL, /* special_function */
215 "R_FR30_GNU_VTINHERIT", /* name */
216 false, /* partial_inplace */
219 false), /* pcrel_offset */
221 /* GNU extension to record C++ vtable member usage */
222 HOWTO (R_FR30_GNU_VTENTRY, /* type */
224 2, /* size (0 = byte, 1 = short, 2 = long) */
226 false, /* pc_relative */
228 complain_overflow_dont, /* complain_on_overflow */
229 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
230 "R_FR30_GNU_VTENTRY", /* name */
231 false, /* partial_inplace */
234 false), /* pcrel_offset */
238 /* Utility to actually perform an R_FR30_20 reloc. */
240 static bfd_reloc_status_type
241 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
242 input_section, output_bfd, error_message)
244 arelent * reloc_entry;
247 asection * input_section;
249 char ** error_message;
254 /* This part is from bfd_elf_generic_reloc. */
255 if (output_bfd != (bfd *) NULL
256 && (symbol->flags & BSF_SECTION_SYM) == 0
257 && (! reloc_entry->howto->partial_inplace
258 || reloc_entry->addend == 0))
260 reloc_entry->address += input_section->output_offset;
264 if (output_bfd != NULL)
265 /* FIXME: See bfd_perform_relocation. Is this right? */
270 + symbol->section->output_section->vma
271 + symbol->section->output_offset
272 + reloc_entry->addend;
274 if (relocation > ((1U << 20) - 1))
275 return bfd_reloc_overflow;
277 x = bfd_get_32 (abfd, data + reloc_entry->address);
278 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
279 bfd_put_32 (abfd, x, data + reloc_entry->address);
285 /* Utility to actually perform a R_FR30_48 reloc. */
287 static bfd_reloc_status_type
288 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
289 input_section, output_bfd, error_message)
291 arelent * reloc_entry;
294 asection * input_section;
296 char ** error_message;
300 /* This part is from bfd_elf_generic_reloc. */
301 if (output_bfd != (bfd *) NULL
302 && (symbol->flags & BSF_SECTION_SYM) == 0
303 && (! reloc_entry->howto->partial_inplace
304 || reloc_entry->addend == 0))
306 reloc_entry->address += input_section->output_offset;
310 if (output_bfd != NULL)
311 /* FIXME: See bfd_perform_relocation. Is this right? */
316 + symbol->section->output_section->vma
317 + symbol->section->output_offset
318 + reloc_entry->addend;
320 bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
325 /* Map BFD reloc types to FR30 ELF reloc types. */
327 struct fr30_reloc_map
329 unsigned int bfd_reloc_val;
330 unsigned int fr30_reloc_val;
333 static const struct fr30_reloc_map fr30_reloc_map [] =
335 { BFD_RELOC_NONE, R_FR30_NONE },
336 { BFD_RELOC_8, R_FR30_8 },
337 { BFD_RELOC_FR30_20, R_FR30_20 },
338 { BFD_RELOC_32, R_FR30_32 },
339 { BFD_RELOC_FR30_48, R_FR30_48 },
340 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
341 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
342 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
343 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
344 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
345 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
346 { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
347 { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY },
350 static reloc_howto_type *
351 fr30_reloc_type_lookup (abfd, code)
353 bfd_reloc_code_real_type code;
357 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
359 if (fr30_reloc_map [i].bfd_reloc_val == code)
360 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
365 /* Set the howto pointer for an FR30 ELF reloc. */
368 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
371 Elf32_Internal_Rela * dst;
375 r_type = ELF32_R_TYPE (dst->r_info);
376 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
377 cache_ptr->howto = & fr30_elf_howto_table [r_type];
380 /* Perform a single relocation. By default we use the standard BFD
381 routines, but a few relocs, we have to do them ourselves. */
383 static bfd_reloc_status_type
384 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
385 reloc_howto_type * howto;
387 asection * input_section;
389 Elf_Internal_Rela * rel;
392 bfd_reloc_status_type r = bfd_reloc_ok;
399 contents += rel->r_offset;
400 relocation += rel->r_addend;
402 if (relocation > ((1 << 20) - 1))
403 return bfd_reloc_overflow;
405 x = bfd_get_32 (input_bfd, contents);
406 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
407 bfd_put_32 (input_bfd, x, contents);
411 contents += rel->r_offset + 2;
412 relocation += rel->r_addend;
413 bfd_put_32 (input_bfd, relocation, contents);
417 contents += rel->r_offset + 1;
418 srel = (bfd_signed_vma) relocation;
419 srel += rel->r_addend;
420 srel -= rel->r_offset;
421 srel -= 2; /* Branch instructions add 2 to the PC... */
422 srel -= (input_section->output_section->vma +
423 input_section->output_offset);
426 return bfd_reloc_outofrange;
427 if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
428 return bfd_reloc_overflow;
430 bfd_put_8 (input_bfd, srel >> 1, contents);
433 case R_FR30_12_PCREL:
434 contents += rel->r_offset;
435 srel = (bfd_signed_vma) relocation;
436 srel += rel->r_addend;
437 srel -= rel->r_offset;
438 srel -= 2; /* Branch instructions add 2 to the PC... */
439 srel -= (input_section->output_section->vma +
440 input_section->output_offset);
443 return bfd_reloc_outofrange;
444 if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
445 return bfd_reloc_overflow;
447 x = bfd_get_16 (input_bfd, contents);
448 x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
449 bfd_put_16 (input_bfd, x, contents);
453 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
454 contents, rel->r_offset,
455 relocation, rel->r_addend);
462 /* Relocate an FR30 ELF section.
463 There is some attempt to make this function usable for many architectures,
464 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
465 if only to serve as a learning tool.
467 The RELOCATE_SECTION function is called by the new ELF backend linker
468 to handle the relocations for a section.
470 The relocs are always passed as Rela structures; if the section
471 actually uses Rel structures, the r_addend field will always be
474 This function is responsible for adjusting the section contents as
475 necessary, and (if using Rela relocs and generating a relocateable
476 output file) adjusting the reloc addend as necessary.
478 This function does not have to worry about setting the reloc
479 address or the reloc symbol index.
481 LOCAL_SYMS is a pointer to the swapped in local symbols.
483 LOCAL_SECTIONS is an array giving the section in the input file
484 corresponding to the st_shndx field of each local symbol.
486 The global hash table entry for the global symbols can be found
487 via elf_sym_hashes (input_bfd).
489 When generating relocateable output, this function must handle
490 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
491 going to be the section symbol corresponding to the output
492 section, which means that the addend must be adjusted
496 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
497 contents, relocs, local_syms, local_sections)
499 struct bfd_link_info * info;
501 asection * input_section;
503 Elf_Internal_Rela * relocs;
504 Elf_Internal_Sym * local_syms;
505 asection ** local_sections;
507 Elf_Internal_Shdr * symtab_hdr;
508 struct elf_link_hash_entry ** sym_hashes;
509 Elf_Internal_Rela * rel;
510 Elf_Internal_Rela * relend;
512 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
513 sym_hashes = elf_sym_hashes (input_bfd);
514 relend = relocs + input_section->reloc_count;
516 for (rel = relocs; rel < relend; rel ++)
518 reloc_howto_type * howto;
519 unsigned long r_symndx;
520 Elf_Internal_Sym * sym;
522 struct elf_link_hash_entry * h;
524 bfd_reloc_status_type r;
525 const char * name = NULL;
527 r_symndx = ELF32_R_SYM (rel->r_info);
529 if (info->relocateable)
531 /* This is a relocateable link. We don't have to change
532 anything, unless the reloc is against a section symbol,
533 in which case we have to adjust according to where the
534 section symbol winds up in the output section. */
535 if (r_symndx < symtab_hdr->sh_info)
537 sym = local_syms + r_symndx;
539 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
541 sec = local_sections [r_symndx];
542 rel->r_addend += sec->output_offset + sym->st_value;
549 /* This is a final link. */
550 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
555 if (r_symndx < symtab_hdr->sh_info)
557 sym = local_syms + r_symndx;
558 sec = local_sections [r_symndx];
559 relocation = (sec->output_section->vma
563 name = bfd_elf_string_from_elf_section
564 (input_bfd, symtab_hdr->sh_link, sym->st_name);
565 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
567 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
568 sec->name, name, sym->st_name,
569 sec->output_section->vma, sec->output_offset,
570 sym->st_value, rel->r_addend);
575 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
577 while (h->root.type == bfd_link_hash_indirect
578 || h->root.type == bfd_link_hash_warning)
579 h = (struct elf_link_hash_entry *) h->root.u.i.link;
581 name = h->root.root.string;
583 if (h->root.type == bfd_link_hash_defined
584 || h->root.type == bfd_link_hash_defweak)
586 sec = h->root.u.def.section;
587 relocation = (h->root.u.def.value
588 + sec->output_section->vma
589 + sec->output_offset);
592 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
593 sec->name, name, h->root.u.def.value,
594 sec->output_section->vma, sec->output_offset, relocation);
597 else if (h->root.type == bfd_link_hash_undefweak)
600 fprintf (stderr, "undefined: sec: %s, name: %s\n",
607 if (! ((*info->callbacks->undefined_symbol)
608 (info, h->root.root.string, input_bfd,
609 input_section, rel->r_offset)))
612 fprintf (stderr, "unknown: name: %s\n", name);
618 r = fr30_final_link_relocate (howto, input_bfd, input_section,
619 contents, rel, relocation);
621 if (r != bfd_reloc_ok)
623 const char * msg = (const char *) NULL;
627 case bfd_reloc_overflow:
628 r = info->callbacks->reloc_overflow
629 (info, name, howto->name, (bfd_vma) 0,
630 input_bfd, input_section, rel->r_offset);
633 case bfd_reloc_undefined:
634 r = info->callbacks->undefined_symbol
635 (info, name, input_bfd, input_section, rel->r_offset);
638 case bfd_reloc_outofrange:
639 msg = _("internal error: out of range error");
642 case bfd_reloc_notsupported:
643 msg = _("internal error: unsupported relocation error");
646 case bfd_reloc_dangerous:
647 msg = _("internal error: dangerous relocation");
651 msg = _("internal error: unknown error");
656 r = info->callbacks->warning
657 (info, msg, name, input_bfd, input_section, rel->r_offset);
667 #define ELF_ARCH bfd_arch_fr30
668 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
669 #define ELF_MAXPAGESIZE 0x1000
671 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
672 #define TARGET_BIG_NAME "elf32-fr30"
674 #define elf_info_to_howto_rel NULL
675 #define elf_info_to_howto fr30_info_to_howto_rela
676 #define elf_backend_relocate_section fr30_elf_relocate_section
678 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
680 #include "elf32-target.h"