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 bfd_reloc_status_type fr30_elf_pc9_reloc
32 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
33 static bfd_reloc_status_type fr30_elf_pc12_reloc
34 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
35 static reloc_howto_type * fr30_reloc_type_lookup
36 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
37 static void fr30_info_to_howto_rela
38 PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
39 static boolean fr30_elf_relocate_section
40 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, 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 *, Elf_Internal_Rela *, bfd_vma));
44 static reloc_howto_type fr30_elf_howto_table [] =
46 /* This reloc does nothing. */
47 HOWTO (R_FR30_NONE, /* type */
49 2, /* size (0 = byte, 1 = short, 2 = long) */
51 false, /* pc_relative */
53 complain_overflow_bitfield, /* complain_on_overflow */
54 bfd_elf_generic_reloc, /* special_function */
55 "R_FR30_NONE", /* name */
56 false, /* partial_inplace */
59 false), /* pcrel_offset */
61 /* An 8 bit absolute relocation. */
62 HOWTO (R_FR30_8, /* type */
64 1, /* size (0 = byte, 1 = short, 2 = long) */
66 false, /* pc_relative */
68 complain_overflow_bitfield, /* complain_on_overflow */
69 bfd_elf_generic_reloc, /* special_function */
70 "R_FR30_8", /* name */
71 true, /* partial_inplace */
72 0x0ff0, /* src_mask */
73 0x0ff0, /* dst_mask */
74 false), /* pcrel_offset */
76 /* A 20 bit absolute relocation. */
77 HOWTO (R_FR30_20, /* type */
79 2, /* size (0 = byte, 1 = short, 2 = long) */
81 false, /* pc_relative */
83 complain_overflow_bitfield, /* complain_on_overflow */
84 fr30_elf_i20_reloc, /* special_function */
85 "R_FR30_20", /* name */
86 true, /* partial_inplace */
87 0x00f0ffff, /* src_mask */
88 0x00f0ffff, /* dst_mask */
89 false), /* pcrel_offset */
91 /* A 32 bit absolute relocation. */
92 HOWTO (R_FR30_32, /* type */
94 2, /* size (0 = byte, 1 = short, 2 = long) */
96 false, /* pc_relative */
98 complain_overflow_bitfield, /* complain_on_overflow */
99 fr30_elf_i32_reloc, /* special_function */
100 "R_FR30_32", /* name */
101 true, /* partial_inplace */
102 0xffffffff, /* src_mask */
103 0xffffffff, /* dst_mask */
104 false), /* pcrel_offset */
106 /* A 6 bit absolute relocation. */
107 HOWTO (R_FR30_6_IN_4, /* type */
109 1, /* size (0 = byte, 1 = short, 2 = long) */
111 false, /* pc_relative */
113 complain_overflow_unsigned, /* complain_on_overflow */
114 bfd_elf_generic_reloc, /* special_function */
115 "R_FR30_6_IN_4", /* name */
116 true, /* partial_inplace */
117 0x00f0, /* src_mask */
118 0x00f0, /* dst_mask */
119 false), /* pcrel_offset */
121 /* An 8 bit absolute relocation. */
122 HOWTO (R_FR30_8_IN_8, /* type */
124 1, /* size (0 = byte, 1 = short, 2 = long) */
126 false, /* pc_relative */
128 complain_overflow_signed, /* complain_on_overflow */
129 bfd_elf_generic_reloc,/* special_function */
130 "R_FR30_8_IN_8", /* name */
131 true, /* partial_inplace */
132 0x0ff0, /* src_mask */
133 0x0ff0, /* dst_mask */
134 false), /* pcrel_offset */
136 /* A 9 bit absolute relocation. */
137 HOWTO (R_FR30_9_IN_8, /* type */
139 1, /* size (0 = byte, 1 = short, 2 = long) */
141 false, /* pc_relative */
143 complain_overflow_signed, /* complain_on_overflow */
144 bfd_elf_generic_reloc,/* special_function */
145 "R_FR30_9_IN_8", /* name */
146 true, /* partial_inplace */
147 0x0ff0, /* src_mask */
148 0x0ff0, /* dst_mask */
149 false), /* pcrel_offset */
151 /* A 10 bit absolute relocation. */
152 HOWTO (R_FR30_10_IN_8, /* type */
154 1, /* size (0 = byte, 1 = short, 2 = long) */
156 false, /* pc_relative */
158 complain_overflow_signed, /* complain_on_overflow */
159 bfd_elf_generic_reloc,/* special_function */
160 "R_FR30_10_IN_8", /* name */
161 true, /* partial_inplace */
162 0x0ff0, /* src_mask */
163 0x0ff0, /* dst_mask */
164 false), /* pcrel_offset */
166 /* A PC relative 9 bit relocation, right shifted by 1. */
167 HOWTO (R_FR30_9_PCREL, /* type */
169 1, /* size (0 = byte, 1 = short, 2 = long) */
171 true, /* pc_relative */
173 complain_overflow_signed, /* complain_on_overflow */
174 fr30_elf_pc9_reloc, /* special_function */
175 "R_FR30_9_PCREL", /* name */
176 false, /* partial_inplace */
177 0x00ff, /* src_mask */
178 0x00ff, /* dst_mask */
179 false), /* pcrel_offset */
181 /* A PC relative 12 bit relocation, right shifted by 1. */
182 HOWTO (R_FR30_12_PCREL, /* type */
184 1, /* size (0 = byte, 1 = short, 2 = long) */
186 true, /* pc_relative */
188 complain_overflow_signed, /* complain_on_overflow */
189 fr30_elf_pc12_reloc, /* special_function */
190 "R_FR30_12_PCREL", /* name */
191 false, /* partial_inplace */
192 0x07ff, /* src_mask */
193 0x07ff, /* dst_mask */
194 false), /* pcrel_offset */
197 /* Utility to actually perform an R_FR30_20 reloc. */
199 static bfd_reloc_status_type
200 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
201 input_section, output_bfd, error_message)
203 arelent * reloc_entry;
206 asection * input_section;
208 char ** error_message;
213 /* This part is from bfd_elf_generic_reloc. */
214 if (output_bfd != (bfd *) NULL
215 && (symbol->flags & BSF_SECTION_SYM) == 0
216 && (! reloc_entry->howto->partial_inplace
217 || reloc_entry->addend == 0))
219 reloc_entry->address += input_section->output_offset;
223 if (output_bfd != NULL)
224 /* FIXME: See bfd_perform_relocation. Is this right? */
229 + symbol->section->output_section->vma
230 + symbol->section->output_offset
231 + reloc_entry->addend;
233 if (relocation > ((1U << 20) - 1))
234 return bfd_reloc_overflow;
236 x = bfd_get_32 (abfd, data + reloc_entry->address);
237 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
238 bfd_put_32 (abfd, x, data + reloc_entry->address);
244 /* Utility to actually perform a R_FR30_32 reloc. */
246 static bfd_reloc_status_type
247 fr30_elf_i32_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;
259 /* This part is from bfd_elf_generic_reloc. */
260 if (output_bfd != (bfd *) NULL
261 && (symbol->flags & BSF_SECTION_SYM) == 0
262 && (! reloc_entry->howto->partial_inplace
263 || reloc_entry->addend == 0))
265 reloc_entry->address += input_section->output_offset;
269 if (output_bfd != NULL)
270 /* FIXME: See bfd_perform_relocation. Is this right? */
275 + symbol->section->output_section->vma
276 + symbol->section->output_offset
277 + reloc_entry->addend;
279 bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
285 /* Utility to actually perform a R_FR30_9_PCREL reloc. */
287 static bfd_reloc_status_type
288 fr30_elf_pc9_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;
298 bfd_signed_vma relocation;
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
319 - input_section->output_section->vma
320 - input_section->output_offset
324 return bfd_reloc_outofrange;
326 if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
327 return bfd_reloc_overflow;
329 bfd_put_8 (abfd, relocation >> 1, data + reloc_entry->address + 1);
335 /* Utility to actually perform a R_FR30_12_PCREL reloc. */
337 static bfd_reloc_status_type
338 fr30_elf_pc12_reloc (abfd, reloc_entry, symbol, data,
339 input_section, output_bfd, error_message)
341 arelent * reloc_entry;
344 asection * input_section;
346 char ** error_message;
348 bfd_signed_vma relocation;
352 /* This part is from bfd_elf_generic_reloc. */
353 if (output_bfd != (bfd *) NULL
354 && (symbol->flags & BSF_SECTION_SYM) == 0
355 && (! reloc_entry->howto->partial_inplace
356 || reloc_entry->addend == 0))
358 reloc_entry->address += input_section->output_offset;
362 if (output_bfd != NULL)
363 /* FIXME: See bfd_perform_relocation. Is this right? */
368 + symbol->section->output_section->vma
369 + symbol->section->output_offset
370 + reloc_entry->addend
371 - input_section->output_section->vma
372 - input_section->output_offset
376 return bfd_reloc_outofrange;
378 if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
379 return bfd_reloc_overflow;
381 data += reloc_entry->address;
383 x = bfd_get_16 (abfd, data);
384 x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
385 bfd_put_16 (abfd, x, data);
391 /* Map BFD reloc types to FR30 ELF reloc types. */
393 struct fr30_reloc_map
395 unsigned int bfd_reloc_val;
396 unsigned int fr30_reloc_val;
399 static const struct fr30_reloc_map fr30_reloc_map [] =
401 { BFD_RELOC_NONE, R_FR30_NONE },
402 { BFD_RELOC_8, R_FR30_8 },
403 { BFD_RELOC_FR30_20, R_FR30_20 },
404 { BFD_RELOC_32, R_FR30_32 },
405 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
406 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
407 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
408 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
409 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
410 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
413 static reloc_howto_type *
414 fr30_reloc_type_lookup (abfd, code)
416 bfd_reloc_code_real_type code;
420 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
422 if (fr30_reloc_map [i].bfd_reloc_val == code)
423 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
428 /* Set the howto pointer for an FR30 ELF reloc. */
431 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
434 Elf32_Internal_Rela * dst;
438 r_type = ELF32_R_TYPE (dst->r_info);
439 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
440 cache_ptr->howto = & fr30_elf_howto_table [r_type];
443 /* Perform a single relocation. By default we use the standard BFD
444 routines, but a few relocs, we have to do them ourselves. */
446 static bfd_reloc_status_type
447 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
448 reloc_howto_type * howto;
450 asection * input_section;
452 Elf_Internal_Rela * rel;
455 bfd_reloc_status_type r = bfd_reloc_ok;
461 contents += rel->r_offset;
462 relocation += rel->r_addend;
464 if (relocation > ((1 << 20) - 1))
465 return bfd_reloc_overflow;
467 x = bfd_get_32 (input_bfd, contents);
468 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
469 bfd_put_32 (input_bfd, relocation, contents);
473 contents += rel->r_offset + 2;
474 relocation += rel->r_addend;
475 bfd_put_32 (input_bfd, relocation, contents);
479 contents += rel->r_offset + 1;
480 relocation += rel->r_addend;
481 relocation -= (input_section->output_section->vma +
482 input_section->output_offset);
485 return bfd_reloc_outofrange;
486 if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
487 return bfd_reloc_overflow;
489 bfd_put_8 (input_bfd, relocation >> 1, contents);
492 case R_FR30_12_PCREL:
493 contents += rel->r_offset;
494 relocation += rel->r_addend;
495 relocation -= (input_section->output_section->vma +
496 input_section->output_offset);
499 return bfd_reloc_outofrange;
500 if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
501 return bfd_reloc_overflow;
503 x = bfd_get_16 (input_bfd, contents);
504 x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
505 bfd_put_16 (input_bfd, x, contents);
509 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
510 contents, rel->r_offset,
511 relocation, rel->r_addend);
518 /* Relocate an FR30 ELF section.
519 There is some attempt to make this function usable for many architectures,
520 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
521 if only to serve as a learning tool.
523 The RELOCATE_SECTION function is called by the new ELF backend linker
524 to handle the relocations for a section.
526 The relocs are always passed as Rela structures; if the section
527 actually uses Rel structures, the r_addend field will always be
530 This function is responsible for adjusting the section contents as
531 necessary, and (if using Rela relocs and generating a relocateable
532 output file) adjusting the reloc addend as necessary.
534 This function does not have to worry about setting the reloc
535 address or the reloc symbol index.
537 LOCAL_SYMS is a pointer to the swapped in local symbols.
539 LOCAL_SECTIONS is an array giving the section in the input file
540 corresponding to the st_shndx field of each local symbol.
542 The global hash table entry for the global symbols can be found
543 via elf_sym_hashes (input_bfd).
545 When generating relocateable output, this function must handle
546 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
547 going to be the section symbol corresponding to the output
548 section, which means that the addend must be adjusted
552 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
553 contents, relocs, local_syms, local_sections)
555 struct bfd_link_info * info;
557 asection * input_section;
559 Elf_Internal_Rela * relocs;
560 Elf_Internal_Sym * local_syms;
561 asection ** local_sections;
563 Elf_Internal_Shdr * symtab_hdr;
564 struct elf_link_hash_entry ** sym_hashes;
565 Elf_Internal_Rela * rel;
566 Elf_Internal_Rela * relend;
568 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
569 sym_hashes = elf_sym_hashes (input_bfd);
570 relend = relocs + input_section->reloc_count;
572 for (rel = relocs; rel < relend; rel ++)
574 reloc_howto_type * howto;
575 unsigned long r_symndx;
576 Elf_Internal_Sym * sym;
578 struct elf_link_hash_entry * h;
580 bfd_reloc_status_type r;
581 const char * name = NULL;
583 r_symndx = ELF32_R_SYM (rel->r_info);
585 if (info->relocateable)
587 /* This is a relocateable link. We don't have to change
588 anything, unless the reloc is against a section symbol,
589 in which case we have to adjust according to where the
590 section symbol winds up in the output section. */
591 if (r_symndx < symtab_hdr->sh_info)
593 sym = local_syms + r_symndx;
595 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
597 sec = local_sections [r_symndx];
598 rel->r_addend += sec->output_offset + sym->st_value;
605 /* This is a final link. */
606 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
611 if (r_symndx < symtab_hdr->sh_info)
613 sym = local_syms + r_symndx;
614 sec = local_sections [r_symndx];
615 relocation = (sec->output_section->vma
619 name = bfd_elf_string_from_elf_section
620 (input_bfd, symtab_hdr->sh_link, sym->st_name);
621 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
623 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
624 sec->name, name, sym->st_name,
625 sec->output_section->vma, sec->output_offset,
626 sym->st_value, rel->r_addend);
631 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
633 while (h->root.type == bfd_link_hash_indirect
634 || h->root.type == bfd_link_hash_warning)
635 h = (struct elf_link_hash_entry *) h->root.u.i.link;
637 name = h->root.root.string;
639 if (h->root.type == bfd_link_hash_defined
640 || h->root.type == bfd_link_hash_defweak)
642 sec = h->root.u.def.section;
643 relocation = (h->root.u.def.value
644 + sec->output_section->vma
645 + sec->output_offset);
648 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
649 sec->name, name, h->root.u.def.value,
650 sec->output_section->vma, sec->output_offset, relocation);
653 else if (h->root.type == bfd_link_hash_undefweak)
656 fprintf (stderr, "undefined: sec: %s, name: %s\n",
663 if (! ((*info->callbacks->undefined_symbol)
664 (info, h->root.root.string, input_bfd,
665 input_section, rel->r_offset)))
668 fprintf (stderr, "unknown: name: %s\n", name);
674 r = fr30_final_link_relocate (howto, input_bfd, input_section,
675 contents, rel, relocation);
677 if (r != bfd_reloc_ok)
679 const char * msg = (const char *) NULL;
683 case bfd_reloc_overflow:
684 r = info->callbacks->reloc_overflow
685 (info, name, howto->name, (bfd_vma) 0,
686 input_bfd, input_section, rel->r_offset);
689 case bfd_reloc_undefined:
690 r = info->callbacks->undefined_symbol
691 (info, name, input_bfd, input_section, rel->r_offset);
694 case bfd_reloc_outofrange:
695 msg = _("internal error: out of range error");
698 case bfd_reloc_notsupported:
699 msg = _("internal error: unsupported relocation error");
702 case bfd_reloc_dangerous:
703 msg = _("internal error: dangerous relocation");
707 msg = _("internal error: unknown error");
712 r = info->callbacks->warning
713 (info, msg, name, input_bfd, input_section, rel->r_offset);
723 #define ELF_ARCH bfd_arch_fr30
724 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
725 #define ELF_MAXPAGESIZE 0x1000
727 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
728 #define TARGET_BIG_NAME "elf32-fr30"
730 #define elf_info_to_howto_rel NULL
731 #define elf_info_to_howto fr30_info_to_howto_rela
732 #define elf_backend_relocate_section fr30_elf_relocate_section
734 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
736 #include "elf32-target.h"