b50edfeb14db2db4e10b56d55b516a4665f848d1
[binutils-gdb.git] / bfd / elf32-fr30.c
1 /* FR30-specific support for 32-bit ELF.
2 Copyright (C) 1998 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
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.
10
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.
15
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. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/fr30.h"
25
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));
39
40 static reloc_howto_type fr30_elf_howto_table [] =
41 {
42 /* This reloc does nothing. */
43 HOWTO (R_FR30_NONE, /* type */
44 0, /* rightshift */
45 2, /* size (0 = byte, 1 = short, 2 = long) */
46 32, /* bitsize */
47 false, /* pc_relative */
48 0, /* bitpos */
49 complain_overflow_bitfield, /* complain_on_overflow */
50 bfd_elf_generic_reloc, /* special_function */
51 "R_FR30_NONE", /* name */
52 false, /* partial_inplace */
53 0, /* src_mask */
54 0, /* dst_mask */
55 false), /* pcrel_offset */
56
57 /* An 8 bit absolute relocation. */
58 HOWTO (R_FR30_8, /* type */
59 0, /* rightshift */
60 1, /* size (0 = byte, 1 = short, 2 = long) */
61 8, /* bitsize */
62 false, /* pc_relative */
63 4, /* bitpos */
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 */
71
72 /* A 20 bit absolute relocation. */
73 HOWTO (R_FR30_20, /* type */
74 0, /* rightshift */
75 2, /* size (0 = byte, 1 = short, 2 = long) */
76 20, /* bitsize */
77 false, /* pc_relative */
78 0, /* bitpos */
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 */
86
87 /* A 32 bit absolute relocation. */
88 HOWTO (R_FR30_32, /* type */
89 0, /* rightshift */
90 2, /* size (0 = byte, 1 = short, 2 = long) */
91 32, /* bitsize */
92 false, /* pc_relative */
93 0, /* bitpos */
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 */
101
102 /* A 6 bit absolute relocation. */
103 HOWTO (R_FR30_6_IN_4, /* type */
104 2, /* rightshift */
105 1, /* size (0 = byte, 1 = short, 2 = long) */
106 6, /* bitsize */
107 false, /* pc_relative */
108 4, /* bitpos */
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 */
116
117 /* An 8 bit absolute relocation. */
118 HOWTO (R_FR30_8_IN_8, /* type */
119 0, /* rightshift */
120 1, /* size (0 = byte, 1 = short, 2 = long) */
121 8, /* bitsize */
122 false, /* pc_relative */
123 4, /* bitpos */
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 */
131
132 /* A 9 bit absolute relocation. */
133 HOWTO (R_FR30_9_IN_8, /* type */
134 1, /* rightshift */
135 1, /* size (0 = byte, 1 = short, 2 = long) */
136 9, /* bitsize */
137 false, /* pc_relative */
138 4, /* bitpos */
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 */
146
147 /* A 10 bit absolute relocation. */
148 HOWTO (R_FR30_10_IN_8, /* type */
149 2, /* rightshift */
150 1, /* size (0 = byte, 1 = short, 2 = long) */
151 10, /* bitsize */
152 false, /* pc_relative */
153 4, /* bitpos */
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 */
161
162 /* A PC relative 9 bit relocation, right shifted by 1. */
163 HOWTO (R_FR30_9_PCREL, /* type */
164 1, /* rightshift */
165 1, /* size (0 = byte, 1 = short, 2 = long) */
166 9, /* bitsize */
167 true, /* pc_relative */
168 0, /* bitpos */
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 */
176
177 /* A PC relative 12 bit relocation, right shifted by 1. */
178 HOWTO (R_FR30_12_PCREL, /* type */
179 1, /* rightshift */
180 1, /* size (0 = byte, 1 = short, 2 = long) */
181 12, /* bitsize */
182 true, /* pc_relative */
183 0, /* bitpos */
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 */
191 };
192 \f
193 /* Utility to actually perform an R_FR30_20 reloc. */
194
195 static bfd_reloc_status_type
196 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
197 input_section, output_bfd, error_message)
198 bfd * abfd;
199 arelent * reloc_entry;
200 asymbol * symbol;
201 PTR data;
202 asection * input_section;
203 bfd * output_bfd;
204 char ** error_message;
205 {
206 bfd_vma relocation;
207 unsigned long x;
208
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))
214 {
215 reloc_entry->address += input_section->output_offset;
216 return bfd_reloc_ok;
217 }
218
219 if (output_bfd != NULL)
220 /* FIXME: See bfd_perform_relocation. Is this right? */
221 return bfd_reloc_ok;
222
223 relocation =
224 symbol->value
225 + symbol->section->output_section->vma
226 + symbol->section->output_offset
227 + reloc_entry->addend;
228
229 if (relocation > ((1U << 20) - 1))
230 return bfd_reloc_overflow;
231
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);
235
236 return bfd_reloc_ok;
237 }
238
239 \f
240 /* Utility to actually perform a R_FR30_32 reloc. */
241
242 static bfd_reloc_status_type
243 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
244 input_section, output_bfd, error_message)
245 bfd * abfd;
246 arelent * reloc_entry;
247 asymbol * symbol;
248 PTR data;
249 asection * input_section;
250 bfd * output_bfd;
251 char ** error_message;
252 {
253 bfd_vma relocation;
254
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))
260 {
261 reloc_entry->address += input_section->output_offset;
262 return bfd_reloc_ok;
263 }
264
265 if (output_bfd != NULL)
266 /* FIXME: See bfd_perform_relocation. Is this right? */
267 return bfd_reloc_ok;
268
269 relocation =
270 symbol->value
271 + symbol->section->output_section->vma
272 + symbol->section->output_offset
273 + reloc_entry->addend;
274
275 bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
276
277 return bfd_reloc_ok;
278 }
279
280 \f
281 /* Map BFD reloc types to FR30 ELF reloc types. */
282
283 struct fr30_reloc_map
284 {
285 unsigned int bfd_reloc_val;
286 unsigned int fr30_reloc_val;
287 };
288
289 static const struct fr30_reloc_map fr30_reloc_map [] =
290 {
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 },
301 };
302
303 static reloc_howto_type *
304 fr30_reloc_type_lookup (abfd, code)
305 bfd * abfd;
306 bfd_reloc_code_real_type code;
307 {
308 unsigned int i;
309
310 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
311 --i;)
312 if (fr30_reloc_map [i].bfd_reloc_val == code)
313 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
314
315 return NULL;
316 }
317
318 /* Set the howto pointer for an FR30 ELF reloc. */
319
320 static void
321 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
322 bfd * abfd;
323 arelent * cache_ptr;
324 Elf32_Internal_Rela * dst;
325 {
326 unsigned int r_type;
327
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];
331 }
332 \f
333 /* Perform a single relocation. By default we use the standard BFD
334 routines, but a few relocs, we have to do them ourselves. */
335
336 static bfd_reloc_status_type
337 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
338 reloc_howto_type * howto;
339 bfd * input_bfd;
340 asection * input_section;
341 bfd_byte * contents;
342 Elf_Internal_Rela * rel;
343 bfd_vma relocation;
344 {
345 bfd_reloc_status_type r = bfd_reloc_ok;
346 bfd_vma x;
347
348 switch (howto->type)
349 {
350 case R_FR30_20:
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);
356 break;
357
358 case R_FR30_32:
359 contents += rel->r_offset + 2;
360 relocation += rel->r_addend;
361 bfd_put_32 (input_bfd, relocation, contents);
362 break;
363
364 default:
365 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
366 contents, rel->r_offset,
367 relocation, rel->r_addend);
368 }
369
370 return r;
371 }
372
373 \f
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.
378
379 The RELOCATE_SECTION function is called by the new ELF backend linker
380 to handle the relocations for a section.
381
382 The relocs are always passed as Rela structures; if the section
383 actually uses Rel structures, the r_addend field will always be
384 zero.
385
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.
389
390 This function does not have to worry about setting the reloc
391 address or the reloc symbol index.
392
393 LOCAL_SYMS is a pointer to the swapped in local symbols.
394
395 LOCAL_SECTIONS is an array giving the section in the input file
396 corresponding to the st_shndx field of each local symbol.
397
398 The global hash table entry for the global symbols can be found
399 via elf_sym_hashes (input_bfd).
400
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
405 accordingly. */
406
407 static boolean
408 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
409 contents, relocs, local_syms, local_sections)
410 bfd * output_bfd;
411 struct bfd_link_info * info;
412 bfd * input_bfd;
413 asection * input_section;
414 bfd_byte * contents;
415 Elf_Internal_Rela * relocs;
416 Elf_Internal_Sym * local_syms;
417 asection ** local_sections;
418 {
419 Elf_Internal_Shdr * symtab_hdr;
420 struct elf_link_hash_entry ** sym_hashes;
421 Elf_Internal_Rela * rel;
422 Elf_Internal_Rela * relend;
423
424 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
425 sym_hashes = elf_sym_hashes (input_bfd);
426 relend = relocs + input_section->reloc_count;
427
428 for (rel = relocs; rel < relend; rel ++)
429 {
430 reloc_howto_type * howto;
431 unsigned long r_symndx;
432 Elf_Internal_Sym * sym;
433 asection * sec;
434 struct elf_link_hash_entry * h;
435 bfd_vma relocation;
436 bfd_reloc_status_type r;
437 const char * name = NULL;
438
439 r_symndx = ELF32_R_SYM (rel->r_info);
440
441 if (info->relocateable)
442 {
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)
448 {
449 sym = local_syms + r_symndx;
450
451 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
452 {
453 sec = local_sections [r_symndx];
454 rel->r_addend += sec->output_offset + sym->st_value;
455 }
456 }
457
458 continue;
459 }
460
461 /* This is a final link. */
462 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
463 h = NULL;
464 sym = NULL;
465 sec = NULL;
466
467 if (r_symndx < symtab_hdr->sh_info)
468 {
469 sym = local_syms + r_symndx;
470 sec = local_sections [r_symndx];
471 relocation = (sec->output_section->vma
472 + sec->output_offset
473 + sym->st_value);
474
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;
478 #if 0
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);
483 #endif
484 }
485 else
486 {
487 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
488
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;
492
493 name = h->root.root.string;
494
495 if (h->root.type == bfd_link_hash_defined
496 || h->root.type == bfd_link_hash_defweak)
497 {
498 sec = h->root.u.def.section;
499 relocation = (h->root.u.def.value
500 + sec->output_section->vma
501 + sec->output_offset);
502 #if 0
503 fprintf (stderr,
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);
507 #endif
508 }
509 else if (h->root.type == bfd_link_hash_undefweak)
510 {
511 #if 0
512 fprintf (stderr, "undefined: sec: %s, name: %s\n",
513 sec->name, name);
514 #endif
515 relocation = 0;
516 }
517 else
518 {
519 if (! ((*info->callbacks->undefined_symbol)
520 (info, h->root.root.string, input_bfd,
521 input_section, rel->r_offset)))
522 return false;
523 #if 0
524 fprintf (stderr, "unknown: name: %s\n", name);
525 #endif
526 relocation = 0;
527 }
528 }
529
530 r = fr30_final_link_relocate (howto, input_bfd, input_section,
531 contents, rel, relocation);
532
533 if (r != bfd_reloc_ok)
534 {
535 const char * msg = (const char *) NULL;
536
537 switch (r)
538 {
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);
543 break;
544
545 case bfd_reloc_undefined:
546 r = info->callbacks->undefined_symbol
547 (info, name, input_bfd, input_section, rel->r_offset);
548 break;
549
550 case bfd_reloc_outofrange:
551 msg = _("internal error: out of range error");
552 break;
553
554 case bfd_reloc_notsupported:
555 msg = _("internal error: unsupported relocation error");
556 break;
557
558 case bfd_reloc_dangerous:
559 msg = _("internal error: dangerous relocation");
560 break;
561
562 default:
563 msg = _("internal error: unknown error");
564 break;
565 }
566
567 if (msg)
568 r = info->callbacks->warning
569 (info, msg, name, input_bfd, input_section, rel->r_offset);
570
571 if (! r)
572 return false;
573 }
574 }
575
576 return true;
577 }
578 \f
579 #define ELF_ARCH bfd_arch_fr30
580 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
581 #define ELF_MAXPAGESIZE 0x1000
582
583 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
584 #define TARGET_BIG_NAME "elf32-fr30"
585
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
589
590 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
591
592 #include "elf32-target.h"