OSDN Git Service

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