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 **));
30 static reloc_howto_type fr30_elf_howto_table [] =
32 /* This reloc does nothing. */
33 HOWTO (R_FR30_NONE, /* type */
35 2, /* size (0 = byte, 1 = short, 2 = long) */
37 false, /* pc_relative */
39 complain_overflow_bitfield, /* complain_on_overflow */
40 bfd_elf_generic_reloc, /* special_function */
41 "R_FR30_NONE", /* name */
42 false, /* partial_inplace */
45 false), /* pcrel_offset */
47 /* An 8 bit absolute relocation. */
48 HOWTO (R_FR30_8, /* type */
50 1, /* size (0 = byte, 1 = short, 2 = long) */
52 false, /* pc_relative */
54 complain_overflow_bitfield, /* complain_on_overflow */
55 bfd_elf_generic_reloc, /* special_function */
56 "R_FR30_8", /* name */
57 true, /* partial_inplace */
58 0x0ff0, /* src_mask */
59 0x0ff0, /* dst_mask */
60 false), /* pcrel_offset */
62 /* A 20 bit absolute relocation. */
63 HOWTO (R_FR30_20, /* type */
65 2, /* size (0 = byte, 1 = short, 2 = long) */
67 false, /* pc_relative */
69 complain_overflow_bitfield, /* complain_on_overflow */
70 fr30_elf_i20_reloc, /* special_function */
71 "R_FR30_20", /* name */
72 true, /* partial_inplace */
73 0x00f0ffff, /* src_mask */
74 0x00f0ffff, /* dst_mask */
75 false), /* pcrel_offset */
77 /* A 32 bit absolute relocation. */
78 HOWTO (R_FR30_32, /* type */
80 2, /* size (0 = byte, 1 = short, 2 = long) */
82 false, /* pc_relative */
84 complain_overflow_bitfield, /* complain_on_overflow */
85 bfd_elf_generic_reloc, /* special_function */
86 "R_FR30_32", /* name */
87 true, /* partial_inplace */
88 0xffffffff, /* src_mask */
89 0xffffffff, /* dst_mask */
90 false), /* pcrel_offset */
92 /* A 6 bit absolute relocation. */
93 HOWTO (R_FR30_6_IN_4, /* type */
95 1, /* size (0 = byte, 1 = short, 2 = long) */
97 false, /* pc_relative */
99 complain_overflow_unsigned, /* complain_on_overflow */
100 bfd_elf_generic_reloc, /* special_function */
101 "R_FR30_6_IN_4", /* name */
102 true, /* partial_inplace */
103 0x00f0, /* src_mask */
104 0x00f0, /* dst_mask */
105 false), /* pcrel_offset */
107 /* An 8 bit absolute relocation. */
108 HOWTO (R_FR30_8_IN_8, /* type */
110 1, /* size (0 = byte, 1 = short, 2 = long) */
112 false, /* pc_relative */
114 complain_overflow_signed, /* complain_on_overflow */
115 bfd_elf_generic_reloc,/* special_function */
116 "R_FR30_8_IN_8", /* name */
117 true, /* partial_inplace */
118 0x0ff0, /* src_mask */
119 0x0ff0, /* dst_mask */
120 false), /* pcrel_offset */
122 /* A 9 bit absolute relocation. */
123 HOWTO (R_FR30_9_IN_8, /* type */
125 1, /* size (0 = byte, 1 = short, 2 = long) */
127 false, /* pc_relative */
129 complain_overflow_signed, /* complain_on_overflow */
130 bfd_elf_generic_reloc,/* special_function */
131 "R_FR30_9_IN_8", /* name */
132 true, /* partial_inplace */
133 0x0ff0, /* src_mask */
134 0x0ff0, /* dst_mask */
135 false), /* pcrel_offset */
137 /* A 10 bit absolute relocation. */
138 HOWTO (R_FR30_10_IN_8, /* type */
140 1, /* size (0 = byte, 1 = short, 2 = long) */
142 false, /* pc_relative */
144 complain_overflow_signed, /* complain_on_overflow */
145 bfd_elf_generic_reloc,/* special_function */
146 "R_FR30_10_IN_8", /* name */
147 true, /* partial_inplace */
148 0x0ff0, /* src_mask */
149 0x0ff0, /* dst_mask */
150 false), /* pcrel_offset */
152 /* A PC relative 9 bit relocation, right shifted by 1. */
153 HOWTO (R_FR30_9_PCREL, /* type */
155 1, /* size (0 = byte, 1 = short, 2 = long) */
157 true, /* pc_relative */
159 complain_overflow_signed, /* complain_on_overflow */
160 bfd_elf_generic_reloc, /* special_function */
161 "R_FR30_9_PCREL", /* name */
162 false, /* partial_inplace */
163 0x00ff, /* src_mask */
164 0x00ff, /* dst_mask */
165 true), /* pcrel_offset */
167 /* A PC relative 12 bit relocation, right shifted by 1. */
168 HOWTO (R_FR30_12_PCREL, /* type */
170 1, /* size (0 = byte, 1 = short, 2 = long) */
172 true, /* pc_relative */
174 complain_overflow_signed, /* complain_on_overflow */
175 bfd_elf_generic_reloc, /* special_function */
176 "R_FR30_12_PCREL", /* name */
177 false, /* partial_inplace */
178 0x07ff, /* src_mask */
179 0x07ff, /* dst_mask */
180 true), /* pcrel_offset */
183 /* Utility to actually perform an R_FR30_20 reloc. */
185 static bfd_reloc_status_type
186 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
187 input_section, output_bfd, error_message)
189 arelent * reloc_entry;
192 asection * input_section;
194 char ** error_message;
199 /* This part is from bfd_elf_generic_reloc. */
200 if (output_bfd != (bfd *) NULL
201 && (symbol->flags & BSF_SECTION_SYM) == 0
202 && (! reloc_entry->howto->partial_inplace
203 || reloc_entry->addend == 0))
205 reloc_entry->address += input_section->output_offset;
209 if (output_bfd != NULL)
210 /* FIXME: See bfd_perform_relocation. Is this right? */
211 return bfd_reloc_continue;
215 + symbol->section->output_section->vma
216 + symbol->section->output_offset
217 + reloc_entry->addend;
219 if (relocation > ((1U << 20) - 1))
220 return bfd_reloc_overflow;
222 x = bfd_get_32 (abfd, data + reloc_entry->address);
223 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
224 bfd_put_32 (abfd, x, data + reloc_entry->address);
230 /* Map BFD reloc types to FR30 ELF reloc types. */
232 struct fr30_reloc_map
234 unsigned char bfd_reloc_val;
235 unsigned char elf_reloc_val;
238 static const struct fr30_reloc_map fr30_reloc_map [] =
240 { BFD_RELOC_NONE, R_FR30_NONE },
241 { BFD_RELOC_8, R_FR30_8 },
242 { BFD_RELOC_FR30_20, R_FR30_20 },
243 { BFD_RELOC_32, R_FR30_32 },
244 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
245 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
246 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
247 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
248 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
249 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
252 static reloc_howto_type *
253 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
255 bfd_reloc_code_real_type code;
259 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
262 if (fr30_reloc_map [i].bfd_reloc_val == code)
263 return & fr30_elf_howto_table [fr30_reloc_map[i].elf_reloc_val];
269 /* Set the howto pointer for an FR30 ELF reloc. */
272 fr30_info_to_howto_rel (abfd, cache_ptr, dst)
275 Elf32_Internal_Rela * dst;
279 r_type = ELF32_R_TYPE (dst->r_info);
280 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
281 cache_ptr->howto = & fr30_elf_howto_table [r_type];
284 /* Relocate an FR30 ELF section.
285 There is some attempt to make this function usable for many architectures,
286 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
287 if only to serve as a learning tool.
289 The RELOCATE_SECTION function is called by the new ELF backend linker
290 to handle the relocations for a section.
292 The relocs are always passed as Rela structures; if the section
293 actually uses Rel structures, the r_addend field will always be
296 This function is responsible for adjusting the section contents as
297 necessary, and (if using Rela relocs and generating a relocateable
298 output file) adjusting the reloc addend as necessary.
300 This function does not have to worry about setting the reloc
301 address or the reloc symbol index.
303 LOCAL_SYMS is a pointer to the swapped in local symbols.
305 LOCAL_SECTIONS is an array giving the section in the input file
306 corresponding to the st_shndx field of each local symbol.
308 The global hash table entry for the global symbols can be found
309 via elf_sym_hashes (input_bfd).
311 When generating relocateable output, this function must handle
312 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
313 going to be the section symbol corresponding to the output
314 section, which means that the addend must be adjusted
318 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
319 contents, relocs, local_syms, local_sections)
321 struct bfd_link_info * info;
323 asection * input_section;
325 Elf_Internal_Rela * relocs;
326 Elf_Internal_Sym * local_syms;
327 asection ** local_sections;
329 Elf_Internal_Shdr * symtab_hdr;
330 struct elf_link_hash_entry ** sym_hashes;
331 Elf_Internal_Rela * rel;
332 Elf_Internal_Rela * relend;
334 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
335 sym_hashes = elf_sym_hashes (input_bfd);
336 relend = relocs + input_section->reloc_count;
338 for (rel = relocs; rel < relend; rel ++)
340 reloc_howto_type * howto;
341 unsigned long r_symndx;
342 Elf_Internal_Sym * sym;
344 struct elf_link_hash_entry * h;
346 bfd_reloc_status_type r;
349 r_symndx = ELF32_R_SYM (rel->r_info);
351 if (info->relocateable)
353 /* This is a relocateable link. We don't have to change
354 anything, unless the reloc is against a section symbol,
355 in which case we have to adjust according to where the
356 section symbol winds up in the output section. */
357 if (r_symndx < symtab_hdr->sh_info)
359 sym = local_syms + r_symndx;
361 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
363 sec = local_sections [r_symndx];
364 rel->r_addend += sec->output_offset + sym->st_value;
371 /* This is a final link. */
372 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
377 if (r_symndx < symtab_hdr->sh_info)
379 sym = local_syms + r_symndx;
380 sec = local_sections [r_symndx];
381 relocation = (sec->output_section->vma
385 name = bfd_elf_string_from_elf_section
386 (input_bfd, symtab_hdr->sh_link, sym->st_name);
387 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
389 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
390 sec->name, name, sym->st_name,
391 sec->output_section->vma, sec->output_offset,
392 sym->st_value, rel->r_addend);
397 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
399 while (h->root.type == bfd_link_hash_indirect
400 || h->root.type == bfd_link_hash_warning)
401 h = (struct elf_link_hash_entry *) h->root.u.i.link;
403 name = h->root.root.string;
405 if (h->root.type == bfd_link_hash_defined
406 || h->root.type == bfd_link_hash_defweak)
408 sec = h->root.u.def.section;
409 relocation = (h->root.u.def.value
410 + sec->output_section->vma
411 + sec->output_offset);
414 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
415 sec->name, name, h->root.u.def.value,
416 sec->output_section->vma, sec->output_offset, relocation);
419 else if (h->root.type == bfd_link_hash_undefweak)
422 fprintf (stderr, "undefined: sec: %s, name: %s\n",
429 if (! ((*info->callbacks->undefined_symbol)
430 (info, h->root.root.string, input_bfd,
431 input_section, rel->r_offset)))
434 fprintf (stderr, "unknown: name: %s\n", name);
440 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
441 contents, rel->r_offset,
442 relocation, rel->r_addend);
444 if (r != bfd_reloc_ok)
446 const char * msg = (const char *)0;
450 case bfd_reloc_overflow:
451 if (! ((*info->callbacks->reloc_overflow)
452 (info, name, howto->name, (bfd_vma) 0,
453 input_bfd, input_section, rel->r_offset)))
457 case bfd_reloc_undefined:
458 if (! ((*info->callbacks->undefined_symbol)
459 (info, name, input_bfd, input_section,
464 case bfd_reloc_outofrange:
465 msg = _("internal error: out of range error");
468 case bfd_reloc_notsupported:
469 msg = _("internal error: unsupported relocation error");
472 case bfd_reloc_dangerous:
473 msg = _("internal error: dangerous relocation");
476 case bfd_reloc_other:
477 msg = _("could not locate special linker symbol __gp");
480 case bfd_reloc_continue:
481 msg = _("could not locate special linker symbol __ep");
484 case (bfd_reloc_dangerous + 1):
485 msg = _("could not locate special linker symbol __ctbp");
489 msg = _("internal error: unknown error");
493 if (!((*info->callbacks->warning)
494 (info, msg, name, input_bfd, input_section,
505 #define ELF_ARCH bfd_arch_fr30
506 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
507 #define ELF_MAXPAGESIZE 0x1000
509 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
510 #define TARGET_BIG_NAME "elf32-fr30"
512 #define elf_info_to_howto 0
513 #define elf_info_to_howto_rel fr30_info_to_howto_rel
514 #define elf_backend_relocate_section fr30_elf_relocate_section
516 #include "elf32-target.h"