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 fr30_elf_i32_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 6 bit absolute relocation. */
103 HOWTO (R_FR30_6_IN_4, /* type */
105 1, /* size (0 = byte, 1 = short, 2 = long) */
107 false, /* pc_relative */
109 complain_overflow_unsigned, /* complain_on_overflow */
110 bfd_elf_generic_reloc, /* special_function */
111 "R_FR30_6_IN_4", /* name */
112 true, /* partial_inplace */
113 0x00f0, /* src_mask */
114 0x00f0, /* dst_mask */
115 false), /* pcrel_offset */
117 /* An 8 bit absolute relocation. */
118 HOWTO (R_FR30_8_IN_8, /* type */
120 1, /* size (0 = byte, 1 = short, 2 = long) */
122 false, /* pc_relative */
124 complain_overflow_signed, /* complain_on_overflow */
125 bfd_elf_generic_reloc,/* special_function */
126 "R_FR30_8_IN_8", /* name */
127 true, /* partial_inplace */
128 0x0ff0, /* src_mask */
129 0x0ff0, /* dst_mask */
130 false), /* pcrel_offset */
132 /* A 9 bit absolute relocation. */
133 HOWTO (R_FR30_9_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_9_IN_8", /* name */
142 true, /* partial_inplace */
143 0x0ff0, /* src_mask */
144 0x0ff0, /* dst_mask */
145 false), /* pcrel_offset */
147 /* A 10 bit absolute relocation. */
148 HOWTO (R_FR30_10_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_10_IN_8", /* name */
157 true, /* partial_inplace */
158 0x0ff0, /* src_mask */
159 0x0ff0, /* dst_mask */
160 false), /* pcrel_offset */
162 /* A PC relative 9 bit relocation, right shifted by 1. */
163 HOWTO (R_FR30_9_PCREL, /* type */
165 1, /* size (0 = byte, 1 = short, 2 = long) */
167 true, /* pc_relative */
169 complain_overflow_signed, /* complain_on_overflow */
170 bfd_elf_generic_reloc, /* special_function */
171 "R_FR30_9_PCREL", /* name */
172 false, /* partial_inplace */
173 0x00ff, /* src_mask */
174 0x00ff, /* dst_mask */
175 true), /* pcrel_offset */
177 /* A PC relative 12 bit relocation, right shifted by 1. */
178 HOWTO (R_FR30_12_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_12_PCREL", /* name */
187 false, /* partial_inplace */
188 0x07ff, /* src_mask */
189 0x07ff, /* dst_mask */
190 true), /* pcrel_offset */
193 /* Utility to actually perform an R_FR30_20 reloc. */
195 static bfd_reloc_status_type
196 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
197 input_section, output_bfd, error_message)
199 arelent * reloc_entry;
202 asection * input_section;
204 char ** error_message;
209 /* This part is from bfd_elf_generic_reloc. */
210 if (output_bfd != (bfd *) NULL
211 && (symbol->flags & BSF_SECTION_SYM) == 0
212 && (! reloc_entry->howto->partial_inplace
213 || reloc_entry->addend == 0))
215 reloc_entry->address += input_section->output_offset;
219 if (output_bfd != NULL)
220 /* FIXME: See bfd_perform_relocation. Is this right? */
225 + symbol->section->output_section->vma
226 + symbol->section->output_offset
227 + reloc_entry->addend;
229 if (relocation > ((1U << 20) - 1))
230 return bfd_reloc_overflow;
232 x = bfd_get_32 (abfd, data + reloc_entry->address);
233 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
234 bfd_put_32 (abfd, x, data + reloc_entry->address);
240 /* Utility to actually perform a R_FR30_32 reloc. */
242 static bfd_reloc_status_type
243 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
244 input_section, output_bfd, error_message)
246 arelent * reloc_entry;
249 asection * input_section;
251 char ** error_message;
255 /* This part is from bfd_elf_generic_reloc. */
256 if (output_bfd != (bfd *) NULL
257 && (symbol->flags & BSF_SECTION_SYM) == 0
258 && (! reloc_entry->howto->partial_inplace
259 || reloc_entry->addend == 0))
261 reloc_entry->address += input_section->output_offset;
265 if (output_bfd != NULL)
266 /* FIXME: See bfd_perform_relocation. Is this right? */
271 + symbol->section->output_section->vma
272 + symbol->section->output_offset
273 + reloc_entry->addend;
275 bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
281 /* Map BFD reloc types to FR30 ELF reloc types. */
283 struct fr30_reloc_map
285 unsigned int bfd_reloc_val;
286 unsigned int fr30_reloc_val;
289 static const struct fr30_reloc_map fr30_reloc_map [] =
291 { BFD_RELOC_NONE, R_FR30_NONE },
292 { BFD_RELOC_8, R_FR30_8 },
293 { BFD_RELOC_FR30_20, R_FR30_20 },
294 { BFD_RELOC_32, R_FR30_32 },
295 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
296 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
297 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
298 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
299 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
300 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
303 static reloc_howto_type *
304 fr30_reloc_type_lookup (abfd, code)
306 bfd_reloc_code_real_type code;
310 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
312 if (fr30_reloc_map [i].bfd_reloc_val == code)
313 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
318 /* Set the howto pointer for an FR30 ELF reloc. */
321 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
324 Elf32_Internal_Rela * dst;
328 r_type = ELF32_R_TYPE (dst->r_info);
329 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
330 cache_ptr->howto = & fr30_elf_howto_table [r_type];
333 /* Perform a single relocation. By default we use the standard BFD
334 routines, but a few relocs, we have to do them ourselves. */
336 static bfd_reloc_status_type
337 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
338 reloc_howto_type * howto;
340 asection * input_section;
342 Elf_Internal_Rela * rel;
345 bfd_reloc_status_type r = bfd_reloc_ok;
351 contents += rel->r_offset;
352 relocation += rel->r_addend;
353 x = bfd_get_32 (input_bfd, contents);
354 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
355 bfd_put_32 (input_bfd, relocation, contents);
359 contents += rel->r_offset + 2;
360 relocation += rel->r_addend;
361 bfd_put_32 (input_bfd, relocation, contents);
365 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
366 contents, rel->r_offset,
367 relocation, rel->r_addend);
374 /* Relocate an FR30 ELF section.
375 There is some attempt to make this function usable for many architectures,
376 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
377 if only to serve as a learning tool.
379 The RELOCATE_SECTION function is called by the new ELF backend linker
380 to handle the relocations for a section.
382 The relocs are always passed as Rela structures; if the section
383 actually uses Rel structures, the r_addend field will always be
386 This function is responsible for adjusting the section contents as
387 necessary, and (if using Rela relocs and generating a relocateable
388 output file) adjusting the reloc addend as necessary.
390 This function does not have to worry about setting the reloc
391 address or the reloc symbol index.
393 LOCAL_SYMS is a pointer to the swapped in local symbols.
395 LOCAL_SECTIONS is an array giving the section in the input file
396 corresponding to the st_shndx field of each local symbol.
398 The global hash table entry for the global symbols can be found
399 via elf_sym_hashes (input_bfd).
401 When generating relocateable output, this function must handle
402 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
403 going to be the section symbol corresponding to the output
404 section, which means that the addend must be adjusted
408 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
409 contents, relocs, local_syms, local_sections)
411 struct bfd_link_info * info;
413 asection * input_section;
415 Elf_Internal_Rela * relocs;
416 Elf_Internal_Sym * local_syms;
417 asection ** local_sections;
419 Elf_Internal_Shdr * symtab_hdr;
420 struct elf_link_hash_entry ** sym_hashes;
421 Elf_Internal_Rela * rel;
422 Elf_Internal_Rela * relend;
424 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
425 sym_hashes = elf_sym_hashes (input_bfd);
426 relend = relocs + input_section->reloc_count;
428 for (rel = relocs; rel < relend; rel ++)
430 reloc_howto_type * howto;
431 unsigned long r_symndx;
432 Elf_Internal_Sym * sym;
434 struct elf_link_hash_entry * h;
436 bfd_reloc_status_type r;
437 const char * name = NULL;
439 r_symndx = ELF32_R_SYM (rel->r_info);
441 if (info->relocateable)
443 /* This is a relocateable link. We don't have to change
444 anything, unless the reloc is against a section symbol,
445 in which case we have to adjust according to where the
446 section symbol winds up in the output section. */
447 if (r_symndx < symtab_hdr->sh_info)
449 sym = local_syms + r_symndx;
451 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
453 sec = local_sections [r_symndx];
454 rel->r_addend += sec->output_offset + sym->st_value;
461 /* This is a final link. */
462 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
467 if (r_symndx < symtab_hdr->sh_info)
469 sym = local_syms + r_symndx;
470 sec = local_sections [r_symndx];
471 relocation = (sec->output_section->vma
475 name = bfd_elf_string_from_elf_section
476 (input_bfd, symtab_hdr->sh_link, sym->st_name);
477 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
479 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
480 sec->name, name, sym->st_name,
481 sec->output_section->vma, sec->output_offset,
482 sym->st_value, rel->r_addend);
487 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
489 while (h->root.type == bfd_link_hash_indirect
490 || h->root.type == bfd_link_hash_warning)
491 h = (struct elf_link_hash_entry *) h->root.u.i.link;
493 name = h->root.root.string;
495 if (h->root.type == bfd_link_hash_defined
496 || h->root.type == bfd_link_hash_defweak)
498 sec = h->root.u.def.section;
499 relocation = (h->root.u.def.value
500 + sec->output_section->vma
501 + sec->output_offset);
504 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
505 sec->name, name, h->root.u.def.value,
506 sec->output_section->vma, sec->output_offset, relocation);
509 else if (h->root.type == bfd_link_hash_undefweak)
512 fprintf (stderr, "undefined: sec: %s, name: %s\n",
519 if (! ((*info->callbacks->undefined_symbol)
520 (info, h->root.root.string, input_bfd,
521 input_section, rel->r_offset)))
524 fprintf (stderr, "unknown: name: %s\n", name);
530 r = fr30_final_link_relocate (howto, input_bfd, input_section,
531 contents, rel, relocation);
533 if (r != bfd_reloc_ok)
535 const char * msg = (const char *) NULL;
539 case bfd_reloc_overflow:
540 r = info->callbacks->reloc_overflow
541 (info, name, howto->name, (bfd_vma) 0,
542 input_bfd, input_section, rel->r_offset);
545 case bfd_reloc_undefined:
546 r = info->callbacks->undefined_symbol
547 (info, name, input_bfd, input_section, rel->r_offset);
550 case bfd_reloc_outofrange:
551 msg = _("internal error: out of range error");
554 case bfd_reloc_notsupported:
555 msg = _("internal error: unsupported relocation error");
558 case bfd_reloc_dangerous:
559 msg = _("internal error: dangerous relocation");
563 msg = _("internal error: unknown error");
568 r = info->callbacks->warning
569 (info, msg, name, input_bfd, input_section, rel->r_offset);
579 #define ELF_ARCH bfd_arch_fr30
580 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
581 #define ELF_MAXPAGESIZE 0x1000
583 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
584 #define TARGET_BIG_NAME "elf32-fr30"
586 #define elf_info_to_howto_rel NULL
587 #define elf_info_to_howto fr30_info_to_howto_rela
588 #define elf_backend_relocate_section fr30_elf_relocate_section
590 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
592 #include "elf32-target.h"