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"