1 /* V850-specific support for 32-bit ELF
2 Copyright (C) 1994, 1995 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. */
22 /* XXX FIXME: This code is littered with 32bit int, 16bit short, 8bit char
23 dependencies. As is the gas & simulator code or the v850. */
32 static reloc_howto_type
*bfd_elf32_bfd_reloc_type_lookup
33 PARAMS ((bfd
*abfd
, bfd_reloc_code_real_type code
));
34 static void v850_info_to_howto_rel
35 PARAMS ((bfd
*, arelent
*, Elf32_Internal_Rel
*));
36 static bfd_reloc_status_type bfd_elf32_v850_reloc
37 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
41 /* Try to minimize the amount of space occupied by relocation tables
42 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
62 static reloc_howto_type elf_v850_howto_table
[] =
64 /* This reloc does nothing. */
65 HOWTO (R_V850_NONE
, /* type */
67 2, /* size (0 = byte, 1 = short, 2 = long) */
69 false, /* pc_relative */
71 complain_overflow_bitfield
, /* complain_on_overflow */
72 bfd_elf_generic_reloc
, /* special_function */
73 "R_V850_NONE", /* name */
74 false, /* partial_inplace */
77 false), /* pcrel_offset */
79 /* A PC relative 9 bit branch. */
80 HOWTO (R_V850_9_PCREL
, /* type */
82 2, /* size (0 = byte, 1 = short, 2 = long) */
84 true, /* pc_relative */
86 complain_overflow_bitfield
, /* complain_on_overflow */
87 bfd_elf32_v850_reloc
, /* special_function */
88 "R_V850_9_PCREL", /* name */
89 false, /* partial_inplace */
90 0x00ffffff, /* src_mask */
91 0x00ffffff, /* dst_mask */
92 true), /* pcrel_offset */
94 /* A PC relative 22 bit branch. */
95 HOWTO (R_V850_22_PCREL
, /* type */
97 2, /* size (0 = byte, 1 = short, 2 = long) */
99 true, /* pc_relative */
101 complain_overflow_signed
, /* complain_on_overflow */
102 bfd_elf32_v850_reloc
, /* special_function */
103 "R_V850_22_PCREL", /* name */
104 false, /* partial_inplace */
105 0x07ffff80, /* src_mask */
106 0x07ffff80, /* dst_mask */
107 true), /* pcrel_offset */
109 /* High 16 bits of symbol value. */
110 HOWTO (R_V850_HI16_S
, /* type */
112 1, /* size (0 = byte, 1 = short, 2 = long) */
114 false, /* pc_relative */
116 complain_overflow_dont
,/* complain_on_overflow */
117 bfd_elf32_v850_reloc
, /* special_function */
118 "R_V850_HI16_S", /* name */
119 true, /* partial_inplace */
120 0xffff, /* src_mask */
121 0xffff, /* dst_mask */
122 false), /* pcrel_offset */
124 /* High 16 bits of symbol value. */
125 HOWTO (R_V850_HI16
, /* type */
127 1, /* size (0 = byte, 1 = short, 2 = long) */
129 false, /* pc_relative */
131 complain_overflow_dont
,/* complain_on_overflow */
132 bfd_elf32_v850_reloc
, /* special_function */
133 "R_V850_HI16", /* name */
134 true, /* partial_inplace */
135 0xffff, /* src_mask */
136 0xffff, /* dst_mask */
137 false), /* pcrel_offset */
139 /* Low 16 bits of symbol value. */
140 HOWTO (R_V850_LO16
, /* type */
142 1, /* size (0 = byte, 1 = short, 2 = long) */
144 false, /* pc_relative */
146 complain_overflow_dont
,/* complain_on_overflow */
147 bfd_elf_generic_reloc
, /* special_function */
148 "R_V850_LO16", /* name */
149 true, /* partial_inplace */
150 0xffff, /* src_mask */
151 0xffff, /* dst_mask */
152 false), /* pcrel_offset */
154 /* Simple 32bit reloc. */
155 HOWTO (R_V850_32
, /* type */
157 2, /* size (0 = byte, 1 = short, 2 = long) */
159 false, /* pc_relative */
161 complain_overflow_dont
,/* complain_on_overflow */
162 bfd_elf_generic_reloc
, /* special_function */
163 "R_V850_32", /* name */
164 true, /* partial_inplace */
165 0xffffffff, /* src_mask */
166 0xffffffff, /* dst_mask */
167 false), /* pcrel_offset */
169 /* Simple 16bit reloc. */
170 HOWTO (R_V850_16
, /* type */
172 1, /* size (0 = byte, 1 = short, 2 = long) */
174 false, /* pc_relative */
176 complain_overflow_dont
,/* complain_on_overflow */
177 bfd_elf_generic_reloc
, /* special_function */
178 "R_V850_16", /* name */
179 true, /* partial_inplace */
180 0xffff, /* src_mask */
181 0xffff, /* dst_mask */
182 false), /* pcrel_offset */
184 /* Simple 8bit reloc. */
185 HOWTO (R_V850_8
, /* type */
187 0, /* size (0 = byte, 1 = short, 2 = long) */
189 false, /* pc_relative */
191 complain_overflow_dont
,/* complain_on_overflow */
192 bfd_elf_generic_reloc
, /* special_function */
193 "R_V850_8", /* name */
194 true, /* partial_inplace */
197 false), /* pcrel_offset */
199 /* Offset from the short data area pointer. */
200 HOWTO (R_V850_SDA_OFFSET
, /* type */
202 1, /* size (0 = byte, 1 = short, 2 = long) */
204 false, /* pc_relative */
206 complain_overflow_dont
,/* complain_on_overflow */
207 bfd_elf_generic_reloc
, /* special_function */
208 "R_V850_SDA_OFFSET", /* name */
209 true, /* partial_inplace */
210 0xffff, /* src_mask */
211 0xffff, /* dst_mask */
212 false), /* pcrel_offset */
214 /* Offset from the zero data area pointer. */
215 HOWTO (R_V850_ZDA_OFFSET
, /* type */
217 1, /* size (0 = byte, 1 = short, 2 = long) */
219 false, /* pc_relative */
221 complain_overflow_dont
,/* complain_on_overflow */
222 bfd_elf_generic_reloc
, /* special_function */
223 "R_V850_ZDA_OFFSET", /* name */
224 true, /* partial_inplace */
225 0xffff, /* src_mask */
226 0xffff, /* dst_mask */
227 false), /* pcrel_offset */
229 /* Offset from the tiny data area pointer. */
230 HOWTO (R_V850_TDA_OFFSET
, /* type */
232 2, /* size (0 = byte, 1 = short, 2 = long) */
234 false, /* pc_relative */
236 complain_overflow_dont
,/* complain_on_overflow */
237 bfd_elf_generic_reloc
, /* special_function */
238 "R_V850_TDA_OFFSET", /* name */
239 true, /* partial_inplace */
242 false), /* pcrel_offset */
246 /* Map BFD reloc types to V850 ELF reloc types. */
248 struct v850_reloc_map
250 unsigned char bfd_reloc_val
;
251 unsigned char elf_reloc_val
;
254 static const struct v850_reloc_map v850_reloc_map
[] =
256 { BFD_RELOC_NONE
, R_V850_NONE
, },
257 { BFD_RELOC_V850_9_PCREL
, R_V850_9_PCREL
, },
258 { BFD_RELOC_V850_22_PCREL
, R_V850_22_PCREL
, },
259 { BFD_RELOC_HI16_S
, R_V850_HI16_S
, },
260 { BFD_RELOC_HI16
, R_V850_HI16
, },
261 { BFD_RELOC_LO16
, R_V850_LO16
, },
262 { BFD_RELOC_32
, R_V850_32
, },
263 { BFD_RELOC_16
, R_V850_16
, },
264 { BFD_RELOC_8
, R_V850_8
, },
265 { BFD_RELOC_V850_TDA_OFFSET
, R_V850_TDA_OFFSET
, },
266 { BFD_RELOC_V850_SDA_OFFSET
, R_V850_SDA_OFFSET
, },
267 { BFD_RELOC_V850_ZDA_OFFSET
, R_V850_ZDA_OFFSET
, },
270 static reloc_howto_type
*
271 bfd_elf32_bfd_reloc_type_lookup (abfd
, code
)
273 bfd_reloc_code_real_type code
;
278 i
< sizeof (v850_reloc_map
) / sizeof (struct v850_reloc_map
);
281 if (v850_reloc_map
[i
].bfd_reloc_val
== code
)
282 return &elf_v850_howto_table
[v850_reloc_map
[i
].elf_reloc_val
];
288 /* Set the howto pointer for an V850 ELF reloc. */
291 v850_info_to_howto_rel (abfd
, cache_ptr
, dst
)
294 Elf32_Internal_Rel
*dst
;
298 r_type
= ELF32_R_TYPE (dst
->r_info
);
299 BFD_ASSERT (r_type
< (unsigned int) R_V850_max
);
300 cache_ptr
->howto
= &elf_v850_howto_table
[r_type
];
303 static bfd_reloc_status_type
304 bfd_elf32_v850_reloc (abfd
, reloc
, symbol
, data
, isection
, obfd
, err
)
313 if (obfd
!= (bfd
*) NULL
314 && (symbol
->flags
& BSF_SECTION_SYM
) == 0
315 && (! reloc
->howto
->partial_inplace
316 || reloc
->addend
== 0))
318 reloc
->address
+= isection
->output_offset
;
321 else if (obfd
!= NULL
)
323 return bfd_reloc_continue
;
326 /* Catch relocs involving undefined symbols. */
327 if (bfd_is_und_section (symbol
->section
)
328 && (symbol
->flags
& BSF_WEAK
) == 0
330 return bfd_reloc_undefined
;
332 /* We handle final linking of some relocs ourselves. */
334 long relocation
, insn
;
336 /* Is the address of the relocation really within the section? */
337 if (reloc
->address
> isection
->_cooked_size
)
338 return bfd_reloc_outofrange
;
340 /* Work out which section the relocation is targetted at and the
341 initial relocation command value. */
343 /* Get symbol value. (Common symbols are special.) */
344 if (bfd_is_com_section (symbol
->section
))
347 relocation
= symbol
->value
;
349 /* Convert input-section-relative symbol value to absolute + addend. */
350 relocation
+= symbol
->section
->output_section
->vma
;
351 relocation
+= symbol
->section
->output_offset
;
352 relocation
+= reloc
->addend
;
354 if (reloc
->howto
->pc_relative
== true)
356 /* Here the variable relocation holds the final address of the
357 symbol we are relocating against, plus any addend. */
358 relocation
-= isection
->output_section
->vma
+ isection
->output_offset
;
360 /* Deal with pcrel_offset */
361 relocation
-= reloc
->address
;
364 /* I've got no clue... */
367 if (reloc
->howto
->type
== R_V850_22_PCREL
)
369 if (relocation
> 0x1ffff || relocation
< -0x200000)
370 return bfd_reloc_overflow
;
372 if ((relocation
% 2) != 0)
373 return bfd_reloc_dangerous
;
375 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
377 insn
|= (((relocation
& 0xfffe) << 16)
378 | ((relocation
& 0x3f0000) >> 16));
379 bfd_put_32 (abfd
, insn
, (bfd_byte
*)data
+ reloc
->address
);
382 else if (reloc
->howto
->type
== R_V850_9_PCREL
)
384 if (relocation
> 0xff || relocation
< -0x100)
385 return bfd_reloc_overflow
;
387 if ((relocation
% 2) != 0)
388 return bfd_reloc_dangerous
;
390 insn
= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
392 insn
|= ((relocation
& 0x1f0) << 7) | ((relocation
& 0x0e) << 3);
393 bfd_put_16 (abfd
, insn
, (bfd_byte
*)data
+ reloc
->address
);
396 else if (reloc
->howto
->type
== R_V850_HI16_S
)
398 relocation
+= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
399 relocation
= (relocation
>> 16) + ((relocation
& 0x8000) != 0);
400 bfd_put_16 (abfd
, relocation
, (bfd_byte
*)data
+ reloc
->address
);
403 else if (reloc
->howto
->type
== R_V850_HI16
)
405 relocation
+= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
406 relocation
= (relocation
>> 16);
407 bfd_put_16 (abfd
, relocation
, (bfd_byte
*)data
+ reloc
->address
);
411 return bfd_reloc_notsupported
;
414 return bfd_reloc_continue
;
417 static boolean bfd_elf32_v850_is_local_label
PARAMS ((bfd
*, asymbol
*));
421 bfd_elf32_v850_is_local_label (abfd
, symbol
)
425 return ((symbol
->name
[0] == '.' && (symbol
->name
[1] == 'L' || symbol
->name
[1] == '.'))
426 || (symbol
->name
[0] == '_' && symbol
->name
[1] == '.' && symbol
->name
[2] == 'L'
427 && symbol
->name
[3] == '_'));
430 /* Perform a relocation as part of a final link. */
431 static bfd_reloc_status_type
432 elf32_v850_bfd_final_link_relocate (howto
, input_bfd
, output_bfd
,
433 input_section
, contents
, offset
, value
,
434 addend
, info
, sym_sec
, is_local
)
435 reloc_howto_type
*howto
;
438 asection
*input_section
;
443 struct bfd_link_info
*info
;
448 unsigned long r_type
= howto
->type
;
449 unsigned long r_format
= howto
->bitsize
;
450 bfd_byte
*hit_data
= contents
+ offset
;
451 boolean r_pcrel
= howto
->pc_relative
;
456 value
-= (input_section
->output_section
->vma
457 + input_section
->output_offset
);
460 if ((long)value
> 0xff || (long)value
< -0x100)
461 return bfd_reloc_overflow
;
463 if ((value
% 2) != 0)
464 return bfd_reloc_dangerous
;
466 insn
= bfd_get_16 (input_bfd
, hit_data
);
468 insn
|= ((value
& 0x1f0) << 7) | ((value
& 0x0e) << 3);
469 bfd_put_16 (input_bfd
, insn
, hit_data
);
472 case R_V850_22_PCREL
:
473 value
-= (input_section
->output_section
->vma
474 + input_section
->output_offset
);
477 if ((long)value
> 0x1ffff || (long)value
< -0x200000)
478 return bfd_reloc_overflow
;
480 if ((value
% 2) != 0)
481 return bfd_reloc_dangerous
;
483 insn
= bfd_get_32 (input_bfd
, hit_data
);
485 insn
|= (((value
& 0xfffe) << 16) | ((value
& 0x3f0000) >> 16));
486 bfd_put_32 (input_bfd
, insn
, hit_data
);
490 value
+= (short)bfd_get_16 (input_bfd
, hit_data
);
491 value
= (value
>> 16) + ((value
& 0x8000) != 0);
493 if ((long)value
> 0x7fff || (long)value
< -0x8000)
494 return bfd_reloc_overflow
;
496 bfd_put_16 (input_bfd
, value
, hit_data
);
500 value
+= (short)bfd_get_16 (input_bfd
, hit_data
);
503 if ((long)value
> 0x7fff || (long)value
< -0x8000)
504 return bfd_reloc_overflow
;
506 bfd_put_16 (input_bfd
, value
, hit_data
);
510 value
+= (short)bfd_get_16 (input_bfd
, hit_data
);
513 bfd_put_16 (input_bfd
, value
, hit_data
);
517 case R_V850_ZDA_OFFSET
:
518 value
+= (short)bfd_get_16 (input_bfd
, hit_data
);
520 if ((long)value
> 0x7fff || (long)value
< -0x8000)
521 return bfd_reloc_overflow
;
523 bfd_put_16 (input_bfd
, value
, hit_data
);
527 value
+= bfd_get_32 (input_bfd
, hit_data
);
528 bfd_put_32 (input_bfd
, value
, hit_data
);
532 value
+= (char)bfd_get_8 (input_bfd
, hit_data
);
534 if ((long)value
> 0x7f || (long)value
< -0x80)
535 return bfd_reloc_overflow
;
537 bfd_put_8 (input_bfd
, value
, hit_data
);
540 case R_V850_SDA_OFFSET
:
543 struct bfd_link_hash_entry
*h
;
545 value
+= (short)bfd_get_16 (input_bfd
, hit_data
);
547 /* Get the value of __gp. */
548 h
= bfd_link_hash_lookup (info
->hash
, "__gp", false,
550 if (h
== (struct bfd_link_hash_entry
*) NULL
551 || h
->type
!= bfd_link_hash_defined
)
552 return bfd_reloc_undefined
;
555 + h
->u
.def
.section
->output_section
->vma
556 + h
->u
.def
.section
->output_offset
);
559 if ((long)value
> 0x7fff || (long)value
< -0x8000)
560 return bfd_reloc_overflow
;
562 bfd_put_16 (input_bfd
, value
, hit_data
);
566 case R_V850_TDA_OFFSET
:
569 struct bfd_link_hash_entry
*h
;
571 insn
= bfd_get_16 (input_bfd
, hit_data
);
573 /* Get the value of __ep. */
574 h
= bfd_link_hash_lookup (info
->hash
, "__ep", false,
576 if (h
== (struct bfd_link_hash_entry
*) NULL
577 || h
->type
!= bfd_link_hash_defined
)
578 return bfd_reloc_undefined
;
581 + h
->u
.def
.section
->output_section
->vma
582 + h
->u
.def
.section
->output_offset
);
586 /* Overflow computation and operand insertion is complicated
587 by valid offsets and insertions changing depending on the
588 instruction being used! */
589 if ((insn
& 0x0780) == 0x0500)
591 value
+= ((insn
& 0x7f) << 2);
593 /* Handle sld.w and sst.w -- 8 bit unsigned offset */
594 if ((long) value
> 0xff || (long) value
< 0)
595 return bfd_reloc_overflow
;
597 if ((value
% 4) != 0)
598 return bfd_reloc_dangerous
;
601 insn
|= (value
>> 1);
602 bfd_put_16 (input_bfd
, insn
, hit_data
);
606 if ((insn
& 0x0780) == 0x0400 || (insn
& 0x0780) == 0x0480)
608 value
+= ((insn
& 0x7f) << 1);
610 /* Handle sld.h and sst.h -- 8 bit unsigned offset */
611 if ((long) value
> 0xff || (long) value
< 0)
612 return bfd_reloc_overflow
;
614 if ((value
% 2) != 0)
615 return bfd_reloc_dangerous
;
618 insn
|= (value
>> 1);
619 bfd_put_16 (input_bfd
, insn
, hit_data
);
623 if ((insn
& 0x0780) == 0x0300 || (insn
& 0x0780) == 0x0380)
625 value
+= (insn
& 0x7f);
627 /* Handle sld.b and sst.b -- 7 bit unsigned offset */
628 if ((long) value
> 0x7f || (long) value
< 0)
629 return bfd_reloc_overflow
;
632 bfd_put_16 (input_bfd
, insn
, hit_data
);
636 /* Guess (XXX) that it's a movea instruction or something
638 value
+= (short)insn
;
639 if ((long)value
> 0x7fff || (long)value
< -0x8000)
640 return bfd_reloc_overflow
;
642 bfd_put_16 (input_bfd
, value
, hit_data
);
653 /* Relocate an V850 ELF section. */
656 v850_elf_relocate_section (output_bfd
, info
, input_bfd
, input_section
,
657 contents
, relocs
, local_syms
, local_sections
)
659 struct bfd_link_info
*info
;
661 asection
*input_section
;
663 Elf_Internal_Rela
*relocs
;
664 Elf_Internal_Sym
*local_syms
;
665 asection
**local_sections
;
667 Elf_Internal_Shdr
*symtab_hdr
;
668 struct elf_link_hash_entry
**sym_hashes
;
669 Elf_Internal_Rela
*rel
, *relend
;
671 symtab_hdr
= &elf_tdata (input_bfd
)->symtab_hdr
;
672 sym_hashes
= elf_sym_hashes (input_bfd
);
675 relend
= relocs
+ input_section
->reloc_count
;
676 for (; rel
< relend
; rel
++)
679 reloc_howto_type
*howto
;
680 unsigned long r_symndx
;
681 Elf_Internal_Sym
*sym
;
683 struct elf_link_hash_entry
*h
;
685 bfd_reloc_status_type r
;
687 if (info
->relocateable
)
689 /* This is a relocateable link. We don't have to change
690 anything, unless the reloc is against a section symbol,
691 in which case we have to adjust according to where the
692 section symbol winds up in the output section. */
693 if (r_symndx
< symtab_hdr
->sh_info
)
695 sym
= local_syms
+ r_symndx
;
696 if (ELF_ST_TYPE (sym
->st_info
) == STT_SECTION
)
698 sec
= local_sections
[r_symndx
];
699 rel
->r_addend
+= sec
->output_offset
+ sym
->st_value
;
706 r_type
= ELF32_R_TYPE (rel
->r_info
);
708 howto
= elf_v850_howto_table
+ r_type
;
710 r_symndx
= ELF32_R_SYM (rel
->r_info
);
712 /* This is a final link. */
716 if (r_symndx
< symtab_hdr
->sh_info
)
718 sym
= local_syms
+ r_symndx
;
719 sec
= local_sections
[r_symndx
];
720 relocation
= (sec
->output_section
->vma
726 h
= sym_hashes
[r_symndx
- symtab_hdr
->sh_info
];
727 while (h
->root
.type
== bfd_link_hash_indirect
728 || h
->root
.type
== bfd_link_hash_warning
)
729 h
= (struct elf_link_hash_entry
*) h
->root
.u
.i
.link
;
730 if (h
->root
.type
== bfd_link_hash_defined
731 || h
->root
.type
== bfd_link_hash_defweak
)
733 sec
= h
->root
.u
.def
.section
;
734 relocation
= (h
->root
.u
.def
.value
735 + sec
->output_section
->vma
736 + sec
->output_offset
);
738 else if (h
->root
.type
== bfd_link_hash_undefweak
)
742 if (! ((*info
->callbacks
->undefined_symbol
)
743 (info
, h
->root
.root
.string
, input_bfd
,
744 input_section
, rel
->r_offset
)))
750 /* FIXME: We should use the addend, but the COFF relocations
752 r
= elf32_v850_bfd_final_link_relocate (howto
, input_bfd
, output_bfd
,
754 contents
, rel
->r_offset
,
755 relocation
, rel
->r_addend
,
756 info
, sec
, h
== NULL
);
758 if (r
!= bfd_reloc_ok
)
763 case bfd_reloc_outofrange
:
765 case bfd_reloc_overflow
:
770 name
= h
->root
.root
.string
;
773 name
= (bfd_elf_string_from_elf_section
774 (input_bfd
, symtab_hdr
->sh_link
, sym
->st_name
));
778 name
= bfd_section_name (input_bfd
, sec
);
780 if (! ((*info
->callbacks
->reloc_overflow
)
781 (info
, name
, howto
->name
, (bfd_vma
) 0,
782 input_bfd
, input_section
, rel
->r_offset
)))
792 #define bfd_elf32_bfd_is_local_label bfd_elf32_v850_is_local_label
794 #define TARGET_LITTLE_SYM bfd_elf32_v850_vec
795 #define TARGET_LITTLE_NAME "elf32-v850"
796 #define ELF_ARCH bfd_arch_v850
797 #define ELF_MACHINE_CODE EM_CYGNUS_V850
798 #define ELF_MAXPAGESIZE 0x1000
800 #define elf_info_to_howto 0
801 #define elf_info_to_howto_rel v850_info_to_howto_rel
802 #define elf_backend_relocate_section v850_elf_relocate_section
805 #define elf_symbol_leading_char '_'
807 #include "elf32-target.h"