gas/
[deliverable/binutils-gdb.git] / bfd / elf32-d30v.c
CommitLineData
252b5132 1/* D30V-specific support for 32-bit ELF
47b0e7ad 2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
82e51918 3 Free Software Foundation, Inc.
252b5132
RH
4 Contributed by Martin Hunt (hunt@cygnus.com).
5
47b0e7ad 6 This file is part of BFD, the Binary File Descriptor library.
252b5132 7
47b0e7ad
NC
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
252b5132 12
47b0e7ad
NC
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
252b5132 17
47b0e7ad
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
252b5132
RH
22
23#include "bfd.h"
24#include "sysdep.h"
25#include "libbfd.h"
26#include "elf-bfd.h"
1b452ec6 27#include "elf/d30v.h"
252b5132 28
fc633e5b
AM
29#define MAX32 ((bfd_signed_vma) 0x7fffffff)
30#define MIN32 (- MAX32 - 1)
252b5132
RH
31
32static bfd_reloc_status_type
47b0e7ad
NC
33bfd_elf_d30v_reloc (bfd *abfd,
34 arelent *reloc_entry,
35 asymbol *symbol,
36 void * data,
37 asection *input_section,
38 bfd *output_bfd,
39 char **error_message)
252b5132 40{
fc633e5b 41 bfd_signed_vma relocation;
252b5132
RH
42 bfd_vma in1, in2, num;
43 bfd_vma tmp_addr = 0;
44 bfd_reloc_status_type r;
45 asection *reloc_target_output_section;
46 bfd_size_type addr = reloc_entry->address;
47 bfd_reloc_status_type flag = bfd_reloc_ok;
48 bfd_vma output_base = 0;
49 reloc_howto_type *howto = reloc_entry->howto;
50 int make_absolute = 0;
51
47b0e7ad 52 if (output_bfd != NULL)
b51a1338
RH
53 {
54 /* Partial linking -- do nothing. */
55 reloc_entry->address += input_section->output_offset;
56 return bfd_reloc_ok;
57 }
58
252b5132
RH
59 r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
60 input_section, output_bfd, error_message);
61 if (r != bfd_reloc_continue)
a7c10850 62 return r;
252b5132 63
47b0e7ad 64 /* A hacked-up version of bfd_perform_reloc() follows. */
252b5132
RH
65 if (bfd_is_und_section (symbol->section)
66 && (symbol->flags & BSF_WEAK) == 0
47b0e7ad 67 && output_bfd == NULL)
252b5132
RH
68 flag = bfd_reloc_undefined;
69
70 /* Is the address of the relocation really within the section? */
07515404 71 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
252b5132
RH
72 return bfd_reloc_outofrange;
73
4cc11e76 74 /* Work out which section the relocation is targeted at and the
252b5132
RH
75 initial relocation command value. */
76
77 /* Get symbol value. (Common symbols are special.) */
78 if (bfd_is_com_section (symbol->section))
79 relocation = 0;
80 else
81 relocation = symbol->value;
82
83 reloc_target_output_section = symbol->section->output_section;
84
85 /* Convert input-section-relative symbol value to absolute. */
b51a1338 86 output_base = reloc_target_output_section->vma;
252b5132
RH
87 relocation += output_base + symbol->section->output_offset;
88
89 /* Add in supplied addend. */
90 relocation += reloc_entry->addend;
91
92 /* Here the variable relocation holds the final address of the
93 symbol we are relocating against, plus any addend. */
82e51918 94 if (howto->pc_relative)
252b5132 95 {
47b0e7ad
NC
96 tmp_addr = input_section->output_section->vma
97 + input_section->output_offset
252b5132
RH
98 + reloc_entry->address;
99 relocation -= tmp_addr;
100 }
a7c10850 101
252b5132
RH
102 in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
103 in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
104
47b0e7ad 105 /* Extract the addend. */
252b5132
RH
106 num = ((in2 & 0x3FFFF)
107 | ((in2 & 0xFF00000) >> 2)
108 | ((in1 & 0x3F) << 26));
109 in1 &= 0xFFFFFFC0;
110 in2 = 0x80000000;
a7c10850 111
252b5132
RH
112 relocation += num;
113
82e51918 114 if (howto->pc_relative && howto->bitsize == 32)
252b5132 115 {
fc633e5b
AM
116 /* The D30V has a PC that doesn't wrap and PC-relative jumps are
117 signed, so a PC-relative jump can't be more than +/- 2^31 bytes.
118 If one exceeds this, change it to an absolute jump. */
119 if (relocation > MAX32 || relocation < MIN32)
252b5132
RH
120 {
121 relocation = (relocation + tmp_addr) & 0xffffffff;
122 make_absolute = 1;
123 }
124 }
a7c10850 125
47b0e7ad
NC
126 in1 |= (relocation >> 26) & 0x3F; /* Top 6 bits. */
127 in2 |= ((relocation & 0x03FC0000) << 2); /* Next 8 bits. */
128 in2 |= relocation & 0x0003FFFF; /* Bottom 18 bits. */
a7c10850 129
47b0e7ad
NC
130 /* Change a PC-relative instruction to its
131 absolute equivalent with this simple hack. */
252b5132
RH
132 if (make_absolute)
133 in1 |= 0x00100000;
134
135 bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
136 bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4);
252b5132 137
a7c10850
KH
138 return flag;
139}
252b5132
RH
140
141static bfd_reloc_status_type
47b0e7ad
NC
142bfd_elf_d30v_reloc_21 (bfd *abfd,
143 arelent *reloc_entry,
144 asymbol *symbol,
145 void * data,
146 asection *input_section,
147 bfd *output_bfd,
148 char **error_message)
252b5132
RH
149{
150 bfd_vma relocation;
151 bfd_vma in1, num;
152 bfd_reloc_status_type r;
153 asection *reloc_target_output_section;
154 bfd_size_type addr = reloc_entry->address;
155 bfd_reloc_status_type flag = bfd_reloc_ok;
156 bfd_vma output_base = 0;
157 reloc_howto_type *howto = reloc_entry->howto;
158 int mask, max;
159
47b0e7ad 160 if (output_bfd != NULL)
b51a1338
RH
161 {
162 /* Partial linking -- do nothing. */
163 reloc_entry->address += input_section->output_offset;
164 return bfd_reloc_ok;
165 }
a7c10850 166
252b5132
RH
167 r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
168 input_section, output_bfd, error_message);
169 if (r != bfd_reloc_continue)
a7c10850 170 return r;
252b5132 171
47b0e7ad
NC
172 /* A hacked-up version of bfd_perform_reloc() follows. */
173 if (bfd_is_und_section (symbol->section)
252b5132 174 && (symbol->flags & BSF_WEAK) == 0
47b0e7ad 175 && output_bfd == NULL)
252b5132
RH
176 flag = bfd_reloc_undefined;
177
178 /* Is the address of the relocation really within the section? */
07515404 179 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
252b5132
RH
180 return bfd_reloc_outofrange;
181
4cc11e76 182 /* Work out which section the relocation is targeted at and the
252b5132
RH
183 initial relocation command value. */
184
185 /* Get symbol value. (Common symbols are special.) */
186 if (bfd_is_com_section (symbol->section))
187 relocation = 0;
188 else
189 relocation = symbol->value;
190
191 reloc_target_output_section = symbol->section->output_section;
192
193 /* Convert input-section-relative symbol value to absolute. */
b51a1338 194 output_base = reloc_target_output_section->vma;
252b5132
RH
195 relocation += output_base + symbol->section->output_offset;
196
197 /* Add in supplied addend. */
198 relocation += reloc_entry->addend;
199
200 /* Here the variable relocation holds the final address of the
201 symbol we are relocating against, plus any addend. */
202
82e51918 203 if (howto->pc_relative)
252b5132 204 {
b51a1338
RH
205 relocation -= (input_section->output_section->vma
206 + input_section->output_offset);
82e51918 207 if (howto->pcrel_offset)
252b5132
RH
208 relocation -= reloc_entry->address;
209 }
210
252b5132
RH
211 in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
212
213 mask = (1 << howto->bitsize) - 1;
214 if (howto->bitsize == 6)
215 mask <<= 12;
216 max = (1 << (howto->bitsize + 2)) - 1;
217
47b0e7ad
NC
218 /* Extract the addend. */
219 num = in1 & mask; /* 18 bits. */
252b5132
RH
220 if (howto->bitsize == 6)
221 num >>= 12;
47b0e7ad
NC
222 num <<= 3; /* shift left 3. */
223 in1 &= ~mask; /* Mask out addend. */
252b5132
RH
224
225 relocation += num;
47b0e7ad
NC
226 if (howto->type == R_D30V_21_PCREL_R
227 || howto->type == R_D30V_15_PCREL_R
228 || howto->type == R_D30V_9_PCREL_R)
229 relocation += 4;
252b5132 230
47b0e7ad 231 if ((int) relocation < 0)
252b5132 232 {
47b0e7ad 233 if (~ (int) relocation > max)
252b5132
RH
234 flag = bfd_reloc_overflow;
235 }
236 else
237 {
47b0e7ad 238 if ((int) relocation > max)
252b5132
RH
239 flag = bfd_reloc_overflow;
240 }
47b0e7ad 241
a7c10850 242 relocation >>= 3;
252b5132
RH
243 if (howto->bitsize == 6)
244 in1 |= ((relocation & (mask >> 12)) << 12);
245 else
246 in1 |= relocation & mask;
247
248 bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
a7c10850 249
252b5132 250 return flag;
a7c10850 251}
252b5132 252
47b0e7ad
NC
253static reloc_howto_type elf_d30v_howto_table[] =
254{
255 /* This reloc does nothing. */
256 HOWTO (R_D30V_NONE, /* Type. */
257 0, /* Rightshift. */
258 2, /* Size (0 = byte, 1 = short, 2 = long). */
259 32, /* Bitsize. */
260 FALSE, /* PC_relative. */
261 0, /* Bitpos. */
262 complain_overflow_bitfield, /* Complain_on_overflow. */
263 bfd_elf_generic_reloc, /* Special_function. */
264 "R_D30V_NONE", /* Name. */
265 FALSE, /* Partial_inplace. */
266 0, /* Src_mask. */
267 0, /* Dst_mask. */
268 FALSE), /* PCrel_offset. */
269
270 /* A 6 bit absolute relocation. */
271 HOWTO (R_D30V_6, /* Type. */
272 0, /* Rightshift. */
273 2, /* Size (0 = byte, 1 = short, 2 = long). */
274 6, /* Bitsize. */
275 FALSE, /* PC_relative. */
276 0, /* Bitpos. */
277 complain_overflow_bitfield, /* Complain_on_overflow. */
278 bfd_elf_generic_reloc, /* Special_function. */
279 "R_D30V_6", /* Name. */
280 FALSE, /* Partial_inplace. */
281 0x3f, /* Src_mask. */
282 0x3f, /* Dst_mask. */
283 FALSE), /* PCrel_offset. */
284
285 /* A relative 9 bit relocation, right shifted by 3. */
286 HOWTO (R_D30V_9_PCREL, /* Type. */
287 3, /* Rightshift. */
288 2, /* Size (0 = byte, 1 = short, 2 = long). */
289 6, /* Bitsize. */
290 TRUE, /* PC_relative. */
291 0, /* Bitpos. */
292 complain_overflow_signed, /* Complain_on_overflow. */
293 bfd_elf_d30v_reloc_21, /* Special_function. */
294 "R_D30V_9_PCREL", /* Name. */
295 FALSE, /* Partial_inplace. */
296 0x3f, /* Src_mask. */
297 0x3f, /* Dst_mask. */
298 TRUE), /* PCrel_offset. */
299
300 /* A relative 9 bit relocation, right shifted by 3. */
301 HOWTO (R_D30V_9_PCREL_R, /* Type. */
302 3, /* Rightshift. */
303 2, /* Size (0 = byte, 1 = short, 2 = long). */
304 6, /* Bitsize. */
305 TRUE, /* PC_relative. */
306 0, /* Bitpos. */
307 complain_overflow_signed, /* Complain_on_overflow. */
308 bfd_elf_d30v_reloc_21, /* Special_function. */
309 "R_D30V_9_PCREL_R", /* Name. */
310 FALSE, /* Partial_inplace. */
311 0x3f, /* Src_mask. */
312 0x3f, /* Dst_mask. */
313 TRUE), /* PCrel_offset. */
314
315 /* An absolute 15 bit relocation, right shifted by 3. */
316 HOWTO (R_D30V_15, /* Type. */
317 3, /* Rightshift. */
318 2, /* Size (0 = byte, 1 = short, 2 = long). */
319 12, /* Bitsize. */
320 FALSE, /* PC_relative. */
321 0, /* Bitpos. */
322 complain_overflow_signed, /* Complain_on_overflow. */
323 bfd_elf_generic_reloc, /* Special_function. */
324 "R_D30V_15", /* Name. */
325 FALSE, /* Partial_inplace. */
326 0xfff, /* Src_mask. */
327 0xfff, /* Dst_mask. */
328 FALSE), /* PCrel_offset. */
329
330 /* A relative 15 bit relocation, right shifted by 3. */
331 HOWTO (R_D30V_15_PCREL, /* Type. */
332 3, /* Rightshift. */
333 2, /* Size (0 = byte, 1 = short, 2 = long). */
334 12, /* Bitsize. */
335 TRUE, /* PC_relative. */
336 0, /* Bitpos. */
337 complain_overflow_signed, /* Complain_on_overflow. */
338 bfd_elf_d30v_reloc_21, /* Special_function. */
339 "R_D30V_15_PCREL", /* Name. */
340 FALSE, /* Partial_inplace. */
341 0xfff, /* Src_mask. */
342 0xfff, /* Dst_mask. */
343 TRUE), /* PCrel_offset. */
344
345 /* A relative 15 bit relocation, right shifted by 3. */
346 HOWTO (R_D30V_15_PCREL_R, /* Type. */
347 3, /* Rightshift. */
348 2, /* Size (0 = byte, 1 = short, 2 = long). */
349 12, /* Bitsize. */
350 TRUE, /* PC_relative. */
351 0, /* Bitpos. */
352 complain_overflow_signed, /* Complain_on_overflow. */
353 bfd_elf_d30v_reloc_21, /* Special_function. */
354 "R_D30V_15_PCREL_R", /* Name. */
355 FALSE, /* Partial_inplace. */
356 0xfff, /* Src_mask. */
357 0xfff, /* Dst_mask. */
358 TRUE), /* PCrel_offset. */
359
360 /* An absolute 21 bit relocation, right shifted by 3. */
361 HOWTO (R_D30V_21, /* Type. */
362 3, /* Rightshift. */
363 2, /* Size (0 = byte, 1 = short, 2 = long). */
364 18, /* Bitsize. */
365 FALSE, /* PC_relative. */
366 0, /* Bitpos. */
367 complain_overflow_signed, /* Complain_on_overflow. */
368 bfd_elf_generic_reloc, /* Special_function. */
369 "R_D30V_21", /* Name. */
370 FALSE, /* Partial_inplace. */
371 0x3ffff, /* Src_mask. */
372 0x3ffff, /* Dst_mask. */
373 FALSE), /* PCrel_offset. */
374
375 /* A relative 21 bit relocation, right shifted by 3. */
376 HOWTO (R_D30V_21_PCREL, /* Type. */
377 3, /* Rightshift. */
378 2, /* Size (0 = byte, 1 = short, 2 = long). */
379 18, /* Bitsize. */
380 TRUE, /* PC_relative. */
381 0, /* Bitpos. */
382 complain_overflow_signed, /* Complain_on_overflow. */
383 bfd_elf_d30v_reloc_21, /* Special_function. */
384 "R_D30V_21_PCREL", /* Name. */
385 FALSE, /* Partial_inplace. */
386 0x3ffff, /* Src_mask. */
387 0x3ffff, /* Dst_mask. */
388 TRUE), /* PCrel_offset. */
389
390 /* A relative 21 bit relocation, right shifted by 3, in the Right container. */
391 HOWTO (R_D30V_21_PCREL_R, /* Type. */
392 3, /* Rightshift. */
393 2, /* Size (0 = byte, 1 = short, 2 = long). */
394 18, /* Bitsize. */
395 TRUE, /* PC_relative. */
396 0, /* Bitpos. */
397 complain_overflow_signed, /* Complain_on_overflow. */
398 bfd_elf_d30v_reloc_21, /* Special_function. */
399 "R_D30V_21_PCREL_R", /* Name. */
400 FALSE, /* Partial_inplace. */
401 0x3ffff, /* Src_mask. */
402 0x3ffff, /* Dst_mask. */
403 TRUE), /* PCrel_offset. */
404
405 /* A D30V 32 bit absolute relocation. */
406 HOWTO (R_D30V_32, /* Type. */
407 0, /* Rightshift. */
408 4, /* Size (0 = byte, 1 = short, 2 = long). */
409 32, /* Bitsize. */
410 FALSE, /* PC_relative. */
411 0, /* Bitpos. */
412 complain_overflow_bitfield, /* Complain_on_overflow. */
413 bfd_elf_d30v_reloc, /* Special_function. */
414 "R_D30V_32", /* Name. */
415 FALSE, /* Partial_inplace. */
416 0xffffffff, /* Src_mask. */
417 0xffffffff, /* Dst_mask. */
418 FALSE), /* PCrel_offset. */
419
420 /* A relative 32 bit relocation. */
421 HOWTO (R_D30V_32_PCREL, /* Type. */
422 0, /* Rightshift. */
423 4, /* Size (0 = byte, 1 = short, 2 = long). */
424 32, /* Bitsize. */
425 TRUE, /* PC_relative. */
426 0, /* Bitpos. */
427 complain_overflow_signed, /* Complain_on_overflow. */
428 bfd_elf_d30v_reloc, /* Special_function. */
429 "R_D30V_32_PCREL", /* Name. */
430 FALSE, /* Partial_inplace. */
431 0xffffffff, /* Src_mask. */
432 0xffffffff, /* Dst_mask. */
433 TRUE), /* PCrel_offset. */
434
435 /* A regular 32 bit absolute relocation. */
436 HOWTO (R_D30V_32_NORMAL, /* Type. */
437 0, /* Rightshift. */
438 2, /* Size (0 = byte, 1 = short, 2 = long). */
439 32, /* Bitsize. */
440 FALSE, /* PC_relative. */
441 0, /* Bitpos. */
442 complain_overflow_bitfield, /* Complain_on_overflow. */
443 bfd_elf_generic_reloc, /* Special_function. */
444 "R_D30V_32_NORMAL", /* Name. */
445 FALSE, /* Partial_inplace. */
446 0xffffffff, /* Src_mask. */
447 0xffffffff, /* Dst_mask. */
448 FALSE), /* PCrel_offset. */
449
450};
451
252b5132
RH
452/* Map BFD reloc types to D30V ELF reloc types. */
453
454struct d30v_reloc_map
455{
456 bfd_reloc_code_real_type bfd_reloc_val;
457 unsigned char elf_reloc_val;
458};
459
252b5132
RH
460static const struct d30v_reloc_map d30v_reloc_map[] =
461{
462 { BFD_RELOC_NONE, R_D30V_NONE, },
463 { BFD_RELOC_D30V_6, R_D30V_6 },
464 { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL },
465 { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R },
466 { BFD_RELOC_D30V_15, R_D30V_15 },
467 { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL },
468 { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R },
469 { BFD_RELOC_D30V_21, R_D30V_21 },
470 { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL },
471 { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R },
472 { BFD_RELOC_D30V_32, R_D30V_32 },
473 { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL },
474 { BFD_RELOC_32, R_D30V_32_NORMAL },
475};
476
477static reloc_howto_type *
47b0e7ad
NC
478bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
479 bfd_reloc_code_real_type code)
252b5132
RH
480{
481 unsigned int i;
482
483 for (i = 0;
484 i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map);
485 i++)
486 {
487 if (d30v_reloc_map[i].bfd_reloc_val == code)
488 return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val];
489 }
490
491 return NULL;
492}
493
494/* Set the howto pointer for an D30V ELF reloc (type REL). */
495
496static void
47b0e7ad
NC
497d30v_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
498 arelent *cache_ptr,
499 Elf_Internal_Rela *dst)
252b5132
RH
500{
501 unsigned int r_type;
502
503 r_type = ELF32_R_TYPE (dst->r_info);
504 BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
505 cache_ptr->howto = &elf_d30v_howto_table[r_type];
506}
507
508/* Set the howto pointer for an D30V ELF reloc (type RELA). */
509
510static void
47b0e7ad
NC
511d30v_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
512 arelent *cache_ptr,
513 Elf_Internal_Rela *dst)
252b5132
RH
514{
515 unsigned int r_type;
516
517 r_type = ELF32_R_TYPE (dst->r_info);
518 BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
519 cache_ptr->howto = &elf_d30v_howto_table[r_type];
520}
521
522#define ELF_ARCH bfd_arch_d30v
aa4f99bb
AO
523#define ELF_MACHINE_CODE EM_D30V
524#define ELF_MACHINE_ALT1 EM_CYGNUS_D30V
252b5132
RH
525#define ELF_MAXPAGESIZE 0x1000
526
527#define TARGET_BIG_SYM bfd_elf32_d30v_vec
528#define TARGET_BIG_NAME "elf32-d30v"
529
530#define elf_info_to_howto d30v_info_to_howto_rela
531#define elf_info_to_howto_rel d30v_info_to_howto_rel
532#define elf_backend_object_p 0
533#define elf_backend_final_write_processing 0
534
535#include "elf32-target.h"
This page took 0.363202 seconds and 4 git commands to generate.