OSDN Git Service

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