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 reloc_howto_type * fr30_reloc_type_lookup
30 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
31 static void fr30_info_to_howto_rela
32 PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
33 static boolean fr30_elf_relocate_section
34 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
36 static reloc_howto_type fr30_elf_howto_table [] =
38 /* This reloc does nothing. */
39 HOWTO (R_FR30_NONE, /* type */
41 2, /* size (0 = byte, 1 = short, 2 = long) */
43 false, /* pc_relative */
45 complain_overflow_bitfield, /* complain_on_overflow */
46 bfd_elf_generic_reloc, /* special_function */
47 "R_FR30_NONE", /* name */
48 false, /* partial_inplace */
51 false), /* pcrel_offset */
53 /* An 8 bit absolute relocation. */
54 HOWTO (R_FR30_8, /* type */
56 1, /* size (0 = byte, 1 = short, 2 = long) */
58 false, /* pc_relative */
60 complain_overflow_bitfield, /* complain_on_overflow */
61 bfd_elf_generic_reloc, /* special_function */
62 "R_FR30_8", /* name */
63 true, /* partial_inplace */
64 0x0ff0, /* src_mask */
65 0x0ff0, /* dst_mask */
66 false), /* pcrel_offset */
68 /* A 20 bit absolute relocation. */
69 HOWTO (R_FR30_20, /* type */
71 2, /* size (0 = byte, 1 = short, 2 = long) */
73 false, /* pc_relative */
75 complain_overflow_bitfield, /* complain_on_overflow */
76 fr30_elf_i20_reloc, /* special_function */
77 "R_FR30_20", /* name */
78 true, /* partial_inplace */
79 0x00f0ffff, /* src_mask */
80 0x00f0ffff, /* dst_mask */
81 false), /* pcrel_offset */
83 /* A 32 bit absolute relocation. */
84 HOWTO (R_FR30_32, /* type */
86 2, /* size (0 = byte, 1 = short, 2 = long) */
88 false, /* pc_relative */
90 complain_overflow_bitfield, /* complain_on_overflow */
91 bfd_elf_generic_reloc, /* special_function */
92 "R_FR30_32", /* name */
93 true, /* partial_inplace */
94 0xffffffff, /* src_mask */
95 0xffffffff, /* dst_mask */
96 false), /* pcrel_offset */
98 /* A 6 bit absolute relocation. */
99 HOWTO (R_FR30_6_IN_4, /* type */
101 1, /* size (0 = byte, 1 = short, 2 = long) */
103 false, /* pc_relative */
105 complain_overflow_unsigned, /* complain_on_overflow */
106 bfd_elf_generic_reloc, /* special_function */
107 "R_FR30_6_IN_4", /* name */
108 true, /* partial_inplace */
109 0x00f0, /* src_mask */
110 0x00f0, /* dst_mask */
111 false), /* pcrel_offset */
113 /* An 8 bit absolute relocation. */
114 HOWTO (R_FR30_8_IN_8, /* type */
116 1, /* size (0 = byte, 1 = short, 2 = long) */
118 false, /* pc_relative */
120 complain_overflow_signed, /* complain_on_overflow */
121 bfd_elf_generic_reloc,/* special_function */
122 "R_FR30_8_IN_8", /* name */
123 true, /* partial_inplace */
124 0x0ff0, /* src_mask */
125 0x0ff0, /* dst_mask */
126 false), /* pcrel_offset */
128 /* A 9 bit absolute relocation. */
129 HOWTO (R_FR30_9_IN_8, /* type */
131 1, /* size (0 = byte, 1 = short, 2 = long) */
133 false, /* pc_relative */
135 complain_overflow_signed, /* complain_on_overflow */
136 bfd_elf_generic_reloc,/* special_function */
137 "R_FR30_9_IN_8", /* name */
138 true, /* partial_inplace */
139 0x0ff0, /* src_mask */
140 0x0ff0, /* dst_mask */
141 false), /* pcrel_offset */
143 /* A 10 bit absolute relocation. */
144 HOWTO (R_FR30_10_IN_8, /* type */
146 1, /* size (0 = byte, 1 = short, 2 = long) */
148 false, /* pc_relative */
150 complain_overflow_signed, /* complain_on_overflow */
151 bfd_elf_generic_reloc,/* special_function */
152 "R_FR30_10_IN_8", /* name */
153 true, /* partial_inplace */
154 0x0ff0, /* src_mask */
155 0x0ff0, /* dst_mask */
156 false), /* pcrel_offset */
158 /* A PC relative 9 bit relocation, right shifted by 1. */
159 HOWTO (R_FR30_9_PCREL, /* type */
161 1, /* size (0 = byte, 1 = short, 2 = long) */
163 true, /* pc_relative */
165 complain_overflow_signed, /* complain_on_overflow */
166 bfd_elf_generic_reloc, /* special_function */
167 "R_FR30_9_PCREL", /* name */
168 false, /* partial_inplace */
169 0x00ff, /* src_mask */
170 0x00ff, /* dst_mask */
171 true), /* pcrel_offset */
173 /* A PC relative 12 bit relocation, right shifted by 1. */
174 HOWTO (R_FR30_12_PCREL, /* type */
176 1, /* size (0 = byte, 1 = short, 2 = long) */
178 true, /* pc_relative */
180 complain_overflow_signed, /* complain_on_overflow */
181 bfd_elf_generic_reloc, /* special_function */
182 "R_FR30_12_PCREL", /* name */
183 false, /* partial_inplace */
184 0x07ff, /* src_mask */
185 0x07ff, /* dst_mask */
186 true), /* pcrel_offset */
189 /* Utility to actually perform an R_FR30_20 reloc. */
191 static bfd_reloc_status_type
192 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
193 input_section, output_bfd, error_message)
195 arelent * reloc_entry;
198 asection * input_section;
200 char ** error_message;
205 /* This part is from bfd_elf_generic_reloc. */
206 if (output_bfd != (bfd *) NULL
207 && (symbol->flags & BSF_SECTION_SYM) == 0
208 && (! reloc_entry->howto->partial_inplace
209 || reloc_entry->addend == 0))
211 reloc_entry->address += input_section->output_offset;
215 if (output_bfd != NULL)
216 /* FIXME: See bfd_perform_relocation. Is this right? */
217 return bfd_reloc_continue;
221 + symbol->section->output_section->vma
222 + symbol->section->output_offset
223 + reloc_entry->addend;
225 if (relocation > ((1U << 20) - 1))
226 return bfd_reloc_overflow;
228 x = bfd_get_32 (abfd, data + reloc_entry->address);
229 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
230 bfd_put_32 (abfd, x, data + reloc_entry->address);
236 /* Map BFD reloc types to FR30 ELF reloc types. */
238 struct fr30_reloc_map
240 unsigned int bfd_reloc_val;
241 unsigned int fr30_reloc_val;
244 static const struct fr30_reloc_map fr30_reloc_map [] =
246 { BFD_RELOC_NONE, R_FR30_NONE },
247 { BFD_RELOC_8, R_FR30_8 },
248 { BFD_RELOC_FR30_20, R_FR30_20 },
249 { BFD_RELOC_32, R_FR30_32 },
250 { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
251 { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
252 { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
253 { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
254 { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
255 { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
258 static reloc_howto_type *
259 fr30_reloc_type_lookup (abfd, code)
261 bfd_reloc_code_real_type code;
265 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
267 if (fr30_reloc_map [i].bfd_reloc_val == code)
268 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
273 /* Set the howto pointer for an FR30 ELF reloc. */
276 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
279 Elf32_Internal_Rela * dst;
283 r_type = ELF32_R_TYPE (dst->r_info);
284 BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
285 cache_ptr->howto = & fr30_elf_howto_table [r_type];
288 /* Relocate an FR30 ELF section.
289 There is some attempt to make this function usable for many architectures,
290 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
291 if only to serve as a learning tool.
293 The RELOCATE_SECTION function is called by the new ELF backend linker
294 to handle the relocations for a section.
296 The relocs are always passed as Rela structures; if the section
297 actually uses Rel structures, the r_addend field will always be
300 This function is responsible for adjusting the section contents as
301 necessary, and (if using Rela relocs and generating a relocateable
302 output file) adjusting the reloc addend as necessary.
304 This function does not have to worry about setting the reloc
305 address or the reloc symbol index.
307 LOCAL_SYMS is a pointer to the swapped in local symbols.
309 LOCAL_SECTIONS is an array giving the section in the input file
310 corresponding to the st_shndx field of each local symbol.
312 The global hash table entry for the global symbols can be found
313 via elf_sym_hashes (input_bfd).
315 When generating relocateable output, this function must handle
316 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
317 going to be the section symbol corresponding to the output
318 section, which means that the addend must be adjusted
322 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
323 contents, relocs, local_syms, local_sections)
325 struct bfd_link_info * info;
327 asection * input_section;
329 Elf_Internal_Rela * relocs;
330 Elf_Internal_Sym * local_syms;
331 asection ** local_sections;
333 Elf_Internal_Shdr * symtab_hdr;
334 struct elf_link_hash_entry ** sym_hashes;
335 Elf_Internal_Rela * rel;
336 Elf_Internal_Rela * relend;
338 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
339 sym_hashes = elf_sym_hashes (input_bfd);
340 relend = relocs + input_section->reloc_count;
342 for (rel = relocs; rel < relend; rel ++)
344 reloc_howto_type * howto;
345 unsigned long r_symndx;
346 Elf_Internal_Sym * sym;
348 struct elf_link_hash_entry * h;
350 bfd_reloc_status_type r;
353 r_symndx = ELF32_R_SYM (rel->r_info);
355 if (info->relocateable)
357 /* This is a relocateable link. We don't have to change
358 anything, unless the reloc is against a section symbol,
359 in which case we have to adjust according to where the
360 section symbol winds up in the output section. */
361 if (r_symndx < symtab_hdr->sh_info)
363 sym = local_syms + r_symndx;
365 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
367 sec = local_sections [r_symndx];
368 rel->r_addend += sec->output_offset + sym->st_value;
375 /* This is a final link. */
376 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
381 if (r_symndx < symtab_hdr->sh_info)
383 sym = local_syms + r_symndx;
384 sec = local_sections [r_symndx];
385 relocation = (sec->output_section->vma
389 name = bfd_elf_string_from_elf_section
390 (input_bfd, symtab_hdr->sh_link, sym->st_name);
391 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
393 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
394 sec->name, name, sym->st_name,
395 sec->output_section->vma, sec->output_offset,
396 sym->st_value, rel->r_addend);
401 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
403 while (h->root.type == bfd_link_hash_indirect
404 || h->root.type == bfd_link_hash_warning)
405 h = (struct elf_link_hash_entry *) h->root.u.i.link;
407 name = h->root.root.string;
409 if (h->root.type == bfd_link_hash_defined
410 || h->root.type == bfd_link_hash_defweak)
412 sec = h->root.u.def.section;
413 relocation = (h->root.u.def.value
414 + sec->output_section->vma
415 + sec->output_offset);
418 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
419 sec->name, name, h->root.u.def.value,
420 sec->output_section->vma, sec->output_offset, relocation);
423 else if (h->root.type == bfd_link_hash_undefweak)
426 fprintf (stderr, "undefined: sec: %s, name: %s\n",
433 if (! ((*info->callbacks->undefined_symbol)
434 (info, h->root.root.string, input_bfd,
435 input_section, rel->r_offset)))
438 fprintf (stderr, "unknown: name: %s\n", name);
444 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
445 contents, rel->r_offset,
446 relocation, rel->r_addend);
448 if (r != bfd_reloc_ok)
450 const char * msg = (const char *)0;
454 case bfd_reloc_overflow:
455 if (! ((*info->callbacks->reloc_overflow)
456 (info, name, howto->name, (bfd_vma) 0,
457 input_bfd, input_section, rel->r_offset)))
461 case bfd_reloc_undefined:
462 if (! ((*info->callbacks->undefined_symbol)
463 (info, name, input_bfd, input_section,
468 case bfd_reloc_outofrange:
469 msg = _("internal error: out of range error");
472 case bfd_reloc_notsupported:
473 msg = _("internal error: unsupported relocation error");
476 case bfd_reloc_dangerous:
477 msg = _("internal error: dangerous relocation");
480 case bfd_reloc_other:
481 msg = _("could not locate special linker symbol __gp");
484 case bfd_reloc_continue:
485 msg = _("could not locate special linker symbol __ep");
488 case (bfd_reloc_dangerous + 1):
489 msg = _("could not locate special linker symbol __ctbp");
493 msg = _("internal error: unknown error");
497 if (!((*info->callbacks->warning)
498 (info, msg, name, input_bfd, input_section,
509 #define ELF_ARCH bfd_arch_fr30
510 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
511 #define ELF_MAXPAGESIZE 0x1000
513 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
514 #define TARGET_BIG_NAME "elf32-fr30"
516 #define elf_info_to_howto_rel NULL
517 #define elf_info_to_howto fr30_info_to_howto_rela
518 #define elf_backend_relocate_section fr30_elf_relocate_section
520 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
522 #include "elf32-target.h"