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. */
26 static reloc_howto_type
*bfd_elf32_bfd_reloc_type_lookup
27 PARAMS ((bfd
*abfd
, bfd_reloc_code_real_type code
));
28 static void v850_info_to_howto_rel
29 PARAMS ((bfd
*, arelent
*, Elf32_Internal_Rel
*));
30 static bfd_reloc_status_type bfd_elf32_v850_reloc
31 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
35 /* Try to minimize the amount of space occupied by relocation tables
36 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
56 static reloc_howto_type elf_v850_howto_table
[] =
58 /* This reloc does nothing. */
59 HOWTO (R_V850_NONE
, /* type */
61 2, /* size (0 = byte, 1 = short, 2 = long) */
63 false, /* pc_relative */
65 complain_overflow_bitfield
, /* complain_on_overflow */
66 bfd_elf_generic_reloc
, /* special_function */
67 "R_V850_NONE", /* name */
68 false, /* partial_inplace */
71 false), /* pcrel_offset */
73 /* A PC relative 9 bit branch. */
74 HOWTO (R_V850_9_PCREL
, /* type */
76 2, /* size (0 = byte, 1 = short, 2 = long) */
78 true, /* pc_relative */
80 complain_overflow_bitfield
, /* complain_on_overflow */
81 bfd_elf32_v850_reloc
, /* special_function */
82 "R_V850_9_PCREL", /* name */
83 false, /* partial_inplace */
84 0x00ffffff, /* src_mask */
85 0x00ffffff, /* dst_mask */
86 true), /* pcrel_offset */
88 /* A PC relative 22 bit branch. */
89 HOWTO (R_V850_22_PCREL
, /* type */
91 2, /* size (0 = byte, 1 = short, 2 = long) */
93 true, /* pc_relative */
95 complain_overflow_signed
, /* complain_on_overflow */
96 bfd_elf32_v850_reloc
, /* special_function */
97 "R_V850_22_PCREL", /* name */
98 false, /* partial_inplace */
99 0x07ffff80, /* src_mask */
100 0x07ffff80, /* dst_mask */
101 true), /* pcrel_offset */
103 /* High 16 bits of symbol value. */
104 HOWTO (R_V850_HI16_S
, /* type */
106 1, /* size (0 = byte, 1 = short, 2 = long) */
108 false, /* pc_relative */
110 complain_overflow_dont
,/* complain_on_overflow */
111 bfd_elf32_v850_reloc
, /* special_function */
112 "R_V850_HI16_S", /* name */
113 true, /* partial_inplace */
114 0xffff, /* src_mask */
115 0xffff, /* dst_mask */
116 false), /* pcrel_offset */
118 /* High 16 bits of symbol value. */
119 HOWTO (R_V850_HI16
, /* type */
121 1, /* size (0 = byte, 1 = short, 2 = long) */
123 false, /* pc_relative */
125 complain_overflow_dont
,/* complain_on_overflow */
126 bfd_elf32_v850_reloc
, /* special_function */
127 "R_V850_HI16", /* name */
128 true, /* partial_inplace */
129 0xffff, /* src_mask */
130 0xffff, /* dst_mask */
131 false), /* pcrel_offset */
133 /* Low 16 bits of symbol value. */
134 HOWTO (R_V850_LO16
, /* type */
136 1, /* size (0 = byte, 1 = short, 2 = long) */
138 false, /* pc_relative */
140 complain_overflow_dont
,/* complain_on_overflow */
141 bfd_elf_generic_reloc
, /* special_function */
142 "R_V850_LO16", /* name */
143 true, /* partial_inplace */
144 0xffff, /* src_mask */
145 0xffff, /* dst_mask */
146 false), /* pcrel_offset */
148 /* Simple 32bit reloc. */
149 HOWTO (R_V850_32
, /* type */
151 2, /* size (0 = byte, 1 = short, 2 = long) */
153 false, /* pc_relative */
155 complain_overflow_dont
,/* complain_on_overflow */
156 bfd_elf_generic_reloc
, /* special_function */
157 "R_V850_32", /* name */
158 true, /* partial_inplace */
159 0xffffffff, /* src_mask */
160 0xffffffff, /* dst_mask */
161 false), /* pcrel_offset */
163 /* Simple 16bit reloc. */
164 HOWTO (R_V850_16
, /* type */
166 1, /* size (0 = byte, 1 = short, 2 = long) */
168 false, /* pc_relative */
170 complain_overflow_dont
,/* complain_on_overflow */
171 bfd_elf_generic_reloc
, /* special_function */
172 "R_V850_16", /* name */
173 true, /* partial_inplace */
174 0xffff, /* src_mask */
175 0xffff, /* dst_mask */
176 false), /* pcrel_offset */
178 /* Simple 8bit reloc. */
179 HOWTO (R_V850_8
, /* type */
181 0, /* size (0 = byte, 1 = short, 2 = long) */
183 false, /* pc_relative */
185 complain_overflow_dont
,/* complain_on_overflow */
186 bfd_elf_generic_reloc
, /* special_function */
187 "R_V850_8", /* name */
188 true, /* partial_inplace */
191 false), /* pcrel_offset */
193 /* Offset from the short data area pointer. */
194 HOWTO (R_V850_SDA_OFFSET
, /* type */
196 1, /* size (0 = byte, 1 = short, 2 = long) */
198 false, /* pc_relative */
200 complain_overflow_dont
,/* complain_on_overflow */
201 bfd_elf_generic_reloc
, /* special_function */
202 "R_V850_SDA_OFFSET", /* name */
203 true, /* partial_inplace */
204 0xffff, /* src_mask */
205 0xffff, /* dst_mask */
206 false), /* pcrel_offset */
208 /* Offset from the tiny data area pointer. */
209 HOWTO (R_V850_TDA_OFFSET
, /* type */
211 1, /* size (0 = byte, 1 = short, 2 = long) */
213 false, /* pc_relative */
215 complain_overflow_dont
,/* complain_on_overflow */
216 bfd_elf_generic_reloc
, /* special_function */
217 "R_V850_TDA_OFFSET", /* name */
218 true, /* partial_inplace */
219 0xffff, /* src_mask */
220 0xffff, /* dst_mask */
221 false), /* pcrel_offset */
223 /* Offset from the zero data area pointer. */
224 HOWTO (R_V850_ZDA_OFFSET
, /* type */
226 1, /* size (0 = byte, 1 = short, 2 = long) */
228 false, /* pc_relative */
230 complain_overflow_dont
,/* complain_on_overflow */
231 bfd_elf_generic_reloc
, /* special_function */
232 "R_V850_ZDA_OFFSET", /* name */
233 true, /* partial_inplace */
234 0xffff, /* src_mask */
235 0xffff, /* dst_mask */
236 false), /* pcrel_offset */
240 /* Map BFD reloc types to V850 ELF reloc types. */
242 struct v850_reloc_map
244 unsigned char bfd_reloc_val
;
245 unsigned char elf_reloc_val
;
248 static const struct v850_reloc_map v850_reloc_map
[] =
250 { BFD_RELOC_NONE
, R_V850_NONE
, },
251 { BFD_RELOC_V850_9_PCREL
, R_V850_9_PCREL
, },
252 { BFD_RELOC_V850_22_PCREL
, R_V850_22_PCREL
, },
253 { BFD_RELOC_HI16_S
, R_V850_HI16_S
, },
254 { BFD_RELOC_HI16
, R_V850_HI16
, },
255 { BFD_RELOC_LO16
, R_V850_LO16
, },
256 { BFD_RELOC_32
, R_V850_32
, },
257 { BFD_RELOC_16
, R_V850_16
, },
258 { BFD_RELOC_8
, R_V850_8
, },
259 { BFD_RELOC_V850_TDA_OFFSET
, R_V850_TDA_OFFSET
, },
260 { BFD_RELOC_V850_SDA_OFFSET
, R_V850_SDA_OFFSET
, },
261 { BFD_RELOC_V850_ZDA_OFFSET
, R_V850_ZDA_OFFSET
, },
264 static reloc_howto_type
*
265 bfd_elf32_bfd_reloc_type_lookup (abfd
, code
)
267 bfd_reloc_code_real_type code
;
272 i
< sizeof (v850_reloc_map
) / sizeof (struct v850_reloc_map
);
275 if (v850_reloc_map
[i
].bfd_reloc_val
== code
)
276 return &elf_v850_howto_table
[v850_reloc_map
[i
].elf_reloc_val
];
282 /* Set the howto pointer for an V850 ELF reloc. */
285 v850_info_to_howto_rel (abfd
, cache_ptr
, dst
)
288 Elf32_Internal_Rel
*dst
;
292 r_type
= ELF32_R_TYPE (dst
->r_info
);
293 BFD_ASSERT (r_type
< (unsigned int) R_V850_max
);
294 cache_ptr
->howto
= &elf_v850_howto_table
[r_type
];
297 static bfd_reloc_status_type
298 bfd_elf32_v850_reloc (abfd
, reloc
, symbol
, data
, isection
, obfd
, err
)
307 if (obfd
!= (bfd
*) NULL
308 && (symbol
->flags
& BSF_SECTION_SYM
) == 0
309 && (! reloc
->howto
->partial_inplace
310 || reloc
->addend
== 0))
312 reloc
->address
+= isection
->output_offset
;
315 else if (obfd
!= NULL
)
317 return bfd_reloc_continue
;
320 /* Catch relocs involving undefined symbols. */
321 if (bfd_is_und_section (symbol
->section
)
322 && (symbol
->flags
& BSF_WEAK
) == 0
324 return bfd_reloc_undefined
;
326 /* We handle final linking of some relocs ourselves. */
328 long relocation
, insn
;
330 /* Is the address of the relocation really within the section? */
331 if (reloc
->address
> isection
->_cooked_size
)
332 return bfd_reloc_outofrange
;
334 /* Work out which section the relocation is targetted at and the
335 initial relocation command value. */
337 /* Get symbol value. (Common symbols are special.) */
338 if (bfd_is_com_section (symbol
->section
))
341 relocation
= symbol
->value
;
343 /* Convert input-section-relative symbol value to absolute + addend. */
344 relocation
+= symbol
->section
->output_section
->vma
;
345 relocation
+= symbol
->section
->output_offset
;
346 relocation
+= reloc
->addend
;
348 if (reloc
->howto
->pc_relative
== true)
350 /* Here the variable relocation holds the final address of the
351 symbol we are relocating against, plus any addend. */
352 relocation
-= isection
->output_section
->vma
+ isection
->output_offset
;
354 /* Deal with pcrel_offset */
355 relocation
-= reloc
->address
;
358 /* I've got no clue... */
361 if (reloc
->howto
->type
== R_V850_22_PCREL
)
363 if (relocation
> 0x1ffff || relocation
< -0x200000)
364 return bfd_reloc_overflow
;
366 if ((relocation
% 2) != 0)
367 return bfd_reloc_dangerous
;
369 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
371 insn
|= (((relocation
& 0xfffe) << 16)
372 | ((relocation
& 0x3f0000) >> 16));
373 bfd_put_32 (abfd
, insn
, (bfd_byte
*)data
+ reloc
->address
);
376 else if (reloc
->howto
->type
== R_V850_9_PCREL
)
378 if (relocation
> 0xff || relocation
< -0x100)
379 return bfd_reloc_overflow
;
381 if ((relocation
% 2) != 0)
382 return bfd_reloc_dangerous
;
384 insn
= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
386 insn
|= ((relocation
& 0x1f0) << 7) | ((relocation
& 0x0e) << 3);
387 bfd_put_16 (abfd
, insn
, (bfd_byte
*)data
+ reloc
->address
);
390 else if (reloc
->howto
->type
== R_V850_HI16_S
)
392 relocation
+= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
393 relocation
= (relocation
>> 16) + ((relocation
& 0x8000) != 0);
394 bfd_put_16 (abfd
, relocation
, (bfd_byte
*)data
+ reloc
->address
);
397 else if (reloc
->howto
->type
== R_V850_HI16
)
399 relocation
+= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
400 relocation
= (relocation
>> 16);
401 bfd_put_16 (abfd
, relocation
, (bfd_byte
*)data
+ reloc
->address
);
405 return bfd_reloc_notsupported
;
408 return bfd_reloc_continue
;
411 static boolean bfd_elf32_v850_is_local_label
PARAMS ((bfd
*, asymbol
*));
415 bfd_elf32_v850_is_local_label (abfd
, symbol
)
419 return ((symbol
->name
[0] == '.' && (symbol
->name
[1] == 'L' || symbol
->name
[1] == '.'))
420 || (symbol
->name
[0] == '_' && symbol
->name
[1] == '.' && symbol
->name
[2] == 'L'
421 && symbol
->name
[3] == '_'));
424 /* Perform a relocation as part of a final link. */
425 static bfd_reloc_status_type
426 elf32_v850_bfd_final_link_relocate (howto
, input_bfd
, output_bfd
,
427 input_section
, contents
, offset
, value
,
428 addend
, info
, sym_sec
, is_local
)
429 reloc_howto_type
*howto
;
432 asection
*input_section
;
437 struct bfd_link_info
*info
;
442 unsigned long r_type
= howto
->type
;
443 unsigned long r_format
= howto
->bitsize
;
444 bfd_byte
*hit_data
= contents
+ offset
;
445 boolean r_pcrel
= howto
->pc_relative
;
450 value
-= (input_section
->output_section
->vma
451 + input_section
->output_offset
);
454 if ((long)value
> 0xff || (long)value
< -0x100)
455 return bfd_reloc_overflow
;
457 if ((value
% 2) != 0)
458 return bfd_reloc_dangerous
;
460 insn
= bfd_get_16 (input_bfd
, hit_data
);
462 insn
|= ((value
& 0x1f0) << 7) | ((value
& 0x0e) << 3);
463 bfd_put_16 (input_bfd
, insn
, hit_data
);
466 case R_V850_22_PCREL
:
467 value
-= (input_section
->output_section
->vma
468 + input_section
->output_offset
);
471 if ((long)value
> 0x1ffff || (long)value
< -0x200000)
472 return bfd_reloc_overflow
;
474 if ((value
% 2) != 0)
475 return bfd_reloc_dangerous
;
477 insn
= bfd_get_32 (input_bfd
, hit_data
);
479 insn
|= (((value
& 0xfffe) << 16) | ((value
& 0x3f0000) >> 16));
480 bfd_put_32 (input_bfd
, insn
, hit_data
);
484 value
+= bfd_get_16 (input_bfd
, hit_data
);
485 value
= (value
>> 16) + ((value
& 0x8000) != 0);
487 if ((long)value
> 0x7fff || (long)value
< -0x8000)
488 return bfd_reloc_overflow
;
490 bfd_put_16 (input_bfd
, value
, hit_data
);
494 value
+= bfd_get_16 (input_bfd
, hit_data
);
497 if ((long)value
> 0x7fff || (long)value
< -0x8000)
498 return bfd_reloc_overflow
;
500 bfd_put_16 (input_bfd
, value
, hit_data
);
504 value
+= bfd_get_16 (input_bfd
, hit_data
);
507 bfd_put_16 (input_bfd
, value
, hit_data
);
511 case R_V850_ZDA_OFFSET
:
512 value
+= bfd_get_16 (input_bfd
, hit_data
);
514 if ((long)value
> 0x7fff || (long)value
< -0x8000)
515 return bfd_reloc_overflow
;
517 bfd_put_16 (input_bfd
, value
, hit_data
);
521 value
+= bfd_get_32 (input_bfd
, hit_data
);
522 bfd_put_32 (input_bfd
, value
, hit_data
);
526 value
+= bfd_get_8 (input_bfd
, hit_data
);
528 if ((long)value
> 0x7f || (long)value
< -0x80)
529 return bfd_reloc_overflow
;
531 bfd_put_8 (input_bfd
, value
, hit_data
);
534 case R_V850_SDA_OFFSET
:
537 struct bfd_link_hash_entry
*h
;
539 value
+= bfd_get_16 (input_bfd
, hit_data
);
541 /* Get the value of __gp. */
542 h
= bfd_link_hash_lookup (info
->hash
, "__gp", false,
544 if (h
== (struct bfd_link_hash_entry
*) NULL
545 || h
->type
!= bfd_link_hash_defined
)
546 return bfd_reloc_undefined
;
549 + h
->u
.def
.section
->output_section
->vma
550 + h
->u
.def
.section
->output_offset
);
553 if ((long)value
> 0x7fff || (long)value
< -0x8000)
554 return bfd_reloc_overflow
;
556 bfd_put_16 (input_bfd
, value
, hit_data
);
560 case R_V850_TDA_OFFSET
:
563 struct bfd_link_hash_entry
*h
;
565 value
+= bfd_get_16 (input_bfd
, hit_data
);
567 /* Get the value of __ep. */
568 h
= bfd_link_hash_lookup (info
->hash
, "__ep", false,
570 if (h
== (struct bfd_link_hash_entry
*) NULL
571 || h
->type
!= bfd_link_hash_defined
)
572 return bfd_reloc_undefined
;
575 + h
->u
.def
.section
->output_section
->vma
576 + h
->u
.def
.section
->output_offset
);
580 if ((long)value
> 0x7fff || (long)value
< -0x8000)
581 return bfd_reloc_overflow
;
583 bfd_put_16 (input_bfd
, value
, hit_data
);
594 /* Relocate an V850 ELF section. */
597 v850_elf_relocate_section (output_bfd
, info
, input_bfd
, input_section
,
598 contents
, relocs
, local_syms
, local_sections
)
600 struct bfd_link_info
*info
;
602 asection
*input_section
;
604 Elf_Internal_Rela
*relocs
;
605 Elf_Internal_Sym
*local_syms
;
606 asection
**local_sections
;
608 Elf_Internal_Shdr
*symtab_hdr
;
609 struct elf_link_hash_entry
**sym_hashes
;
610 Elf_Internal_Rela
*rel
, *relend
;
612 symtab_hdr
= &elf_tdata (input_bfd
)->symtab_hdr
;
613 sym_hashes
= elf_sym_hashes (input_bfd
);
616 relend
= relocs
+ input_section
->reloc_count
;
617 for (; rel
< relend
; rel
++)
620 reloc_howto_type
*howto
;
621 unsigned long r_symndx
;
622 Elf_Internal_Sym
*sym
;
624 struct elf_link_hash_entry
*h
;
626 bfd_reloc_status_type r
;
628 if (info
->relocateable
)
630 /* This is a relocateable link. We don't have to change
631 anything, unless the reloc is against a section symbol,
632 in which case we have to adjust according to where the
633 section symbol winds up in the output section. */
634 if (r_symndx
< symtab_hdr
->sh_info
)
636 sym
= local_syms
+ r_symndx
;
637 if (ELF_ST_TYPE (sym
->st_info
) == STT_SECTION
)
639 sec
= local_sections
[r_symndx
];
640 rel
->r_addend
+= sec
->output_offset
+ sym
->st_value
;
647 r_type
= ELF32_R_TYPE (rel
->r_info
);
649 howto
= elf_v850_howto_table
+ r_type
;
651 r_symndx
= ELF32_R_SYM (rel
->r_info
);
653 /* This is a final link. */
657 if (r_symndx
< symtab_hdr
->sh_info
)
659 sym
= local_syms
+ r_symndx
;
660 sec
= local_sections
[r_symndx
];
661 relocation
= (sec
->output_section
->vma
667 h
= sym_hashes
[r_symndx
- symtab_hdr
->sh_info
];
668 while (h
->root
.type
== bfd_link_hash_indirect
669 || h
->root
.type
== bfd_link_hash_warning
)
670 h
= (struct elf_link_hash_entry
*) h
->root
.u
.i
.link
;
671 if (h
->root
.type
== bfd_link_hash_defined
672 || h
->root
.type
== bfd_link_hash_defweak
)
674 sec
= h
->root
.u
.def
.section
;
675 relocation
= (h
->root
.u
.def
.value
676 + sec
->output_section
->vma
677 + sec
->output_offset
);
679 else if (h
->root
.type
== bfd_link_hash_undefweak
)
683 if (! ((*info
->callbacks
->undefined_symbol
)
684 (info
, h
->root
.root
.string
, input_bfd
,
685 input_section
, rel
->r_offset
)))
691 /* FIXME: We should use the addend, but the COFF relocations
693 r
= elf32_v850_bfd_final_link_relocate (howto
, input_bfd
, output_bfd
,
695 contents
, rel
->r_offset
,
696 relocation
, rel
->r_addend
,
697 info
, sec
, h
== NULL
);
699 if (r
!= bfd_reloc_ok
)
704 case bfd_reloc_outofrange
:
706 case bfd_reloc_overflow
:
711 name
= h
->root
.root
.string
;
714 name
= (bfd_elf_string_from_elf_section
715 (input_bfd
, symtab_hdr
->sh_link
, sym
->st_name
));
719 name
= bfd_section_name (input_bfd
, sec
);
721 if (! ((*info
->callbacks
->reloc_overflow
)
722 (info
, name
, howto
->name
, (bfd_vma
) 0,
723 input_bfd
, input_section
, rel
->r_offset
)))
733 #define bfd_elf32_bfd_is_local_label bfd_elf32_v850_is_local_label
735 #define TARGET_LITTLE_SYM bfd_elf32_v850_vec
736 #define TARGET_LITTLE_NAME "elf32-v850"
737 #define ELF_ARCH bfd_arch_v850
738 #define ELF_MACHINE_CODE EM_CYGNUS_V850
739 #define ELF_MAXPAGESIZE 0x1000
741 #define elf_info_to_howto 0
742 #define elf_info_to_howto_rel v850_info_to_howto_rel
743 #define elf_backend_relocate_section v850_elf_relocate_section
746 #define elf_symbol_leading_char '_'
748 #include "elf32-target.h"