* testsuite/Makefile.am: Add -ffunction-sections to compile
[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, 2005, 2007
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 3 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., 51 Franklin Street - Fifth Floor, Boston,
21    MA 02110-1301, USA.  */
22
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27 #include "elf/d30v.h"
28
29 #define MAX32 ((bfd_signed_vma) 0x7fffffff)
30 #define MIN32 (- MAX32 - 1)
31
32 static bfd_reloc_status_type
33 bfd_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)
40 {
41   bfd_signed_vma relocation;
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
52   if (output_bfd != NULL)
53     {
54       /* Partial linking -- do nothing.  */
55       reloc_entry->address += input_section->output_offset;
56       return bfd_reloc_ok;
57     }
58
59   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
60                              input_section, output_bfd, error_message);
61   if (r != bfd_reloc_continue)
62     return r;
63
64   /* A hacked-up version of bfd_perform_reloc() follows.  */
65  if (bfd_is_und_section (symbol->section)
66       && (symbol->flags & BSF_WEAK) == 0
67       && output_bfd == NULL)
68     flag = bfd_reloc_undefined;
69
70   /* Is the address of the relocation really within the section?  */
71   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
72     return bfd_reloc_outofrange;
73
74   /* Work out which section the relocation is targeted at and the
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.  */
86   output_base = reloc_target_output_section->vma;
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.  */
94   if (howto->pc_relative)
95     {
96       tmp_addr = input_section->output_section->vma
97         + input_section->output_offset
98         + reloc_entry->address;
99       relocation -= tmp_addr;
100     }
101
102   in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
103   in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
104
105   /* Extract the addend.  */
106   num = ((in2 & 0x3FFFF)
107          | ((in2 & 0xFF00000) >> 2)
108          | ((in1 & 0x3F) << 26));
109   in1 &= 0xFFFFFFC0;
110   in2 = 0x80000000;
111
112   relocation += num;
113
114   if (howto->pc_relative && howto->bitsize == 32)
115     {
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)
120         {
121           relocation = (relocation + tmp_addr) & 0xffffffff;
122           make_absolute = 1;
123         }
124     }
125
126   in1 |= (relocation >> 26) & 0x3F;             /* Top 6 bits.  */
127   in2 |= ((relocation & 0x03FC0000) << 2);      /* Next 8 bits.  */
128   in2 |= relocation & 0x0003FFFF;               /* Bottom 18 bits.  */
129
130   /* Change a PC-relative instruction to its
131      absolute equivalent with this simple hack.  */
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);
137
138   return flag;
139 }
140
141 static bfd_reloc_status_type
142 bfd_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)
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
160   if (output_bfd != NULL)
161     {
162       /* Partial linking -- do nothing.  */
163       reloc_entry->address += input_section->output_offset;
164       return bfd_reloc_ok;
165     }
166
167   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
168                              input_section, output_bfd, error_message);
169   if (r != bfd_reloc_continue)
170     return r;
171
172   /* A hacked-up version of bfd_perform_reloc() follows.  */
173   if (bfd_is_und_section (symbol->section)
174       && (symbol->flags & BSF_WEAK) == 0
175       && output_bfd == NULL)
176     flag = bfd_reloc_undefined;
177
178   /* Is the address of the relocation really within the section?  */
179   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
180     return bfd_reloc_outofrange;
181
182   /* Work out which section the relocation is targeted at and the
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.  */
194   output_base = reloc_target_output_section->vma;
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
203   if (howto->pc_relative)
204     {
205       relocation -= (input_section->output_section->vma
206                      + input_section->output_offset);
207       if (howto->pcrel_offset)
208         relocation -= reloc_entry->address;
209     }
210
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
218   /* Extract the addend.  */
219   num = in1 & mask;  /* 18 bits.  */
220   if (howto->bitsize == 6)
221     num >>= 12;
222   num <<= 3; /* shift left 3.  */
223   in1 &= ~mask;  /* Mask out addend.  */
224
225   relocation += num;
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;
230
231   if ((int) relocation < 0)
232     {
233       if (~ (int) relocation > max)
234         flag = bfd_reloc_overflow;
235     }
236   else
237     {
238       if ((int) relocation > max)
239         flag = bfd_reloc_overflow;
240     }
241
242   relocation >>= 3;
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);
249
250   return flag;
251 }
252
253 static 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
452 /* Map BFD reloc types to D30V ELF reloc types.  */
453
454 struct d30v_reloc_map
455 {
456   bfd_reloc_code_real_type bfd_reloc_val;
457   unsigned char elf_reloc_val;
458 };
459
460 static 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
477 static reloc_howto_type *
478 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
479                                  bfd_reloc_code_real_type code)
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 static reloc_howto_type *
495 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
496                                  const char *r_name)
497 {
498   unsigned int i;
499
500   for (i = 0;
501        i < sizeof (elf_d30v_howto_table) / sizeof (elf_d30v_howto_table[0]);
502        i++)
503     if (elf_d30v_howto_table[i].name != NULL
504         && strcasecmp (elf_d30v_howto_table[i].name, r_name) == 0)
505       return &elf_d30v_howto_table[i];
506
507   return NULL;
508 }
509
510 /* Set the howto pointer for an D30V ELF reloc (type REL).  */
511
512 static void
513 d30v_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
514                         arelent *cache_ptr,
515                         Elf_Internal_Rela *dst)
516 {
517   unsigned int r_type;
518
519   r_type = ELF32_R_TYPE (dst->r_info);
520   BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
521   cache_ptr->howto = &elf_d30v_howto_table[r_type];
522 }
523
524 /* Set the howto pointer for an D30V ELF reloc (type RELA).  */
525
526 static void
527 d30v_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
528                          arelent *cache_ptr,
529                          Elf_Internal_Rela *dst)
530 {
531   unsigned int r_type;
532
533   r_type = ELF32_R_TYPE (dst->r_info);
534   BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
535   cache_ptr->howto = &elf_d30v_howto_table[r_type];
536 }
537
538 #define ELF_ARCH                bfd_arch_d30v
539 #define ELF_MACHINE_CODE        EM_D30V
540 #define ELF_MACHINE_ALT1        EM_CYGNUS_D30V
541 #define ELF_MAXPAGESIZE         0x1000
542
543 #define TARGET_BIG_SYM          bfd_elf32_d30v_vec
544 #define TARGET_BIG_NAME         "elf32-d30v"
545
546 #define elf_info_to_howto       d30v_info_to_howto_rela
547 #define elf_info_to_howto_rel   d30v_info_to_howto_rel
548 #define elf_backend_object_p    0
549 #define elf_backend_final_write_processing      0
550
551 #include "elf32-target.h"