* gas/v850/reloc.s: New tests.
[deliverable/binutils-gdb.git] / bfd / elf32-v850.c
CommitLineData
01b49cb3
C
1/* V850-specific support for 32-bit ELF
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4This file is part of BFD, the Binary File Descriptor library.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20#include "bfd.h"
21#include "sysdep.h"
22#include "libbfd.h"
23#include "elf-bfd.h"
24
25static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
26 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
27static void v850_info_to_howto_rel
28 PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
e73b6ae6
JL
29static bfd_reloc_status_type bfd_elf32_v850_reloc
30 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
31
01b49cb3
C
32
33
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). */
36#define USE_REL
37
38enum reloc_type
39{
40 R_V850_NONE = 0,
41 R_V850_9_PCREL,
42 R_V850_22_PCREL,
43 R_V850_HI16_S,
44 R_V850_HI16,
45 R_V850_LO16,
237b5c4c
JL
46 R_V850_32,
47 R_V850_16,
48 R_V850_8,
01b49cb3
C
49 R_V850_max
50};
51
52static reloc_howto_type elf_v850_howto_table[] =
53{
54 /* This reloc does nothing. */
55 HOWTO (R_V850_NONE, /* type */
56 0, /* rightshift */
57 2, /* size (0 = byte, 1 = short, 2 = long) */
58 32, /* bitsize */
59 false, /* pc_relative */
60 0, /* bitpos */
61 complain_overflow_bitfield, /* complain_on_overflow */
62 bfd_elf_generic_reloc, /* special_function */
63 "R_V850_NONE", /* name */
64 false, /* partial_inplace */
65 0, /* src_mask */
66 0, /* dst_mask */
67 false), /* pcrel_offset */
68
69 /* A PC relative 9 bit branch. */
70 HOWTO (R_V850_9_PCREL, /* type */
71 2, /* rightshift */
72 2, /* size (0 = byte, 1 = short, 2 = long) */
73 26, /* bitsize */
74 true, /* pc_relative */
75 0, /* bitpos */
76 complain_overflow_bitfield, /* complain_on_overflow */
e73b6ae6 77 bfd_elf32_v850_reloc, /* special_function */
01b49cb3
C
78 "R_V850_9_PCREL", /* name */
79 false, /* partial_inplace */
80 0x00ffffff, /* src_mask */
81 0x00ffffff, /* dst_mask */
82 true), /* pcrel_offset */
83
84 /* A PC relative 22 bit branch. */
85 HOWTO (R_V850_22_PCREL, /* type */
86 2, /* rightshift */
87 2, /* size (0 = byte, 1 = short, 2 = long) */
88 22, /* bitsize */
89 true, /* pc_relative */
90 7, /* bitpos */
91 complain_overflow_signed, /* complain_on_overflow */
e73b6ae6 92 bfd_elf32_v850_reloc, /* special_function */
01b49cb3
C
93 "R_V850_22_PCREL", /* name */
94 false, /* partial_inplace */
95 0x07ffff80, /* src_mask */
96 0x07ffff80, /* dst_mask */
97 true), /* pcrel_offset */
98
99 /* High 16 bits of symbol value. */
100 HOWTO (R_V850_HI16_S, /* type */
101 0, /* rightshift */
102 1, /* size (0 = byte, 1 = short, 2 = long) */
103 16, /* bitsize */
104 false, /* pc_relative */
e73b6ae6 105 0, /* bitpos */
01b49cb3 106 complain_overflow_dont,/* complain_on_overflow */
e73b6ae6 107 bfd_elf32_v850_reloc, /* special_function */
01b49cb3
C
108 "R_V850_HI16_S", /* name */
109 true, /* partial_inplace */
110 0xffff, /* src_mask */
111 0xffff, /* dst_mask */
112 false), /* pcrel_offset */
113
114 /* High 16 bits of symbol value. */
115 HOWTO (R_V850_HI16, /* type */
116 0, /* rightshift */
117 1, /* size (0 = byte, 1 = short, 2 = long) */
118 16, /* bitsize */
119 false, /* pc_relative */
e73b6ae6 120 0, /* bitpos */
01b49cb3 121 complain_overflow_dont,/* complain_on_overflow */
e73b6ae6 122 bfd_elf32_v850_reloc, /* special_function */
01b49cb3
C
123 "R_V850_HI16", /* name */
124 true, /* partial_inplace */
125 0xffff, /* src_mask */
126 0xffff, /* dst_mask */
127 false), /* pcrel_offset */
128
129 /* Low 16 bits of symbol value. */
130 HOWTO (R_V850_LO16, /* type */
131 0, /* rightshift */
132 1, /* size (0 = byte, 1 = short, 2 = long) */
133 16, /* bitsize */
134 false, /* pc_relative */
e73b6ae6 135 0, /* bitpos */
01b49cb3
C
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 */
237b5c4c
JL
143
144 /* Simple 32bit reloc. */
145 HOWTO (R_V850_32, /* type */
146 0, /* rightshift */
147 2, /* size (0 = byte, 1 = short, 2 = long) */
148 32, /* bitsize */
149 false, /* pc_relative */
150 0, /* bitpos */
151 complain_overflow_dont,/* complain_on_overflow */
152 bfd_elf_generic_reloc, /* special_function */
153 "R_V850_32", /* name */
e73b6ae6
JL
154 true, /* partial_inplace */
155 0xffffffff, /* src_mask */
237b5c4c
JL
156 0xffffffff, /* dst_mask */
157 false), /* pcrel_offset */
158
159 /* Simple 16bit reloc. */
160 HOWTO (R_V850_16, /* type */
161 0, /* rightshift */
162 1, /* size (0 = byte, 1 = short, 2 = long) */
163 16, /* bitsize */
164 false, /* pc_relative */
165 0, /* bitpos */
166 complain_overflow_dont,/* complain_on_overflow */
167 bfd_elf_generic_reloc, /* special_function */
168 "R_V850_16", /* name */
e73b6ae6
JL
169 true, /* partial_inplace */
170 0xffff, /* src_mask */
237b5c4c
JL
171 0xffff, /* dst_mask */
172 false), /* pcrel_offset */
173
174 /* Simple 8bit reloc. */
175 HOWTO (R_V850_8, /* type */
176 0, /* rightshift */
177 0, /* size (0 = byte, 1 = short, 2 = long) */
178 8, /* bitsize */
179 false, /* pc_relative */
180 0, /* bitpos */
181 complain_overflow_dont,/* complain_on_overflow */
182 bfd_elf_generic_reloc, /* special_function */
183 "R_V850_8", /* name */
e73b6ae6
JL
184 true, /* partial_inplace */
185 0xff, /* src_mask */
237b5c4c
JL
186 0xff, /* dst_mask */
187 false), /* pcrel_offset */
01b49cb3
C
188};
189
190/* Map BFD reloc types to V850 ELF reloc types. */
191
192struct v850_reloc_map
193{
194 unsigned char bfd_reloc_val;
195 unsigned char elf_reloc_val;
196};
197
198static const struct v850_reloc_map v850_reloc_map[] =
199{
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, },
237b5c4c
JL
206 { BFD_RELOC_32, R_V850_32, },
207 { BFD_RELOC_16, R_V850_16, },
208 { BFD_RELOC_8, R_V850_8, },
01b49cb3
C
209};
210
211static reloc_howto_type *
212bfd_elf32_bfd_reloc_type_lookup (abfd, code)
213 bfd *abfd;
214 bfd_reloc_code_real_type code;
215{
216 unsigned int i;
217
218 for (i = 0;
219 i < sizeof (v850_reloc_map) / sizeof (struct v850_reloc_map);
220 i++)
221 {
222 if (v850_reloc_map[i].bfd_reloc_val == code)
223 return &elf_v850_howto_table[v850_reloc_map[i].elf_reloc_val];
224 }
225
226 return NULL;
227}
228
229/* Set the howto pointer for an V850 ELF reloc. */
230
231static void
232v850_info_to_howto_rel (abfd, cache_ptr, dst)
233 bfd *abfd;
234 arelent *cache_ptr;
235 Elf32_Internal_Rel *dst;
236{
237 unsigned int r_type;
238
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];
242}
243
e73b6ae6
JL
244static bfd_reloc_status_type
245bfd_elf32_v850_reloc (abfd, reloc, symbol, data, isection, obfd, err)
246 bfd *abfd;
247 arelent *reloc;
248 asymbol *symbol;
249 PTR data;
250 asection *isection;
251 bfd *obfd;
252 char **err;
253{
254 if (obfd != (bfd *) NULL
255 && (symbol->flags & BSF_SECTION_SYM) == 0
256 && (! reloc->howto->partial_inplace
257 || reloc->addend == 0))
258 {
259 reloc->address += isection->output_offset;
260 return bfd_reloc_ok;
261 }
262 else if (obfd != NULL)
263 {
264 return bfd_reloc_continue;
265 }
266
05f1baaa
JL
267 /* Catch relocs involving undefined symbols. */
268 if (bfd_is_und_section (symbol->section)
269 && (symbol->flags & BSF_WEAK) == 0
270 && obfd == NULL)
271 return bfd_reloc_undefined;
272
e73b6ae6
JL
273 /* We handle final linking of some relocs ourselves. */
274 {
275 long relocation, insn;
276
277 /* Is the address of the relocation really within the section? */
278 if (reloc->address > isection->_cooked_size)
279 return bfd_reloc_outofrange;
280
281 /* Work out which section the relocation is targetted at and the
282 initial relocation command value. */
283
284 /* Get symbol value. (Common symbols are special.) */
285 if (bfd_is_com_section (symbol->section))
286 relocation = 0;
287 else
288 relocation = symbol->value;
289
290 /* Convert input-section-relative symbol value to absolute + addend. */
291 relocation += symbol->section->output_section->vma;
292 relocation += symbol->section->output_offset;
293 relocation += reloc->addend;
294
295 if (reloc->howto->pc_relative == true)
296 {
297 /* Here the variable relocation holds the final address of the
298 symbol we are relocating against, plus any addend. */
299 relocation -= isection->output_section->vma + isection->output_offset;
300
301 /* Deal with pcrel_offset */
302 relocation -= reloc->address;
303 }
304
305 /* I've got no clue... */
306 reloc->addend = 0;
307
308 if (reloc->howto->type == R_V850_22_PCREL)
309 {
310 if (relocation > 0x1ffff || relocation < -0x200000)
311 return bfd_reloc_overflow;
312
313 if ((relocation % 2) != 0)
314 return bfd_reloc_dangerous;
315
316 insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc->address);
e1d98a0a 317 insn &= ~0xfffe003f;
e73b6ae6
JL
318 insn |= (((relocation & 0xfffe) << 16)
319 | ((relocation & 0x3f0000) >> 16));
320 bfd_put_32 (abfd, insn, (bfd_byte *)data + reloc->address);
321 return bfd_reloc_ok;
322 }
323 else if (reloc->howto->type == R_V850_9_PCREL)
324 {
325 if (relocation > 0xff || relocation < -0x100)
326 return bfd_reloc_overflow;
327
328 if ((relocation % 2) != 0)
329 return bfd_reloc_dangerous;
330
331 insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
e1d98a0a 332 insn &= 0xf870;
e73b6ae6
JL
333 insn |= ((relocation & 0x1f0) << 7) | ((relocation & 0x0e) << 3);
334 bfd_put_16 (abfd, insn, (bfd_byte *)data + reloc->address);
335 return bfd_reloc_ok;
336 }
337 else if (reloc->howto->type == R_V850_HI16_S)
338 {
1336da39 339 relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
e73b6ae6
JL
340 relocation = (relocation >> 16) + ((relocation & 0x8000) != 0);
341 bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
342 return bfd_reloc_ok;
343 }
344 else if (reloc->howto->type == R_V850_HI16)
345 {
1336da39 346 relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc->address);
e73b6ae6
JL
347 relocation = (relocation >> 16);
348 bfd_put_16 (abfd, relocation, (bfd_byte *)data + reloc->address);
349 return bfd_reloc_ok;
350 }
351 }
352
353 return bfd_reloc_continue;
354}
355
1336da39
SG
356static boolean bfd_elf32_v850_is_local_label PARAMS ((bfd *, asymbol *));
357
358/*ARGSUSED*/
359static boolean
360bfd_elf32_v850_is_local_label (abfd, symbol)
361 bfd *abfd;
362 asymbol *symbol;
363{
364 return ((symbol->name[0] == '.' && (symbol->name[1] == 'L' || symbol->name[1] == '.'))
365 || (symbol->name[0] == '_' && symbol->name[1] == '.' && symbol->name[2] == 'L'
366 && symbol->name[3] == '_'));
367}
368
369#define bfd_elf32_bfd_is_local_label bfd_elf32_v850_is_local_label
370
e73b6ae6
JL
371#define TARGET_LITTLE_SYM bfd_elf32_v850_vec
372#define TARGET_LITTLE_NAME "elf32-v850"
01b49cb3
C
373#define ELF_ARCH bfd_arch_v850
374#define ELF_MACHINE_CODE EM_CYGNUS_V850
375#define ELF_MAXPAGESIZE 0x1000
376
377#define elf_info_to_howto 0
378#define elf_info_to_howto_rel v850_info_to_howto_rel
379
1336da39
SG
380#define elf_symbol_leading_char '_'
381
01b49cb3 382#include "elf32-target.h"
This page took 0.042184 seconds and 4 git commands to generate.