* testsuite/Makefile.am: Add -ffunction-sections to compile
[external/binutils.git] / bfd / elf32-or32.c
1 /* OR32-specific support for 32-bit ELF
2    Copyright 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
3    Contributed by Ivan Guzvinec  <ivang@opencores.org>
4
5    This file is part of BFD, the Binary File Descriptor library.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #include "sysdep.h"
23 #include "bfd.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/or32.h"
27 #include "libiberty.h"
28
29 /* Try to minimize the amount of space occupied by relocation tables
30    on the ROM (not that the ROM won't be swamped by other ELF overhead).  */
31 #define USE_REL 1
32
33 /* Set the right machine number for an OR32 ELF file.  */
34
35 static bfd_boolean
36 or32_elf_object_p (bfd *abfd)
37 {
38   (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
39   return TRUE;
40 }
41
42 /* The final processing done just before writing out an OR32 ELF object file.
43    This gets the OR32 architecture right based on the machine number.  */
44
45 static void
46 or32_elf_final_write_processing (bfd *abfd,
47                                  bfd_boolean linker ATTRIBUTE_UNUSED)
48 {
49   elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH;
50 }
51
52 static bfd_reloc_status_type
53 or32_elf_32_reloc (bfd *abfd,
54                    arelent *reloc_entry,
55                    asymbol *symbol,
56                    void * data,
57                    asection *input_section,
58                    bfd *output_bfd,
59                    char **error_message ATTRIBUTE_UNUSED)
60 {
61   if (output_bfd != NULL)
62     {
63       unsigned long insn;
64       bfd_size_type addr = reloc_entry->address;
65
66       reloc_entry->address += input_section->output_offset;
67
68       insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
69       insn += symbol->section->output_section->vma;
70       insn += symbol->section->output_offset;
71       insn += symbol->value;
72       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
73
74       return bfd_reloc_ok;
75     }
76
77   return bfd_reloc_continue;
78 }
79
80 static bfd_reloc_status_type
81 or32_elf_16_reloc (bfd *abfd,
82                    arelent *reloc_entry,
83                    asymbol *symbol,
84                    void * data,
85                    asection *input_section,
86                    bfd *output_bfd,
87                    char **error_message ATTRIBUTE_UNUSED)
88 {
89   if (output_bfd != NULL)
90     {
91       unsigned short insn;
92       bfd_size_type addr = reloc_entry->address;
93
94       reloc_entry->address += input_section->output_offset;
95
96       insn = bfd_get_16 (abfd, (bfd_byte *) data + addr);
97       insn += symbol->section->output_section->vma;
98       insn += symbol->section->output_offset;
99       insn += symbol->value;
100       bfd_put_16 (abfd, insn, (bfd_byte *) data + addr);
101
102       return bfd_reloc_ok;
103     }
104
105   return bfd_reloc_continue;
106 }
107
108 static bfd_reloc_status_type
109 or32_elf_8_reloc (bfd *abfd ATTRIBUTE_UNUSED,
110                   arelent *reloc_entry,
111                   asymbol *symbol,
112                   void * data,
113                   asection *input_section,
114                   bfd *output_bfd,
115                   char **error_message ATTRIBUTE_UNUSED)
116 {
117   if (output_bfd != NULL)
118     {
119       unsigned char insn;
120       bfd_size_type addr = reloc_entry->address;
121
122       reloc_entry->address += input_section->output_offset;
123
124       insn = bfd_get_8 (abfd, (bfd_byte *) data + addr);
125       insn += symbol->section->output_section->vma;
126       insn += symbol->section->output_offset;
127       insn += symbol->value;
128       bfd_put_8 (abfd, insn, (bfd_byte *) data + addr);
129
130       return bfd_reloc_ok;
131     }
132
133   return bfd_reloc_continue;
134 }
135
136 /* Do a R_OR32_CONSTH relocation.  This has to be done in combination
137    with a R_OR32_CONST reloc, because there is a carry from the LO16 to
138    the HI16.  Here we just save the information we need; we do the
139    actual relocation when we see the LO16.  OR32 ELF requires that the
140    LO16 immediately follow the HI16.  As a GNU extension, we permit an
141    arbitrary number of HI16 relocs to be associated with a single LO16
142    reloc.  This extension permits gcc to output the HI and LO relocs
143    itself. This code is copied from the elf32-mips.c.  */
144
145 struct or32_consth
146 {
147   struct or32_consth *next;
148   bfd_byte *addr;
149   bfd_vma addend;
150 };
151
152 /* FIXME: This should not be a static variable.  */
153
154 static struct or32_consth *or32_consth_list;
155
156 static bfd_reloc_status_type
157 or32_elf_consth_reloc (bfd *abfd ATTRIBUTE_UNUSED,
158                        arelent *reloc_entry,
159                        asymbol *symbol,
160                        void * data,
161                        asection *input_section,
162                        bfd *output_bfd,
163                        char **error_message ATTRIBUTE_UNUSED)
164 {
165   bfd_reloc_status_type ret;
166   bfd_vma relocation;
167   struct or32_consth *n;
168
169   ret = bfd_reloc_ok;
170
171   if (bfd_is_und_section (symbol->section)
172       && output_bfd == NULL)
173     ret = bfd_reloc_undefined;
174
175   if (bfd_is_com_section (symbol->section))
176     relocation = 0;
177   else
178     relocation = symbol->value;
179
180   relocation += symbol->section->output_section->vma;
181   relocation += symbol->section->output_offset;
182   relocation += reloc_entry->addend;
183
184   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
185     return bfd_reloc_outofrange;
186
187   /* Save the information, and let LO16 do the actual relocation.  */
188   n = bfd_malloc (sizeof *n);
189   if (n == NULL)
190     return bfd_reloc_outofrange;
191   n->addr = (bfd_byte *) data + reloc_entry->address;
192   n->addend = relocation;
193   n->next = or32_consth_list;
194   or32_consth_list = n;
195
196   if (output_bfd != NULL)
197     reloc_entry->address += input_section->output_offset;
198
199   return ret;
200 }
201
202 /* Do a R_OR32_CONST relocation.  This is a straightforward 16 bit
203    inplace relocation; this function exists in order to do the
204    R_OR32_CONSTH relocation described above.  */
205
206 static bfd_reloc_status_type
207 or32_elf_const_reloc (bfd *abfd,
208                       arelent *reloc_entry,
209                       asymbol *symbol,
210                       void * data,
211                       asection *input_section,
212                       bfd *output_bfd,
213                       char **error_message)
214 {
215   if (or32_consth_list != NULL)
216     {
217       struct or32_consth *l;
218
219       l = or32_consth_list;
220       while (l != NULL)
221         {
222           unsigned long insn;
223           unsigned long val;
224           unsigned long vallo;
225           struct or32_consth *next;
226
227           /* Do the HI16 relocation.  Note that we actually don't need
228              to know anything about the LO16 itself, except where to
229              find the low 16 bits of the addend needed by the LO16.  */
230           insn = bfd_get_32 (abfd, l->addr);
231           vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
232                    & 0xffff);
233           val = ((insn & 0xffff) << 16) + vallo;
234           val += l->addend;
235
236           insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
237           bfd_put_32 (abfd, insn, l->addr);
238
239           next = l->next;
240           free (l);
241           l = next;
242         }
243
244       or32_consth_list = NULL;
245     }
246
247   if (output_bfd != NULL)
248     {
249       unsigned long insn, tmp;
250       bfd_size_type addr = reloc_entry->address;
251
252       reloc_entry->address += input_section->output_offset;
253
254       insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
255       tmp = insn & 0x0000ffff;
256       tmp += symbol->section->output_section->vma;
257       tmp += symbol->section->output_offset;
258       tmp += symbol->value;
259       insn = (insn & 0xffff0000) | (tmp & 0x0000ffff);
260       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
261
262       return bfd_reloc_ok;
263     }
264
265   /* Now do the LO16 reloc in the usual way.  */
266   return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
267                                 input_section, output_bfd, error_message);
268 }
269
270 static bfd_reloc_status_type
271 or32_elf_jumptarg_reloc (bfd *abfd,
272                          arelent *reloc_entry,
273                          asymbol *symbol ATTRIBUTE_UNUSED,
274                          void * data,
275                          asection *input_section,
276                          bfd *output_bfd,
277                          char **error_message ATTRIBUTE_UNUSED)
278 {
279   if (output_bfd != NULL)
280     {
281       unsigned long insn, tmp;
282       bfd_size_type addr = reloc_entry->address;
283
284       reloc_entry->address += input_section->output_offset;
285
286       insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
287       tmp = insn | 0xfc000000;
288       tmp -= (input_section->output_offset >> 2);
289       insn = (insn & 0xfc000000) | (tmp & 0x03ffffff);
290       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
291
292       return bfd_reloc_ok;
293     }
294
295   return bfd_reloc_continue;
296 }
297
298 static reloc_howto_type elf_or32_howto_table[] =
299 {
300   /* This reloc does nothing.  */
301   HOWTO (R_OR32_NONE,           /* type */
302          0,                     /* rightshift */
303          2,                     /* size (0 = byte, 1 = short, 2 = long) */
304          32,                    /* bitsize */
305          FALSE,                 /* pc_relative */
306          0,                     /* bitpos */
307          complain_overflow_bitfield, /* complain_on_overflow */
308          bfd_elf_generic_reloc, /* special_function */
309          "R_OR32_NONE",         /* name */
310          FALSE,                 /* partial_inplace */
311          0,                     /* src_mask */
312          0,                     /* dst_mask */
313          FALSE),                /* pcrel_offset */
314
315   /* A standard 32 bit relocation.  */
316   HOWTO (R_OR32_32,             /* type */
317          0,                     /* rightshift */
318          2,                     /* size (0 = byte, 1 = short, 2 = long) */
319          32,                    /* bitsize */
320          FALSE,                 /* pc_relative */
321          0,                     /* bitpos */
322          complain_overflow_bitfield, /* complain_on_overflow */
323          or32_elf_32_reloc,     /* special_function */
324          "R_OR32_32",           /* name */
325          FALSE,                 /* partial_inplace */
326          0xffffffff,            /* src_mask */
327          0xffffffff,            /* dst_mask */
328          FALSE),                /* pcrel_offset */
329
330   /* A standard 16 bit relocation.  */
331   HOWTO (R_OR32_16,             /* type */
332          0,                     /* rightshift */
333          1,                     /* size (0 = byte, 1 = short, 2 = long) */
334          16,                    /* bitsize */
335          FALSE,                 /* pc_relative */
336          0,                     /* bitpos */
337          complain_overflow_bitfield, /* complain_on_overflow */
338          or32_elf_16_reloc,     /* special_function */
339          "R_OR32_16",           /* name */
340          FALSE,                 /* partial_inplace */
341          0x0000ffff,            /* src_mask */
342          0x0000ffff,            /* dst_mask */
343          FALSE),                /* pcrel_offset */
344
345   /* A standard 8 bit relocation.  */
346   HOWTO (R_OR32_8,              /* type */
347          0,                     /* rightshift */
348          0,                     /* size (0 = byte, 1 = short, 2 = long) */
349          8,                     /* bitsize */
350          FALSE,                 /* pc_relative */
351          0,                     /* bitpos */
352          complain_overflow_bitfield, /* complain_on_overflow */
353          or32_elf_8_reloc,      /* special_function */
354          "R_OR32_8",            /* name */
355          FALSE,                 /* partial_inplace */
356          0x000000ff,            /* src_mask */
357          0x000000ff,            /* dst_mask */
358          FALSE),                /* pcrel_offset */
359
360   /* A standard low 16 bit relocation.  */
361   HOWTO (R_OR32_CONST,          /* type */
362          0,                     /* rightshift */
363          2,                     /* size (0 = byte, 1 = short, 2 = long) */
364          16,                    /* bitsize */
365          FALSE,                 /* pc_relative */
366          0,                     /* bitpos */
367          complain_overflow_dont, /* complain_on_overflow */
368          or32_elf_const_reloc,  /* special_function */
369          "R_OR32_CONST",        /* name */
370          FALSE,                 /* partial_inplace */
371          0x0000ffff,            /* src_mask */
372          0x0000ffff,            /* dst_mask */
373          FALSE),                /* pcrel_offset */
374
375   /* A standard high 16 bit relocation.  */
376   HOWTO (R_OR32_CONSTH,         /* type */
377          16,                    /* rightshift */
378          2,                     /* size (0 = byte, 1 = short, 2 = long) */
379          16,                    /* bitsize */
380          TRUE,                  /* pc_relative */
381          0,                     /* bitpos */
382          complain_overflow_dont, /* complain_on_overflow */
383          or32_elf_consth_reloc, /* special_function */
384          "R_OR32_CONSTH",       /* name */
385          FALSE,                 /* partial_inplace */
386          0xffff0000,            /* src_mask */
387          0x0000ffff,            /* dst_mask */
388          FALSE),                /* pcrel_offset */
389
390   /* A standard branch relocation.  */
391   HOWTO (R_OR32_JUMPTARG,       /* type */
392          2,                     /* rightshift */
393          2,                     /* size (0 = byte, 1 = short, 2 = long) */
394          28,                    /* bitsize */
395          TRUE,                  /* pc_relative */
396          0,                     /* bitpos */
397          complain_overflow_signed, /* complain_on_overflow */
398          or32_elf_jumptarg_reloc,/* special_function */
399          "R_OR32_JUMPTARG",     /* name */
400          FALSE,                 /* partial_inplace */
401          0,                     /* src_mask */
402          0x03ffffff,            /* dst_mask */
403          TRUE),                 /* pcrel_offset */
404
405   /* GNU extension to record C++ vtable hierarchy.  */
406   HOWTO (R_OR32_GNU_VTINHERIT, /* type */
407          0,                     /* rightshift */
408          2,                     /* size (0 = byte, 1 = short, 2 = long) */
409          0,                     /* bitsize */
410          FALSE,                 /* pc_relative */
411          0,                     /* bitpos */
412          complain_overflow_dont, /* complain_on_overflow */
413          NULL,                  /* special_function */
414          "R_OR32_GNU_VTINHERIT", /* name */
415          FALSE,                 /* partial_inplace */
416          0,                     /* src_mask */
417          0,                     /* dst_mask */
418          FALSE),                /* pcrel_offset */
419
420   /* GNU extension to record C++ vtable member usage.  */
421   HOWTO (R_OR32_GNU_VTENTRY,     /* type */
422          0,                     /* rightshift */
423          2,                     /* size (0 = byte, 1 = short, 2 = long) */
424          0,                     /* bitsize */
425          FALSE,                 /* pc_relative */
426          0,                     /* bitpos */
427          complain_overflow_dont, /* complain_on_overflow */
428          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
429          "R_OR32_GNU_VTENTRY",   /* name */
430          FALSE,                 /* partial_inplace */
431          0,                     /* src_mask */
432          0,                     /* dst_mask */
433          FALSE),                /* pcrel_offset */
434 };
435
436 /* Map BFD reloc types to OR32 ELF reloc types.  */
437
438 struct or32_reloc_map
439 {
440   bfd_reloc_code_real_type  bfd_reloc_val;
441   unsigned char             elf_reloc_val;
442 };
443
444 static const struct or32_reloc_map or32_reloc_map[] =
445 {
446   { BFD_RELOC_NONE, R_OR32_NONE },
447   { BFD_RELOC_32, R_OR32_32 },
448   { BFD_RELOC_16, R_OR32_16 },
449   { BFD_RELOC_8, R_OR32_8 },
450   { BFD_RELOC_LO16, R_OR32_CONST },
451   { BFD_RELOC_HI16, R_OR32_CONSTH },
452   { BFD_RELOC_32_GOT_PCREL, R_OR32_JUMPTARG },
453   { BFD_RELOC_VTABLE_INHERIT, R_OR32_GNU_VTINHERIT },
454   { BFD_RELOC_VTABLE_ENTRY, R_OR32_GNU_VTENTRY },
455 };
456
457 static reloc_howto_type *
458 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
459                                  bfd_reloc_code_real_type code)
460 {
461   unsigned int i;
462
463   for (i = ARRAY_SIZE (or32_reloc_map); i--;)
464     if (or32_reloc_map[i].bfd_reloc_val == code)
465       return &elf_or32_howto_table[or32_reloc_map[i].elf_reloc_val];
466
467   return NULL;
468 }
469
470 static reloc_howto_type *
471 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
472                                  const char *r_name)
473 {
474   unsigned int i;
475
476   for (i = 0;
477        i < sizeof (elf_or32_howto_table) / sizeof (elf_or32_howto_table[0]);
478        i++)
479     if (elf_or32_howto_table[i].name != NULL
480         && strcasecmp (elf_or32_howto_table[i].name, r_name) == 0)
481       return &elf_or32_howto_table[i];
482
483   return NULL;
484 }
485
486 /* Set the howto pointer for an OR32 ELF reloc.  */
487
488 static void
489 or32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
490                         arelent *cache_ptr,
491                         Elf_Internal_Rela *dst)
492 {
493   unsigned int r_type;
494
495   r_type = ELF32_R_TYPE (dst->r_info);
496   BFD_ASSERT (r_type < (unsigned int) R_OR32_max);
497   cache_ptr->howto = &elf_or32_howto_table[r_type];
498 }
499
500 #define TARGET_LITTLE_SYM       bfd_elf32_or32_little_vec
501 #define TARGET_LITTLE_NAME      "elf32-littleor32"
502 #define TARGET_BIG_SYM          bfd_elf32_or32_big_vec
503 #define TARGET_BIG_NAME         "elf32-or32"
504 #define ELF_ARCH                bfd_arch_or32
505 #define ELF_MACHINE_CODE        EM_OR32
506 #define ELF_MAXPAGESIZE         0x1000
507
508 #define elf_info_to_howto       0
509 #define elf_info_to_howto_rel   or32_info_to_howto_rel
510 #define elf_backend_object_p    or32_elf_object_p
511 #define elf_backend_final_write_processing \
512                                 or32_elf_final_write_processing
513
514 #include "elf32-target.h"