1 /* FR30-specific support for 32-bit ELF.
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
4 Free Software Foundation, Inc.
6 This file is part of BFD, the Binary File Descriptor library.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
29 /* Forward declarations. */
30 static bfd_reloc_status_type
31 fr30_elf_i20_reloc (bfd
*, arelent
*, asymbol
*, void * data
,
32 asection
*, bfd
*, char **error_message
);
33 static bfd_reloc_status_type
34 fr30_elf_i32_reloc (bfd
*, arelent
*, asymbol
*, void *,
35 asection
*, bfd
*, char **);
37 static reloc_howto_type fr30_elf_howto_table
[] =
39 /* This reloc does nothing. */
40 HOWTO (R_FR30_NONE
, /* type */
42 2, /* size (0 = byte, 1 = short, 2 = long) */
44 FALSE
, /* pc_relative */
46 complain_overflow_bitfield
, /* complain_on_overflow */
47 bfd_elf_generic_reloc
, /* special_function */
48 "R_FR30_NONE", /* name */
49 FALSE
, /* partial_inplace */
52 FALSE
), /* pcrel_offset */
54 /* An 8 bit absolute relocation. */
55 HOWTO (R_FR30_8
, /* type */
57 1, /* size (0 = byte, 1 = short, 2 = long) */
59 FALSE
, /* pc_relative */
61 complain_overflow_bitfield
, /* complain_on_overflow */
62 bfd_elf_generic_reloc
, /* special_function */
63 "R_FR30_8", /* name */
64 FALSE
, /* partial_inplace */
65 0x0000, /* src_mask */
66 0x0ff0, /* dst_mask */
67 FALSE
), /* pcrel_offset */
69 /* A 20 bit absolute relocation. */
70 HOWTO (R_FR30_20
, /* type */
72 2, /* size (0 = byte, 1 = short, 2 = long) */
74 FALSE
, /* pc_relative */
76 complain_overflow_bitfield
, /* complain_on_overflow */
77 fr30_elf_i20_reloc
, /* special_function */
78 "R_FR30_20", /* name */
79 FALSE
, /* partial_inplace */
80 0x00000000, /* src_mask */
81 0x00f0ffff, /* dst_mask */
82 FALSE
), /* pcrel_offset */
84 /* A 32 bit absolute relocation. */
85 HOWTO (R_FR30_32
, /* type */
87 2, /* size (0 = byte, 1 = short, 2 = long) */
89 FALSE
, /* pc_relative */
91 complain_overflow_bitfield
, /* complain_on_overflow */
92 bfd_elf_generic_reloc
, /* special_function */
93 "R_FR30_32", /* name */
94 FALSE
, /* partial_inplace */
95 0x00000000, /* src_mask */
96 0xffffffff, /* dst_mask */
97 FALSE
), /* pcrel_offset */
99 /* A 32 bit into 48 bits absolute relocation. */
100 HOWTO (R_FR30_48
, /* type */
102 2, /* size (0 = byte, 1 = short, 2 = long) */
104 FALSE
, /* pc_relative */
106 complain_overflow_bitfield
, /* complain_on_overflow */
107 fr30_elf_i32_reloc
, /* special_function */
108 "R_FR30_48", /* name */
109 FALSE
, /* partial_inplace */
110 0x00000000, /* src_mask */
111 0xffffffff, /* dst_mask */
112 FALSE
), /* pcrel_offset */
114 /* A 6 bit absolute relocation. */
115 HOWTO (R_FR30_6_IN_4
, /* type */
117 1, /* size (0 = byte, 1 = short, 2 = long) */
119 FALSE
, /* pc_relative */
121 complain_overflow_unsigned
, /* complain_on_overflow */
122 bfd_elf_generic_reloc
, /* special_function */
123 "R_FR30_6_IN_4", /* name */
124 FALSE
, /* partial_inplace */
125 0x0000, /* src_mask */
126 0x00f0, /* dst_mask */
127 FALSE
), /* pcrel_offset */
129 /* An 8 bit absolute relocation. */
130 HOWTO (R_FR30_8_IN_8
, /* type */
132 1, /* size (0 = byte, 1 = short, 2 = long) */
134 FALSE
, /* pc_relative */
136 complain_overflow_signed
, /* complain_on_overflow */
137 bfd_elf_generic_reloc
,/* special_function */
138 "R_FR30_8_IN_8", /* name */
139 FALSE
, /* partial_inplace */
140 0x0000, /* src_mask */
141 0x0ff0, /* dst_mask */
142 FALSE
), /* pcrel_offset */
144 /* A 9 bit absolute relocation. */
145 HOWTO (R_FR30_9_IN_8
, /* type */
147 1, /* size (0 = byte, 1 = short, 2 = long) */
149 FALSE
, /* pc_relative */
151 complain_overflow_signed
, /* complain_on_overflow */
152 bfd_elf_generic_reloc
,/* special_function */
153 "R_FR30_9_IN_8", /* name */
154 FALSE
, /* partial_inplace */
155 0x0000, /* src_mask */
156 0x0ff0, /* dst_mask */
157 FALSE
), /* pcrel_offset */
159 /* A 10 bit absolute relocation. */
160 HOWTO (R_FR30_10_IN_8
, /* type */
162 1, /* size (0 = byte, 1 = short, 2 = long) */
164 FALSE
, /* pc_relative */
166 complain_overflow_signed
, /* complain_on_overflow */
167 bfd_elf_generic_reloc
,/* special_function */
168 "R_FR30_10_IN_8", /* name */
169 FALSE
, /* partial_inplace */
170 0x0000, /* src_mask */
171 0x0ff0, /* dst_mask */
172 FALSE
), /* pcrel_offset */
174 /* A PC relative 9 bit relocation, right shifted by 1. */
175 HOWTO (R_FR30_9_PCREL
, /* type */
177 1, /* size (0 = byte, 1 = short, 2 = long) */
179 TRUE
, /* pc_relative */
181 complain_overflow_signed
, /* complain_on_overflow */
182 bfd_elf_generic_reloc
, /* special_function */
183 "R_FR30_9_PCREL", /* name */
184 FALSE
, /* partial_inplace */
185 0x0000, /* src_mask */
186 0x00ff, /* dst_mask */
187 FALSE
), /* pcrel_offset */
189 /* A PC relative 12 bit relocation, right shifted by 1. */
190 HOWTO (R_FR30_12_PCREL
, /* type */
192 1, /* size (0 = byte, 1 = short, 2 = long) */
194 TRUE
, /* pc_relative */
196 complain_overflow_signed
, /* complain_on_overflow */
197 bfd_elf_generic_reloc
, /* special_function */
198 "R_FR30_12_PCREL", /* name */
199 FALSE
, /* partial_inplace */
200 0x0000, /* src_mask */
201 0x07ff, /* dst_mask */
202 FALSE
), /* pcrel_offset */
203 /* GNU extension to record C++ vtable hierarchy */
204 HOWTO (R_FR30_GNU_VTINHERIT
, /* type */
206 2, /* size (0 = byte, 1 = short, 2 = long) */
208 FALSE
, /* pc_relative */
210 complain_overflow_dont
, /* complain_on_overflow */
211 NULL
, /* special_function */
212 "R_FR30_GNU_VTINHERIT", /* name */
213 FALSE
, /* partial_inplace */
216 FALSE
), /* pcrel_offset */
218 /* GNU extension to record C++ vtable member usage */
219 HOWTO (R_FR30_GNU_VTENTRY
, /* type */
221 2, /* size (0 = byte, 1 = short, 2 = long) */
223 FALSE
, /* pc_relative */
225 complain_overflow_dont
, /* complain_on_overflow */
226 _bfd_elf_rel_vtable_reloc_fn
, /* special_function */
227 "R_FR30_GNU_VTENTRY", /* name */
228 FALSE
, /* partial_inplace */
231 FALSE
), /* pcrel_offset */
234 /* Utility to actually perform an R_FR30_20 reloc. */
236 static bfd_reloc_status_type
237 fr30_elf_i20_reloc (bfd
*abfd
,
238 arelent
*reloc_entry
,
241 asection
*input_section
,
243 char **error_message ATTRIBUTE_UNUSED
)
248 /* This part is from bfd_elf_generic_reloc. */
249 if (output_bfd
!= (bfd
*) NULL
250 && (symbol
->flags
& BSF_SECTION_SYM
) == 0
251 && (! reloc_entry
->howto
->partial_inplace
252 || reloc_entry
->addend
== 0))
254 reloc_entry
->address
+= input_section
->output_offset
;
258 if (output_bfd
!= NULL
)
259 /* FIXME: See bfd_perform_relocation. Is this right? */
264 + symbol
->section
->output_section
->vma
265 + symbol
->section
->output_offset
266 + reloc_entry
->addend
;
268 if (relocation
> (((bfd_vma
) 1 << 20) - 1))
269 return bfd_reloc_overflow
;
271 x
= bfd_get_32 (abfd
, (char *) data
+ reloc_entry
->address
);
272 x
= (x
& 0xff0f0000) | (relocation
& 0x0000ffff) | ((relocation
& 0x000f0000) << 4);
273 bfd_put_32 (abfd
, (bfd_vma
) x
, (char *) data
+ reloc_entry
->address
);
278 /* Utility to actually perform a R_FR30_48 reloc. */
280 static bfd_reloc_status_type
281 fr30_elf_i32_reloc (bfd
*abfd
,
282 arelent
*reloc_entry
,
285 asection
*input_section
,
287 char **error_message ATTRIBUTE_UNUSED
)
291 /* This part is from bfd_elf_generic_reloc. */
292 if (output_bfd
!= (bfd
*) NULL
293 && (symbol
->flags
& BSF_SECTION_SYM
) == 0
294 && (! reloc_entry
->howto
->partial_inplace
295 || reloc_entry
->addend
== 0))
297 reloc_entry
->address
+= input_section
->output_offset
;
301 if (output_bfd
!= NULL
)
302 /* FIXME: See bfd_perform_relocation. Is this right? */
307 + symbol
->section
->output_section
->vma
308 + symbol
->section
->output_offset
309 + reloc_entry
->addend
;
311 bfd_put_32 (abfd
, relocation
, (char *) data
+ reloc_entry
->address
+ 2);
316 /* Map BFD reloc types to FR30 ELF reloc types. */
318 struct fr30_reloc_map
320 bfd_reloc_code_real_type bfd_reloc_val
;
321 unsigned int fr30_reloc_val
;
324 static const struct fr30_reloc_map fr30_reloc_map
[] =
326 { BFD_RELOC_NONE
, R_FR30_NONE
},
327 { BFD_RELOC_8
, R_FR30_8
},
328 { BFD_RELOC_FR30_20
, R_FR30_20
},
329 { BFD_RELOC_32
, R_FR30_32
},
330 { BFD_RELOC_FR30_48
, R_FR30_48
},
331 { BFD_RELOC_FR30_6_IN_4
, R_FR30_6_IN_4
},
332 { BFD_RELOC_FR30_8_IN_8
, R_FR30_8_IN_8
},
333 { BFD_RELOC_FR30_9_IN_8
, R_FR30_9_IN_8
},
334 { BFD_RELOC_FR30_10_IN_8
, R_FR30_10_IN_8
},
335 { BFD_RELOC_FR30_9_PCREL
, R_FR30_9_PCREL
},
336 { BFD_RELOC_FR30_12_PCREL
, R_FR30_12_PCREL
},
337 { BFD_RELOC_VTABLE_INHERIT
, R_FR30_GNU_VTINHERIT
},
338 { BFD_RELOC_VTABLE_ENTRY
, R_FR30_GNU_VTENTRY
},
341 static reloc_howto_type
*
342 fr30_reloc_type_lookup (bfd
*abfd ATTRIBUTE_UNUSED
,
343 bfd_reloc_code_real_type code
)
347 for (i
= sizeof (fr30_reloc_map
) / sizeof (fr30_reloc_map
[0]);
349 if (fr30_reloc_map
[i
].bfd_reloc_val
== code
)
350 return & fr30_elf_howto_table
[fr30_reloc_map
[i
].fr30_reloc_val
];
355 static reloc_howto_type
*
356 fr30_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
, const char *r_name
)
361 i
< sizeof (fr30_elf_howto_table
) / sizeof (fr30_elf_howto_table
[0]);
363 if (fr30_elf_howto_table
[i
].name
!= NULL
364 && strcasecmp (fr30_elf_howto_table
[i
].name
, r_name
) == 0)
365 return &fr30_elf_howto_table
[i
];
370 /* Set the howto pointer for an FR30 ELF reloc. */
373 fr30_info_to_howto_rela (bfd
*abfd ATTRIBUTE_UNUSED
,
375 Elf_Internal_Rela
*dst
)
379 r_type
= ELF32_R_TYPE (dst
->r_info
);
380 BFD_ASSERT (r_type
< (unsigned int) R_FR30_max
);
381 cache_ptr
->howto
= & fr30_elf_howto_table
[r_type
];
384 /* Perform a single relocation. By default we use the standard BFD
385 routines, but a few relocs, we have to do them ourselves. */
387 static bfd_reloc_status_type
388 fr30_final_link_relocate (reloc_howto_type
*howto
,
390 asection
*input_section
,
392 Elf_Internal_Rela
*rel
,
395 bfd_reloc_status_type r
= bfd_reloc_ok
;
402 contents
+= rel
->r_offset
;
403 relocation
+= rel
->r_addend
;
405 if (relocation
> ((1 << 20) - 1))
406 return bfd_reloc_overflow
;
408 x
= bfd_get_32 (input_bfd
, contents
);
409 x
= (x
& 0xff0f0000) | (relocation
& 0x0000ffff) | ((relocation
& 0x000f0000) << 4);
410 bfd_put_32 (input_bfd
, x
, contents
);
414 contents
+= rel
->r_offset
+ 2;
415 relocation
+= rel
->r_addend
;
416 bfd_put_32 (input_bfd
, relocation
, contents
);
420 contents
+= rel
->r_offset
+ 1;
421 srel
= (bfd_signed_vma
) relocation
;
422 srel
+= rel
->r_addend
;
423 srel
-= rel
->r_offset
;
424 srel
-= 2; /* Branch instructions add 2 to the PC... */
425 srel
-= (input_section
->output_section
->vma
+
426 input_section
->output_offset
);
429 return bfd_reloc_outofrange
;
430 if (srel
> ((1 << 8) - 1) || (srel
< - (1 << 8)))
431 return bfd_reloc_overflow
;
433 bfd_put_8 (input_bfd
, srel
>> 1, contents
);
436 case R_FR30_12_PCREL
:
437 contents
+= rel
->r_offset
;
438 srel
= (bfd_signed_vma
) relocation
;
439 srel
+= rel
->r_addend
;
440 srel
-= rel
->r_offset
;
441 srel
-= 2; /* Branch instructions add 2 to the PC... */
442 srel
-= (input_section
->output_section
->vma
+
443 input_section
->output_offset
);
446 return bfd_reloc_outofrange
;
447 if (srel
> ((1 << 11) - 1) || (srel
< - (1 << 11)))
448 return bfd_reloc_overflow
;
450 x
= bfd_get_16 (input_bfd
, contents
);
451 x
= (x
& 0xf800) | ((srel
>> 1) & 0x7ff);
452 bfd_put_16 (input_bfd
, x
, contents
);
456 r
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
457 contents
, rel
->r_offset
,
458 relocation
, rel
->r_addend
);
464 /* Relocate an FR30 ELF section.
466 The RELOCATE_SECTION function is called by the new ELF backend linker
467 to handle the relocations for a section.
469 The relocs are always passed as Rela structures; if the section
470 actually uses Rel structures, the r_addend field will always be
473 This function is responsible for adjusting the section contents as
474 necessary, and (if using Rela relocs and generating a relocatable
475 output file) adjusting the reloc addend as necessary.
477 This function does not have to worry about setting the reloc
478 address or the reloc symbol index.
480 LOCAL_SYMS is a pointer to the swapped in local symbols.
482 LOCAL_SECTIONS is an array giving the section in the input file
483 corresponding to the st_shndx field of each local symbol.
485 The global hash table entry for the global symbols can be found
486 via elf_sym_hashes (input_bfd).
488 When generating relocatable output, this function must handle
489 STB_LOCAL/STT_SECTION symbols specially. The output symbol is
490 going to be the section symbol corresponding to the output
491 section, which means that the addend must be adjusted
495 fr30_elf_relocate_section (bfd
*output_bfd
,
496 struct bfd_link_info
*info
,
498 asection
*input_section
,
500 Elf_Internal_Rela
*relocs
,
501 Elf_Internal_Sym
*local_syms
,
502 asection
**local_sections
)
504 Elf_Internal_Shdr
*symtab_hdr
;
505 struct elf_link_hash_entry
**sym_hashes
;
506 Elf_Internal_Rela
*rel
;
507 Elf_Internal_Rela
*relend
;
509 symtab_hdr
= & elf_tdata (input_bfd
)->symtab_hdr
;
510 sym_hashes
= elf_sym_hashes (input_bfd
);
511 relend
= relocs
+ input_section
->reloc_count
;
513 for (rel
= relocs
; rel
< relend
; rel
++)
515 reloc_howto_type
*howto
;
516 unsigned long r_symndx
;
517 Elf_Internal_Sym
*sym
;
519 struct elf_link_hash_entry
*h
;
521 bfd_reloc_status_type r
;
525 r_type
= ELF32_R_TYPE (rel
->r_info
);
527 if ( r_type
== R_FR30_GNU_VTINHERIT
528 || r_type
== R_FR30_GNU_VTENTRY
)
531 r_symndx
= ELF32_R_SYM (rel
->r_info
);
533 howto
= fr30_elf_howto_table
+ ELF32_R_TYPE (rel
->r_info
);
538 if (r_symndx
< symtab_hdr
->sh_info
)
540 sym
= local_syms
+ r_symndx
;
541 sec
= local_sections
[r_symndx
];
542 relocation
= _bfd_elf_rela_local_sym (output_bfd
, sym
, &sec
, rel
);
544 name
= bfd_elf_string_from_elf_section
545 (input_bfd
, symtab_hdr
->sh_link
, sym
->st_name
);
546 name
= (name
== NULL
) ? bfd_section_name (input_bfd
, sec
) : name
;
550 bfd_boolean unresolved_reloc
, warned
;
552 RELOC_FOR_GLOBAL_SYMBOL (info
, input_bfd
, input_section
, rel
,
553 r_symndx
, symtab_hdr
, sym_hashes
,
555 unresolved_reloc
, warned
);
557 name
= h
->root
.root
.string
;
560 if (sec
!= NULL
&& discarded_section (sec
))
561 RELOC_AGAINST_DISCARDED_SECTION (info
, input_bfd
, input_section
,
562 rel
, 1, relend
, howto
, 0, contents
);
564 if (info
->relocatable
)
567 r
= fr30_final_link_relocate (howto
, input_bfd
, input_section
,
568 contents
, rel
, relocation
);
570 if (r
!= bfd_reloc_ok
)
572 const char * msg
= (const char *) NULL
;
576 case bfd_reloc_overflow
:
577 r
= info
->callbacks
->reloc_overflow
578 (info
, (h
? &h
->root
: NULL
), name
, howto
->name
,
579 (bfd_vma
) 0, input_bfd
, input_section
, rel
->r_offset
);
582 case bfd_reloc_undefined
:
583 r
= info
->callbacks
->undefined_symbol
584 (info
, name
, input_bfd
, input_section
, rel
->r_offset
,
588 case bfd_reloc_outofrange
:
589 msg
= _("internal error: out of range error");
592 case bfd_reloc_notsupported
:
593 msg
= _("internal error: unsupported relocation error");
596 case bfd_reloc_dangerous
:
597 msg
= _("internal error: dangerous relocation");
601 msg
= _("internal error: unknown error");
606 r
= info
->callbacks
->warning
607 (info
, msg
, name
, input_bfd
, input_section
, rel
->r_offset
);
617 /* Return the section that should be marked against GC for a given
621 fr30_elf_gc_mark_hook (asection
*sec
,
622 struct bfd_link_info
*info
,
623 Elf_Internal_Rela
*rel
,
624 struct elf_link_hash_entry
*h
,
625 Elf_Internal_Sym
*sym
)
628 switch (ELF32_R_TYPE (rel
->r_info
))
630 case R_FR30_GNU_VTINHERIT
:
631 case R_FR30_GNU_VTENTRY
:
635 return _bfd_elf_gc_mark_hook (sec
, info
, rel
, h
, sym
);
638 /* Look through the relocs for a section during the first phase.
639 Since we don't do .gots or .plts, we just need to consider the
640 virtual table relocs for gc. */
643 fr30_elf_check_relocs (bfd
*abfd
,
644 struct bfd_link_info
*info
,
646 const Elf_Internal_Rela
*relocs
)
648 Elf_Internal_Shdr
*symtab_hdr
;
649 struct elf_link_hash_entry
**sym_hashes
;
650 const Elf_Internal_Rela
*rel
;
651 const Elf_Internal_Rela
*rel_end
;
653 if (info
->relocatable
)
656 symtab_hdr
= &elf_tdata (abfd
)->symtab_hdr
;
657 sym_hashes
= elf_sym_hashes (abfd
);
659 rel_end
= relocs
+ sec
->reloc_count
;
660 for (rel
= relocs
; rel
< rel_end
; rel
++)
662 struct elf_link_hash_entry
*h
;
663 unsigned long r_symndx
;
665 r_symndx
= ELF32_R_SYM (rel
->r_info
);
666 if (r_symndx
< symtab_hdr
->sh_info
)
670 h
= sym_hashes
[r_symndx
- symtab_hdr
->sh_info
];
671 while (h
->root
.type
== bfd_link_hash_indirect
672 || h
->root
.type
== bfd_link_hash_warning
)
673 h
= (struct elf_link_hash_entry
*) h
->root
.u
.i
.link
;
676 switch (ELF32_R_TYPE (rel
->r_info
))
678 /* This relocation describes the C++ object vtable hierarchy.
679 Reconstruct it for later use during GC. */
680 case R_FR30_GNU_VTINHERIT
:
681 if (!bfd_elf_gc_record_vtinherit (abfd
, sec
, h
, rel
->r_offset
))
685 /* This relocation describes which C++ vtable entries are actually
686 used. Record for later use during GC. */
687 case R_FR30_GNU_VTENTRY
:
688 BFD_ASSERT (h
!= NULL
);
690 && !bfd_elf_gc_record_vtentry (abfd
, sec
, h
, rel
->r_addend
))
699 #define ELF_ARCH bfd_arch_fr30
700 #define ELF_MACHINE_CODE EM_FR30
701 #define ELF_MACHINE_ALT1 EM_CYGNUS_FR30
702 #define ELF_MAXPAGESIZE 0x1000
704 #define TARGET_BIG_SYM bfd_elf32_fr30_vec
705 #define TARGET_BIG_NAME "elf32-fr30"
707 #define elf_info_to_howto_rel NULL
708 #define elf_info_to_howto fr30_info_to_howto_rela
709 #define elf_backend_relocate_section fr30_elf_relocate_section
710 #define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook
711 #define elf_backend_check_relocs fr30_elf_check_relocs
713 #define elf_backend_can_gc_sections 1
714 #define elf_backend_rela_normal 1
716 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
717 #define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup
719 #include "elf32-target.h"