Fix typo in orevious delta
[deliverable/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 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 */
101
102 /* A 32 bit into 48 bits absolute relocation. */
103 HOWTO (R_FR30_48, /* type */
104 0, /* rightshift */
105 2, /* size (0 = byte, 1 = short, 2 = long) */
106 32, /* bitsize */
107 false, /* pc_relative */
108 0, /* bitpos */
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 */
116
117 /* A 6 bit absolute relocation. */
118 HOWTO (R_FR30_6_IN_4, /* type */
119 2, /* rightshift */
120 1, /* size (0 = byte, 1 = short, 2 = long) */
121 6, /* bitsize */
122 false, /* pc_relative */
123 4, /* bitpos */
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 */
131
132 /* An 8 bit absolute relocation. */
133 HOWTO (R_FR30_8_IN_8, /* type */
134 0, /* rightshift */
135 1, /* size (0 = byte, 1 = short, 2 = long) */
136 8, /* 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_8_IN_8", /* name */
142 true, /* partial_inplace */
143 0x0ff0, /* src_mask */
144 0x0ff0, /* dst_mask */
145 false), /* pcrel_offset */
146
147 /* A 9 bit absolute relocation. */
148 HOWTO (R_FR30_9_IN_8, /* type */
149 1, /* rightshift */
150 1, /* size (0 = byte, 1 = short, 2 = long) */
151 9, /* 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_9_IN_8", /* name */
157 true, /* partial_inplace */
158 0x0ff0, /* src_mask */
159 0x0ff0, /* dst_mask */
160 false), /* pcrel_offset */
161
162 /* A 10 bit absolute relocation. */
163 HOWTO (R_FR30_10_IN_8, /* type */
164 2, /* rightshift */
165 1, /* size (0 = byte, 1 = short, 2 = long) */
166 10, /* bitsize */
167 false, /* pc_relative */
168 4, /* bitpos */
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 */
176
177 /* A PC relative 9 bit relocation, right shifted by 1. */
178 HOWTO (R_FR30_9_PCREL, /* type */
179 1, /* rightshift */
180 1, /* size (0 = byte, 1 = short, 2 = long) */
181 9, /* 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_9_PCREL", /* name */
187 false, /* partial_inplace */
188 0x00ff, /* src_mask */
189 0x00ff, /* dst_mask */
190 false), /* pcrel_offset */
191
192 /* A PC relative 12 bit relocation, right shifted by 1. */
193 HOWTO (R_FR30_12_PCREL, /* type */
194 1, /* rightshift */
195 1, /* size (0 = byte, 1 = short, 2 = long) */
196 12, /* bitsize */
197 true, /* pc_relative */
198 0, /* bitpos */
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 */
206 };
207 \f
208 /* Utility to actually perform an R_FR30_20 reloc. */
209
210 static bfd_reloc_status_type
211 fr30_elf_i20_reloc (abfd, reloc_entry, symbol, data,
212 input_section, output_bfd, error_message)
213 bfd * abfd;
214 arelent * reloc_entry;
215 asymbol * symbol;
216 PTR data;
217 asection * input_section;
218 bfd * output_bfd;
219 char ** error_message;
220 {
221 bfd_vma relocation;
222 unsigned long x;
223
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))
229 {
230 reloc_entry->address += input_section->output_offset;
231 return bfd_reloc_ok;
232 }
233
234 if (output_bfd != NULL)
235 /* FIXME: See bfd_perform_relocation. Is this right? */
236 return bfd_reloc_ok;
237
238 relocation =
239 symbol->value
240 + symbol->section->output_section->vma
241 + symbol->section->output_offset
242 + reloc_entry->addend;
243
244 if (relocation > ((1U << 20) - 1))
245 return bfd_reloc_overflow;
246
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);
250
251 return bfd_reloc_ok;
252 }
253
254 \f
255 /* Utility to actually perform a R_FR30_48 reloc. */
256
257 static bfd_reloc_status_type
258 fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
259 input_section, output_bfd, error_message)
260 bfd * abfd;
261 arelent * reloc_entry;
262 asymbol * symbol;
263 PTR data;
264 asection * input_section;
265 bfd * output_bfd;
266 char ** error_message;
267 {
268 bfd_vma relocation;
269
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))
275 {
276 reloc_entry->address += input_section->output_offset;
277 return bfd_reloc_ok;
278 }
279
280 if (output_bfd != NULL)
281 /* FIXME: See bfd_perform_relocation. Is this right? */
282 return bfd_reloc_ok;
283
284 relocation =
285 symbol->value
286 + symbol->section->output_section->vma
287 + symbol->section->output_offset
288 + reloc_entry->addend;
289
290 bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
291
292 return bfd_reloc_ok;
293 }
294 \f
295 /* Map BFD reloc types to FR30 ELF reloc types. */
296
297 struct fr30_reloc_map
298 {
299 unsigned int bfd_reloc_val;
300 unsigned int fr30_reloc_val;
301 };
302
303 static const struct fr30_reloc_map fr30_reloc_map [] =
304 {
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 },
316 };
317
318 static reloc_howto_type *
319 fr30_reloc_type_lookup (abfd, code)
320 bfd * abfd;
321 bfd_reloc_code_real_type code;
322 {
323 unsigned int i;
324
325 for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
326 --i;)
327 if (fr30_reloc_map [i].bfd_reloc_val == code)
328 return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
329
330 return NULL;
331 }
332
333 /* Set the howto pointer for an FR30 ELF reloc. */
334
335 static void
336 fr30_info_to_howto_rela (abfd, cache_ptr, dst)
337 bfd * abfd;
338 arelent * cache_ptr;
339 Elf32_Internal_Rela * dst;
340 {
341 unsigned int r_type;
342
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];
346 }
347 \f
348 /* Perform a single relocation. By default we use the standard BFD
349 routines, but a few relocs, we have to do them ourselves. */
350
351 static bfd_reloc_status_type
352 fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
353 reloc_howto_type * howto;
354 bfd * input_bfd;
355 asection * input_section;
356 bfd_byte * contents;
357 Elf_Internal_Rela * rel;
358 bfd_vma relocation;
359 {
360 bfd_reloc_status_type r = bfd_reloc_ok;
361 bfd_vma x;
362
363 switch (howto->type)
364 {
365 case R_FR30_20:
366 contents += rel->r_offset;
367 relocation += rel->r_addend;
368
369 if (relocation > ((1 << 20) - 1))
370 return bfd_reloc_overflow;
371
372 x = bfd_get_32 (input_bfd, contents);
373 x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
374 bfd_put_32 (input_bfd, relocation, contents);
375 break;
376
377 case R_FR30_48:
378 contents += rel->r_offset + 2;
379 relocation += rel->r_addend;
380 bfd_put_32 (input_bfd, relocation, contents);
381 break;
382
383 case R_FR30_9_PCREL:
384 contents += rel->r_offset + 1;
385 relocation += rel->r_addend;
386 relocation -= (input_section->output_section->vma +
387 input_section->output_offset);
388
389 if (relocation & 1)
390 return bfd_reloc_outofrange;
391 if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
392 return bfd_reloc_overflow;
393
394 bfd_put_8 (input_bfd, relocation >> 1, contents);
395 break;
396
397 case R_FR30_12_PCREL:
398 contents += rel->r_offset;
399 relocation += rel->r_addend;
400 relocation -= (input_section->output_section->vma +
401 input_section->output_offset);
402
403 if (relocation & 1)
404 return bfd_reloc_outofrange;
405 if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
406 return bfd_reloc_overflow;
407
408 x = bfd_get_16 (input_bfd, contents);
409 x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
410 bfd_put_16 (input_bfd, x, contents);
411 break;
412
413 default:
414 fprintf (stderr, " type: %d offset: %x, before: %x\n",
415 howto->type, rel->r_offset, bfd_get_32 (input_bfd, contents + rel->r_offset));
416
417 r = _bfd_final_link_relocate (howto, input_bfd, input_section,
418 contents, rel->r_offset,
419 relocation, rel->r_addend);
420 }
421
422 return r;
423 }
424
425 \f
426 /* Relocate an FR30 ELF section.
427 There is some attempt to make this function usable for many architectures,
428 both USE_REL and USE_RELA ['twould be nice if such a critter existed],
429 if only to serve as a learning tool.
430
431 The RELOCATE_SECTION function is called by the new ELF backend linker
432 to handle the relocations for a section.
433
434 The relocs are always passed as Rela structures; if the section
435 actually uses Rel structures, the r_addend field will always be
436 zero.
437
438 This function is responsible for adjusting the section contents as
439 necessary, and (if using Rela relocs and generating a relocateable
440 output file) adjusting the reloc addend as necessary.
441
442 This function does not have to worry about setting the reloc
443 address or the reloc symbol index.
444
445 LOCAL_SYMS is a pointer to the swapped in local symbols.
446
447 LOCAL_SECTIONS is an array giving the section in the input file
448 corresponding to the st_shndx field of each local symbol.
449
450 The global hash table entry for the global symbols can be found
451 via elf_sym_hashes (input_bfd).
452
453 When generating relocateable output, this function must handle
454 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
455 going to be the section symbol corresponding to the output
456 section, which means that the addend must be adjusted
457 accordingly. */
458
459 static boolean
460 fr30_elf_relocate_section (output_bfd, info, input_bfd, input_section,
461 contents, relocs, local_syms, local_sections)
462 bfd * output_bfd;
463 struct bfd_link_info * info;
464 bfd * input_bfd;
465 asection * input_section;
466 bfd_byte * contents;
467 Elf_Internal_Rela * relocs;
468 Elf_Internal_Sym * local_syms;
469 asection ** local_sections;
470 {
471 Elf_Internal_Shdr * symtab_hdr;
472 struct elf_link_hash_entry ** sym_hashes;
473 Elf_Internal_Rela * rel;
474 Elf_Internal_Rela * relend;
475
476 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
477 sym_hashes = elf_sym_hashes (input_bfd);
478 relend = relocs + input_section->reloc_count;
479
480 fprintf (stderr, "Relocate section: %s\n", bfd_section_name (input_bfd, input_section));
481
482 for (rel = relocs; rel < relend; rel ++)
483 {
484 reloc_howto_type * howto;
485 unsigned long r_symndx;
486 Elf_Internal_Sym * sym;
487 asection * sec;
488 struct elf_link_hash_entry * h;
489 bfd_vma relocation;
490 bfd_reloc_status_type r;
491 const char * name = NULL;
492
493 r_symndx = ELF32_R_SYM (rel->r_info);
494
495 if (info->relocateable)
496 {
497 /* This is a relocateable link. We don't have to change
498 anything, unless the reloc is against a section symbol,
499 in which case we have to adjust according to where the
500 section symbol winds up in the output section. */
501 if (r_symndx < symtab_hdr->sh_info)
502 {
503 sym = local_syms + r_symndx;
504
505 if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
506 {
507 sec = local_sections [r_symndx];
508 rel->r_addend += sec->output_offset + sym->st_value;
509 }
510 }
511
512 continue;
513 }
514
515 /* This is a final link. */
516 howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
517 h = NULL;
518 sym = NULL;
519 sec = NULL;
520
521 if (r_symndx < symtab_hdr->sh_info)
522 {
523 sym = local_syms + r_symndx;
524 sec = local_sections [r_symndx];
525 relocation = (sec->output_section->vma
526 + sec->output_offset
527 + sym->st_value);
528
529 name = bfd_elf_string_from_elf_section
530 (input_bfd, symtab_hdr->sh_link, sym->st_name);
531 name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
532 #if 1
533 fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
534 sec->name, name, sym->st_name,
535 sec->output_section->vma, sec->output_offset,
536 sym->st_value, rel->r_addend);
537 #endif
538 }
539 else
540 {
541 h = sym_hashes [r_symndx - symtab_hdr->sh_info];
542
543 while (h->root.type == bfd_link_hash_indirect
544 || h->root.type == bfd_link_hash_warning)
545 h = (struct elf_link_hash_entry *) h->root.u.i.link;
546
547 name = h->root.root.string;
548
549 if (h->root.type == bfd_link_hash_defined
550 || h->root.type == bfd_link_hash_defweak)
551 {
552 sec = h->root.u.def.section;
553 relocation = (h->root.u.def.value
554 + sec->output_section->vma
555 + sec->output_offset);
556 #if 1
557 fprintf (stderr,
558 "defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
559 sec->name, name, h->root.u.def.value,
560 sec->output_section->vma, sec->output_offset, relocation);
561 #endif
562 }
563 else if (h->root.type == bfd_link_hash_undefweak)
564 {
565 #if 1
566 fprintf (stderr, "undefined: sec: %s, name: %s\n",
567 sec->name, name);
568 #endif
569 relocation = 0;
570 }
571 else
572 {
573 if (! ((*info->callbacks->undefined_symbol)
574 (info, h->root.root.string, input_bfd,
575 input_section, rel->r_offset)))
576 return false;
577 #if 1
578 fprintf (stderr, "unknown: name: %s\n", name);
579 #endif
580 relocation = 0;
581 }
582 }
583
584 r = fr30_final_link_relocate (howto, input_bfd, input_section,
585 contents, rel, relocation);
586
587 if (r != bfd_reloc_ok)
588 {
589 const char * msg = (const char *) NULL;
590
591 switch (r)
592 {
593 case bfd_reloc_overflow:
594 r = info->callbacks->reloc_overflow
595 (info, name, howto->name, (bfd_vma) 0,
596 input_bfd, input_section, rel->r_offset);
597 break;
598
599 case bfd_reloc_undefined:
600 r = info->callbacks->undefined_symbol
601 (info, name, input_bfd, input_section, rel->r_offset);
602 break;
603
604 case bfd_reloc_outofrange:
605 msg = _("internal error: out of range error");
606 break;
607
608 case bfd_reloc_notsupported:
609 msg = _("internal error: unsupported relocation error");
610 break;
611
612 case bfd_reloc_dangerous:
613 msg = _("internal error: dangerous relocation");
614 break;
615
616 default:
617 msg = _("internal error: unknown error");
618 break;
619 }
620
621 if (msg)
622 r = info->callbacks->warning
623 (info, msg, name, input_bfd, input_section, rel->r_offset);
624
625 if (! r)
626 return false;
627 }
628 }
629
630 return true;
631 }
632 \f
633 #define ELF_ARCH bfd_arch_fr30
634 #define ELF_MACHINE_CODE EM_CYGNUS_FR30
635 #define ELF_MAXPAGESIZE 0x1000
636
637 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
638 #define TARGET_BIG_NAME "elf32-fr30"
639
640 #define elf_info_to_howto_rel NULL
641 #define elf_info_to_howto fr30_info_to_howto_rela
642 #define elf_backend_relocate_section fr30_elf_relocate_section
643
644 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
645
646 #include "elf32-target.h"
This page took 0.042075 seconds and 5 git commands to generate.