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 0x0ff0, /* 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 0x00f0ffff, /* 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 0xffffffff, /* 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_32", /* name */
112 true, /* partial_inplace */
113 0xffffffff, /* 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 0x00f0, /* 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 0x0ff0, /* 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 0x0ff0, /* 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 0x0ff0, /* 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 0x00ff, /* 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 0x07ff, /* src_mask */
204 0x07ff, /* dst_mask */
205 false), /* pcrel_offset */
208 /* Utility to actually perform an R_FR30_20 reloc. */
210 static bfd_reloc_status_type
211 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
212 input_section, output_bfd, error_message)
214 arelent * reloc_entry;
217 asection * input_section;
219 char ** error_message;
224 /* This part is from bfd_elf_generic_reloc. */
225 if (output_bfd != (bfd *) NULL
226 && (symbol->flags & BSF_SECTION_SYM) == 0
227 && (! reloc_entry->howto->partial_inplace
228 || reloc_entry->addend == 0))
230 reloc_entry->address += input_section->output_offset;
234 if (output_bfd != NULL)
235 /* FIXME: See bfd_perform_relocation. Is this right? */
240 + symbol->section->output_section->vma
241 + symbol->section->output_offset
242 + reloc_entry->addend;
244 if (relocation > ((1U << 20) - 1))
245 return bfd_reloc_overflow;
247 x = bfd_get_32 (abfd, data + reloc_entry->address);
248 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
249 bfd_put_32 (abfd, x, data + reloc_entry->address);
255 /* Utility to actually perform a R_FR30_48 reloc. */
257 static bfd_reloc_status_type
258 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
259 input_section, output_bfd, error_message)
261 arelent * reloc_entry;
264 asection * input_section;
266 char ** error_message;
270 /* This part is from bfd_elf_generic_reloc. */
271 if (output_bfd != (bfd *) NULL
272 && (symbol->flags & BSF_SECTION_SYM) == 0
273 && (! reloc_entry->howto->partial_inplace
274 || reloc_entry->addend == 0))
276 reloc_entry->address += input_section->output_offset;
280 if (output_bfd != NULL)
281 /* FIXME: See bfd_perform_relocation. Is this right? */
286 + symbol->section->output_section->vma
287 + symbol->section->output_offset
288 + reloc_entry->addend;
290 bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
295 /* Map BFD reloc types to FR30 ELF reloc types. */
297 struct fr30_reloc_map
299 unsigned int bfd_reloc_val;
300 unsigned int fr30_reloc_val;
303 static const struct fr30_reloc_map fr30_reloc_map [] =
305 { BFD_RELOC_NONE, R_FR30_NONE },
306 { BFD_RELOC_8, R_FR30_8 },
307 { BFD_RELOC_FR30_20, R_FR30_20 },
308 { BFD_RELOC_32, R_FR30_32 },
309 { BFD_RELOC_FR30_48, R_FR30_48 },
310 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
311 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
312 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
313 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
314 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
315 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
318 static reloc_howto_type *
319 fr30_reloc_type_lookup (abfd, code)
321 bfd_reloc_code_real_type code;
325 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
327 if (fr30_reloc_map [i].bfd_reloc_val == code)
328 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
333 /* Set the howto pointer for an FR30 ELF reloc. */
336 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
339 Elf32_Internal_Rela * dst;
343 r_type = ELF32_R_TYPE (dst->r_info);
344 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
345 cache_ptr->howto = & fr30_elf_howto_table [r_type];
348 /* Perform a single relocation. By default we use the standard BFD
349 routines, but a few relocs, we have to do them ourselves. */
351 static bfd_reloc_status_type
352 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
353 reloc_howto_type * howto;
355 asection * input_section;
357 Elf_Internal_Rela * rel;
360 bfd_reloc_status_type r = bfd_reloc_ok;
367 contents += rel->r_offset;
368 relocation += rel->r_addend;
370 if (relocation > ((1 << 20) - 1))
371 return bfd_reloc_overflow;
373 x = bfd_get_32 (input_bfd, contents);
374 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
375 bfd_put_32 (input_bfd, relocation, contents);
379 contents += rel->r_offset + 2;
380 relocation += rel->r_addend;
381 bfd_put_32 (input_bfd, relocation, contents);
385 contents += rel->r_offset + 1;
386 srel = (bfd_signed_vma) relocation;
387 srel += rel->r_addend;
388 srel -= rel->r_offset;
389 srel -= 2; /* Branch instructions add 2 to the PC... */
390 srel -= (input_section->output_section->vma +
391 input_section->output_offset);
394 return bfd_reloc_outofrange;
395 if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
396 return bfd_reloc_overflow;
398 bfd_put_8 (input_bfd, srel >> 1, contents);
401 case R_FR30_12_PCREL:
402 contents += rel->r_offset;
403 srel = (bfd_signed_vma) relocation;
404 srel += rel->r_addend;
405 srel -= rel->r_offset;
406 srel -= 2; /* Branch instructions add 2 to the PC... */
407 srel -= (input_section->output_section->vma +
408 input_section->output_offset);
411 return bfd_reloc_outofrange;
412 if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
413 return bfd_reloc_overflow;
415 x = bfd_get_16 (input_bfd, contents);
416 x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
417 bfd_put_16 (input_bfd, x, contents);
421 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
422 contents, rel->r_offset,
423 relocation, rel->r_addend);
430 /* Relocate an FR30 ELF section.
431 There is some attempt to make this function usable for many architectures,
432 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
433 if only to serve as a learning tool.
435 The RELOCATE_SECTION function is called by the new ELF backend linker
436 to handle the relocations for a section.
438 The relocs are always passed as Rela structures; if the section
439 actually uses Rel structures, the r_addend field will always be
442 This function is responsible for adjusting the section contents as
443 necessary, and (if using Rela relocs and generating a relocateable
444 output file) adjusting the reloc addend as necessary.
446 This function does not have to worry about setting the reloc
447 address or the reloc symbol index.
449 LOCAL_SYMS is a pointer to the swapped in local symbols.
451 LOCAL_SECTIONS is an array giving the section in the input file
452 corresponding to the st_shndx field of each local symbol.
454 The global hash table entry for the global symbols can be found
455 via elf_sym_hashes (input_bfd).
457 When generating relocateable output, this function must handle
458 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
459 going to be the section symbol corresponding to the output
460 section, which means that the addend must be adjusted
464 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
465 contents, relocs, local_syms, local_sections)
467 struct bfd_link_info * info;
469 asection * input_section;
471 Elf_Internal_Rela * relocs;
472 Elf_Internal_Sym * local_syms;
473 asection ** local_sections;
475 Elf_Internal_Shdr * symtab_hdr;
476 struct elf_link_hash_entry ** sym_hashes;
477 Elf_Internal_Rela * rel;
478 Elf_Internal_Rela * relend;
480 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
481 sym_hashes = elf_sym_hashes (input_bfd);
482 relend = relocs + input_section->reloc_count;
484 for (rel = relocs; rel < relend; rel ++)
486 reloc_howto_type * howto;
487 unsigned long r_symndx;
488 Elf_Internal_Sym * sym;
490 struct elf_link_hash_entry * h;
492 bfd_reloc_status_type r;
493 const char * name = NULL;
495 r_symndx = ELF32_R_SYM (rel->r_info);
497 if (info->relocateable)
499 /* This is a relocateable link. We don't have to change
500 anything, unless the reloc is against a section symbol,
501 in which case we have to adjust according to where the
502 section symbol winds up in the output section. */
503 if (r_symndx < symtab_hdr->sh_info)
505 sym = local_syms + r_symndx;
507 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
509 sec = local_sections [r_symndx];
510 rel->r_addend += sec->output_offset + sym->st_value;
517 /* This is a final link. */
518 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
523 if (r_symndx < symtab_hdr->sh_info)
525 sym = local_syms + r_symndx;
526 sec = local_sections [r_symndx];
527 relocation = (sec->output_section->vma
531 name = bfd_elf_string_from_elf_section
532 (input_bfd, symtab_hdr->sh_link, sym->st_name);
533 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
535 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
536 sec->name, name, sym->st_name,
537 sec->output_section->vma, sec->output_offset,
538 sym->st_value, rel->r_addend);
543 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
545 while (h->root.type == bfd_link_hash_indirect
546 || h->root.type == bfd_link_hash_warning)
547 h = (struct elf_link_hash_entry *) h->root.u.i.link;
549 name = h->root.root.string;
551 if (h->root.type == bfd_link_hash_defined
552 || h->root.type == bfd_link_hash_defweak)
554 sec = h->root.u.def.section;
555 relocation = (h->root.u.def.value
556 + sec->output_section->vma
557 + sec->output_offset);
560 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
561 sec->name, name, h->root.u.def.value,
562 sec->output_section->vma, sec->output_offset, relocation);
565 else if (h->root.type == bfd_link_hash_undefweak)
568 fprintf (stderr, "undefined: sec: %s, name: %s\n",
575 if (! ((*info->callbacks->undefined_symbol)
576 (info, h->root.root.string, input_bfd,
577 input_section, rel->r_offset)))
580 fprintf (stderr, "unknown: name: %s\n", name);
586 r = fr30_final_link_relocate (howto, input_bfd, input_section,
587 contents, rel, relocation);
589 if (r != bfd_reloc_ok)
591 const char * msg = (const char *) NULL;
595 case bfd_reloc_overflow:
596 r = info->callbacks->reloc_overflow
597 (info, name, howto->name, (bfd_vma) 0,
598 input_bfd, input_section, rel->r_offset);
601 case bfd_reloc_undefined:
602 r = info->callbacks->undefined_symbol
603 (info, name, input_bfd, input_section, rel->r_offset);
606 case bfd_reloc_outofrange:
607 msg = _("internal error: out of range error");
610 case bfd_reloc_notsupported:
611 msg = _("internal error: unsupported relocation error");
614 case bfd_reloc_dangerous:
615 msg = _("internal error: dangerous relocation");
619 msg = _("internal error: unknown error");
624 r = info->callbacks->warning
625 (info, msg, name, input_bfd, input_section, rel->r_offset);
635 #define ELF_ARCH bfd_arch_fr30
636 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
637 #define ELF_MAXPAGESIZE 0x1000
639 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
640 #define TARGET_BIG_NAME "elf32-fr30"
642 #define elf_info_to_howto_rel NULL
643 #define elf_info_to_howto fr30_info_to_howto_rela
644 #define elf_backend_relocate_section fr30_elf_relocate_section
646 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
648 #include "elf32-target.h"