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