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. */
25 static reloc_howto_type
*bfd_elf32_bfd_reloc_type_lookup
26 PARAMS ((bfd
*abfd
, bfd_reloc_code_real_type code
));
27 static void v850_info_to_howto_rel
28 PARAMS ((bfd
*, arelent
*, Elf32_Internal_Rel
*));
29 static bfd_reloc_status_type bfd_elf32_v850_reloc
30 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
34 /* Try to minimize the amount of space occupied by relocation tables
35 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
52 static reloc_howto_type elf_v850_howto_table
[] =
54 /* This reloc does nothing. */
55 HOWTO (R_V850_NONE
, /* type */
57 2, /* 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_V850_NONE", /* name */
64 false, /* partial_inplace */
67 false), /* pcrel_offset */
69 /* A PC relative 9 bit branch. */
70 HOWTO (R_V850_9_PCREL
, /* type */
72 2, /* size (0 = byte, 1 = short, 2 = long) */
74 true, /* pc_relative */
76 complain_overflow_bitfield
, /* complain_on_overflow */
77 bfd_elf32_v850_reloc
, /* special_function */
78 "R_V850_9_PCREL", /* name */
79 false, /* partial_inplace */
80 0x00ffffff, /* src_mask */
81 0x00ffffff, /* dst_mask */
82 true), /* pcrel_offset */
84 /* A PC relative 22 bit branch. */
85 HOWTO (R_V850_22_PCREL
, /* type */
87 2, /* size (0 = byte, 1 = short, 2 = long) */
89 true, /* pc_relative */
91 complain_overflow_signed
, /* complain_on_overflow */
92 bfd_elf32_v850_reloc
, /* special_function */
93 "R_V850_22_PCREL", /* name */
94 false, /* partial_inplace */
95 0x07ffff80, /* src_mask */
96 0x07ffff80, /* dst_mask */
97 true), /* pcrel_offset */
99 /* High 16 bits of symbol value. */
100 HOWTO (R_V850_HI16_S
, /* type */
102 1, /* size (0 = byte, 1 = short, 2 = long) */
104 false, /* pc_relative */
106 complain_overflow_dont
,/* complain_on_overflow */
107 bfd_elf32_v850_reloc
, /* special_function */
108 "R_V850_HI16_S", /* name */
109 true, /* partial_inplace */
110 0xffff, /* src_mask */
111 0xffff, /* dst_mask */
112 false), /* pcrel_offset */
114 /* High 16 bits of symbol value. */
115 HOWTO (R_V850_HI16
, /* type */
117 1, /* size (0 = byte, 1 = short, 2 = long) */
119 false, /* pc_relative */
121 complain_overflow_dont
,/* complain_on_overflow */
122 bfd_elf32_v850_reloc
, /* special_function */
123 "R_V850_HI16", /* name */
124 true, /* partial_inplace */
125 0xffff, /* src_mask */
126 0xffff, /* dst_mask */
127 false), /* pcrel_offset */
129 /* Low 16 bits of symbol value. */
130 HOWTO (R_V850_LO16
, /* type */
132 1, /* size (0 = byte, 1 = short, 2 = long) */
134 false, /* pc_relative */
136 complain_overflow_dont
,/* complain_on_overflow */
137 bfd_elf_generic_reloc
, /* special_function */
138 "R_V850_LO16", /* name */
139 true, /* partial_inplace */
140 0xffff, /* src_mask */
141 0xffff, /* dst_mask */
142 false), /* pcrel_offset */
144 /* Simple 32bit reloc. */
145 HOWTO (R_V850_32
, /* type */
147 2, /* size (0 = byte, 1 = short, 2 = long) */
149 false, /* pc_relative */
151 complain_overflow_dont
,/* complain_on_overflow */
152 bfd_elf_generic_reloc
, /* special_function */
153 "R_V850_32", /* name */
154 true, /* partial_inplace */
155 0xffffffff, /* src_mask */
156 0xffffffff, /* dst_mask */
157 false), /* pcrel_offset */
159 /* Simple 16bit reloc. */
160 HOWTO (R_V850_16
, /* type */
162 1, /* size (0 = byte, 1 = short, 2 = long) */
164 false, /* pc_relative */
166 complain_overflow_dont
,/* complain_on_overflow */
167 bfd_elf_generic_reloc
, /* special_function */
168 "R_V850_16", /* name */
169 true, /* partial_inplace */
170 0xffff, /* src_mask */
171 0xffff, /* dst_mask */
172 false), /* pcrel_offset */
174 /* Simple 8bit reloc. */
175 HOWTO (R_V850_8
, /* type */
177 0, /* size (0 = byte, 1 = short, 2 = long) */
179 false, /* pc_relative */
181 complain_overflow_dont
,/* complain_on_overflow */
182 bfd_elf_generic_reloc
, /* special_function */
183 "R_V850_8", /* name */
184 true, /* partial_inplace */
187 false), /* pcrel_offset */
190 /* Map BFD reloc types to V850 ELF reloc types. */
192 struct v850_reloc_map
194 unsigned char bfd_reloc_val
;
195 unsigned char elf_reloc_val
;
198 static const struct v850_reloc_map v850_reloc_map
[] =
200 { BFD_RELOC_NONE
, R_V850_NONE
, },
201 { BFD_RELOC_V850_9_PCREL
, R_V850_9_PCREL
, },
202 { BFD_RELOC_V850_22_PCREL
, R_V850_22_PCREL
, },
203 { BFD_RELOC_HI16_S
, R_V850_HI16_S
, },
204 { BFD_RELOC_HI16
, R_V850_HI16
, },
205 { BFD_RELOC_LO16
, R_V850_LO16
, },
206 { BFD_RELOC_32
, R_V850_32
, },
207 { BFD_RELOC_16
, R_V850_16
, },
208 { BFD_RELOC_8
, R_V850_8
, },
211 static reloc_howto_type
*
212 bfd_elf32_bfd_reloc_type_lookup (abfd
, code
)
214 bfd_reloc_code_real_type code
;
219 i
< sizeof (v850_reloc_map
) / sizeof (struct v850_reloc_map
);
222 if (v850_reloc_map
[i
].bfd_reloc_val
== code
)
223 return &elf_v850_howto_table
[v850_reloc_map
[i
].elf_reloc_val
];
229 /* Set the howto pointer for an V850 ELF reloc. */
232 v850_info_to_howto_rel (abfd
, cache_ptr
, dst
)
235 Elf32_Internal_Rel
*dst
;
239 r_type
= ELF32_R_TYPE (dst
->r_info
);
240 BFD_ASSERT (r_type
< (unsigned int) R_V850_max
);
241 cache_ptr
->howto
= &elf_v850_howto_table
[r_type
];
244 static bfd_reloc_status_type
245 bfd_elf32_v850_reloc (abfd
, reloc
, symbol
, data
, isection
, obfd
, err
)
254 if (obfd
!= (bfd
*) NULL
255 && (symbol
->flags
& BSF_SECTION_SYM
) == 0
256 && (! reloc
->howto
->partial_inplace
257 || reloc
->addend
== 0))
259 reloc
->address
+= isection
->output_offset
;
262 else if (obfd
!= NULL
)
264 return bfd_reloc_continue
;
267 /* We handle final linking of some relocs ourselves. */
269 long relocation
, insn
;
271 /* Is the address of the relocation really within the section? */
272 if (reloc
->address
> isection
->_cooked_size
)
273 return bfd_reloc_outofrange
;
275 /* Work out which section the relocation is targetted at and the
276 initial relocation command value. */
278 /* Get symbol value. (Common symbols are special.) */
279 if (bfd_is_com_section (symbol
->section
))
282 relocation
= symbol
->value
;
284 /* Convert input-section-relative symbol value to absolute + addend. */
285 relocation
+= symbol
->section
->output_section
->vma
;
286 relocation
+= symbol
->section
->output_offset
;
287 relocation
+= reloc
->addend
;
289 if (reloc
->howto
->pc_relative
== true)
291 /* Here the variable relocation holds the final address of the
292 symbol we are relocating against, plus any addend. */
293 relocation
-= isection
->output_section
->vma
+ isection
->output_offset
;
295 /* Deal with pcrel_offset */
296 relocation
-= reloc
->address
;
299 /* I've got no clue... */
302 if (reloc
->howto
->type
== R_V850_22_PCREL
)
304 if (relocation
> 0x1ffff || relocation
< -0x200000)
305 return bfd_reloc_overflow
;
307 if ((relocation
% 2) != 0)
308 return bfd_reloc_dangerous
;
310 insn
= bfd_get_32 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
311 insn
|= (((relocation
& 0xfffe) << 16)
312 | ((relocation
& 0x3f0000) >> 16));
313 bfd_put_32 (abfd
, insn
, (bfd_byte
*)data
+ reloc
->address
);
316 else if (reloc
->howto
->type
== R_V850_9_PCREL
)
318 if (relocation
> 0xff || relocation
< -0x100)
319 return bfd_reloc_overflow
;
321 if ((relocation
% 2) != 0)
322 return bfd_reloc_dangerous
;
324 insn
= bfd_get_16 (abfd
, (bfd_byte
*) data
+ reloc
->address
);
325 insn
|= ((relocation
& 0x1f0) << 7) | ((relocation
& 0x0e) << 3);
326 bfd_put_16 (abfd
, insn
, (bfd_byte
*)data
+ reloc
->address
);
329 else if (reloc
->howto
->type
== R_V850_HI16_S
)
331 relocation
= (relocation
>> 16) + ((relocation
& 0x8000) != 0);
332 bfd_put_16 (abfd
, relocation
, (bfd_byte
*)data
+ reloc
->address
);
335 else if (reloc
->howto
->type
== R_V850_HI16
)
337 relocation
= (relocation
>> 16);
338 bfd_put_16 (abfd
, relocation
, (bfd_byte
*)data
+ reloc
->address
);
343 return bfd_reloc_continue
;
346 #define TARGET_LITTLE_SYM bfd_elf32_v850_vec
347 #define TARGET_LITTLE_NAME "elf32-v850"
348 #define ELF_ARCH bfd_arch_v850
349 #define ELF_MACHINE_CODE EM_CYGNUS_V850
350 #define ELF_MAXPAGESIZE 0x1000
352 #define elf_info_to_howto 0
353 #define elf_info_to_howto_rel v850_info_to_howto_rel
355 #include "elf32-target.h"