Updated Turkish translation.
[external/binutils.git] / bfd / elf32-openrisc.c
1 /* OpenRISC-specific support for 32-bit ELF.
2    Copyright 2001, 2002 Free Software Foundation, Inc.
3    Contributed by Johan Rydberg, jrydberg@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/openrisc.h"
26 #include "libiberty.h"
27
28 /* Forward declarations.  */
29
30 static reloc_howto_type *openrisc_reloc_type_lookup
31   PARAMS ((bfd * , bfd_reloc_code_real_type));
32 static void openrisc_info_to_howto_rela
33   PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
34 static boolean openrisc_elf_relocate_section
35   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
36            Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
37 static bfd_reloc_status_type openrisc_final_link_relocate
38   PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *,
39            Elf_Internal_Rela *, bfd_vma));
40 static boolean openrisc_elf_gc_sweep_hook
41   PARAMS ((bfd *, struct bfd_link_info *, asection *,
42            const Elf_Internal_Rela *));
43 static asection * openrisc_elf_gc_mark_hook
44   PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
45            struct elf_link_hash_entry *, Elf_Internal_Sym *));
46 static boolean openrisc_elf_check_relocs
47   PARAMS ((bfd *, struct bfd_link_info *, asection *,
48            const Elf_Internal_Rela *));
49 static boolean openrisc_elf_object_p
50   PARAMS ((bfd *));
51 static void openrisc_elf_final_write_processing
52   PARAMS ((bfd *, boolean));
53
54
55 static reloc_howto_type openrisc_elf_howto_table[] =
56   {
57   /* This reloc does nothing.  */
58   HOWTO (R_OPENRISC_NONE,       /* type */
59          0,                     /* rightshift */
60          2,                     /* size (0 = byte, 1 = short, 2 = long) */
61          32,                    /* bitsize */
62          false,                 /* pc_relative */
63          0,                     /* bitpos */
64          complain_overflow_bitfield, /* complain_on_overflow */
65          bfd_elf_generic_reloc, /* special_function */
66          "R_OPENRISC_NONE",     /* name */
67          false,                 /* partial_inplace */
68          0,                     /* src_mask */
69          0,                     /* dst_mask */
70          false),                /* pcrel_offset */
71
72   /* A PC relative 26 bit relocation, right shifted by 2.  */
73   HOWTO (R_OPENRISC_INSN_REL_26, /* type */
74          2,                     /* rightshift */
75          2,                     /* size (0 = byte, 1 = short, 2 = long) */
76          26,                    /* bitsize */
77          true,                  /* pc_relative */
78          0,                     /* bitpos */
79          complain_overflow_signed, /* complain_on_overflow */
80          bfd_elf_generic_reloc, /* special_function */
81          "R_OPENRISC_INSN_REL_26", /* name */
82          false,                 /* partial_inplace */
83          0x00000000,            /* src_mask */
84          0x03ffffff,            /* dst_mask */
85          false),                /* pcrel_offset */
86
87   /* A absolute 26 bit relocation, right shifted by 2.  */
88   HOWTO (R_OPENRISC_INSN_ABS_26, /* type */
89          2,                     /* rightshift */
90          2,                     /* size (0 = byte, 1 = short, 2 = long) */
91          26,                    /* bitsize */
92          false,                 /* pc_relative */
93          0,                     /* bitpos */
94          complain_overflow_signed, /* complain_on_overflow */
95          bfd_elf_generic_reloc, /* special_function */
96          "R_OPENRISC_INSN_ABS_26", /* name */
97          false,                 /* partial_inplace */
98          0x00000000,            /* src_mask */
99          0x03ffffff,            /* dst_mask */
100          false),                /* pcrel_offset */
101
102   HOWTO (R_OPENRISC_LO_16_IN_INSN, /* type */
103          0,                     /* rightshift */
104          1,                     /* size (0 = byte, 1 = short, 2 = long) */
105          16,                    /* bitsize */
106          false,                 /* pc_relative */
107          0,                     /* bitpos */
108          complain_overflow_dont, /* complain_on_overflow */
109          bfd_elf_generic_reloc, /* special_function */
110          "R_OPENRISC_LO_16_IN_INSN", /* name */
111          false,                 /* partial_inplace */
112          0,                     /* src_mask */
113          0x0000ffff,            /* dst_mask */
114          false),                /* pcrel_offset */
115
116   HOWTO (R_OPENRISC_HI_16_IN_INSN, /* type */
117          16,                    /* rightshift */
118          1,                     /* size (0 = byte, 1 = short, 2 = long) */
119          16,                    /* bitsize */
120          false,                 /* pc_relative */
121          0,                     /* bitpos */
122          complain_overflow_dont,        /* complain_on_overflow */
123          bfd_elf_generic_reloc, /* special_function */
124          "R_OPENRISC_HI_16_IN_INSN",    /* name */
125          false,                 /* partial_inplace */
126          0,                     /* src_mask */
127          0x0000ffff,            /* dst_mask */
128          false),                /* pcrel_offset */
129
130   /* An 8 bit absolute relocation.  */
131   HOWTO (R_OPENRISC_8,          /* type */
132          0,                     /* rightshift */
133          0,                     /* size (0 = byte, 1 = short, 2 = long) */
134          8,                     /* bitsize */
135          false,                 /* pc_relative */
136          0,                     /* bitpos */
137          complain_overflow_bitfield, /* complain_on_overflow */
138          bfd_elf_generic_reloc, /* special_function */
139          "R_OPENRISC_8",        /* name */
140          true,                  /* partial_inplace */
141          0x0000,                /* src_mask */
142          0x00ff,                /* dst_mask */
143          false),                /* pcrel_offset */
144
145   /* A 16 bit absolute relocation.  */
146   HOWTO (R_OPENRISC_16,         /* type */
147          0,                     /* rightshift */
148          1,                     /* size (0 = byte, 1 = short, 2 = long) */
149          16,                    /* bitsize */
150          false,                 /* pc_relative */
151          0,                     /* bitpos */
152          complain_overflow_bitfield, /* complain_on_overflow */
153          bfd_elf_generic_reloc, /* special_function */
154          "R_OPENRISC_16",       /* name */
155          true,                  /* partial_inplace */
156          0x00000000,            /* src_mask */
157          0x0000ffff,            /* dst_mask */
158          false),                /* pcrel_offset */
159
160   /* A 32 bit absolute relocation.  */
161   HOWTO (R_OPENRISC_32,         /* type */
162          0,                     /* rightshift */
163          2,                     /* size (0 = byte, 1 = short, 2 = long) */
164          32,                    /* bitsize */
165          false,                 /* pc_relative */
166          0,                     /* bitpos */
167          complain_overflow_bitfield, /* complain_on_overflow */
168          bfd_elf_generic_reloc, /* special_function */
169          "R_OPENRISC_32",       /* name */
170          true,                  /* partial_inplace */
171          0x00000000,            /* src_mask */
172          0xffffffff,            /* dst_mask */
173          false),                /* pcrel_offset */
174
175   /* GNU extension to record C++ vtable hierarchy */
176   HOWTO (R_OPENRISC_GNU_VTINHERIT, /* type */
177          0,                     /* rightshift */
178          2,                     /* size (0 = byte, 1 = short, 2 = long) */
179          0,                     /* bitsize */
180          false,                 /* pc_relative */
181          0,                     /* bitpos */
182          complain_overflow_dont, /* complain_on_overflow */
183          NULL,                  /* special_function */
184          "R_OPENRISC_GNU_VTINHERIT", /* name */
185          false,                 /* partial_inplace */
186          0,                     /* src_mask */
187          0,                     /* dst_mask */
188          false),                /* pcrel_offset */
189
190   /* GNU extension to record C++ vtable member usage */
191   HOWTO (R_OPENRISC_GNU_VTENTRY, /* type */
192          0,                     /* rightshift */
193          2,                     /* size (0 = byte, 1 = short, 2 = long) */
194          0,                     /* bitsize */
195          false,                 /* pc_relative */
196          0,                     /* bitpos */
197          complain_overflow_dont, /* complain_on_overflow */
198          _bfd_elf_rel_vtable_reloc_fn, /* special_function */
199          "R_OPENRISC_GNU_VTENTRY", /* name */
200          false,                 /* partial_inplace */
201          0,                     /* src_mask */
202          0,                     /* dst_mask */
203          false),                /* pcrel_offset */
204 };
205
206 /* Map BFD reloc types to OpenRISC ELF reloc types.  */
207
208 struct openrisc_reloc_map
209   {
210     bfd_reloc_code_real_type bfd_reloc_val;
211     unsigned int openrisc_reloc_val;
212   };
213
214 static const struct openrisc_reloc_map openrisc_reloc_map[] =
215   {
216     { BFD_RELOC_NONE,           R_OPENRISC_NONE },
217     { BFD_RELOC_32,             R_OPENRISC_32 },
218     { BFD_RELOC_16,             R_OPENRISC_16 },
219     { BFD_RELOC_8,              R_OPENRISC_8 },
220     { BFD_RELOC_OPENRISC_REL_26,R_OPENRISC_INSN_REL_26 },
221     { BFD_RELOC_OPENRISC_ABS_26,R_OPENRISC_INSN_ABS_26 },
222     { BFD_RELOC_HI16,           R_OPENRISC_HI_16_IN_INSN },
223     { BFD_RELOC_LO16,           R_OPENRISC_LO_16_IN_INSN },
224     { BFD_RELOC_VTABLE_INHERIT, R_OPENRISC_GNU_VTINHERIT },
225     { BFD_RELOC_VTABLE_ENTRY,   R_OPENRISC_GNU_VTENTRY }
226   };
227
228 static reloc_howto_type *
229 openrisc_reloc_type_lookup (abfd, code)
230      bfd * abfd ATTRIBUTE_UNUSED;
231      bfd_reloc_code_real_type code;
232 {
233   unsigned int i;
234
235   for (i = ARRAY_SIZE (openrisc_reloc_map); --i;)
236     if (openrisc_reloc_map[i].bfd_reloc_val == code)
237       return & openrisc_elf_howto_table[openrisc_reloc_map[i].
238                                        openrisc_reloc_val];
239
240   return NULL;
241 }
242
243 /* Set the howto pointer for an OpenRISC ELF reloc.  */
244
245 static void
246 openrisc_info_to_howto_rela (abfd, cache_ptr, dst)
247      bfd * abfd ATTRIBUTE_UNUSED;
248      arelent * cache_ptr;
249      Elf32_Internal_Rela * dst;
250 {
251   unsigned int r_type;
252
253   r_type = ELF32_R_TYPE (dst->r_info);
254   BFD_ASSERT (r_type < (unsigned int) R_OPENRISC_max);
255   cache_ptr->howto = & openrisc_elf_howto_table[r_type];
256 }
257
258 /* Perform a single relocation.  By default we use the standard BFD
259    routines, but a few relocs, we have to do them ourselves.  */
260
261 static bfd_reloc_status_type
262 openrisc_final_link_relocate (howto, input_bfd, input_section, contents, rel,
263                               relocation)
264      reloc_howto_type *howto;
265      bfd *input_bfd;
266      asection *input_section;
267      bfd_byte *contents;
268      Elf_Internal_Rela *rel;
269      bfd_vma relocation;
270 {
271   bfd_reloc_status_type r = bfd_reloc_ok;
272
273   switch (howto->type)
274     {
275     case R_OPENRISC_LO_16_IN_INSN:
276       relocation &= 0xffff;
277       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
278                                     contents, rel->r_offset,
279                                     relocation, rel->r_addend);
280       break;
281
282     default:
283       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
284                                     contents, rel->r_offset,
285                                     relocation, rel->r_addend);
286     }
287
288   return r;
289 }
290
291 /* Relocate an OpenRISC ELF section.
292
293    The RELOCATE_SECTION function is called by the new ELF backend linker
294    to handle the relocations for a section.
295
296    The relocs are always passed as Rela structures; if the section
297    actually uses Rel structures, the r_addend field will always be
298    zero.
299
300    This function is responsible for adjusting the section contents as
301    necessary, and (if using Rela relocs and generating a relocateable
302    output file) adjusting the reloc addend as necessary.
303
304    This function does not have to worry about setting the reloc
305    address or the reloc symbol index.
306
307    LOCAL_SYMS is a pointer to the swapped in local symbols.
308
309    LOCAL_SECTIONS is an array giving the section in the input file
310    corresponding to the st_shndx field of each local symbol.
311
312    The global hash table entry for the global symbols can be found
313    via elf_sym_hashes (input_bfd).
314
315    When generating relocateable output, this function must handle
316    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
317    going to be the section symbol corresponding to the output
318    section, which means that the addend must be adjusted
319    accordingly.  */
320
321 static boolean
322 openrisc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
323                                contents, relocs, local_syms, local_sections)
324      bfd *output_bfd;
325      struct bfd_link_info *info;
326      bfd *input_bfd;
327      asection *input_section;
328      bfd_byte *contents;
329      Elf_Internal_Rela *relocs;
330      Elf_Internal_Sym *local_syms;
331      asection **local_sections;
332 {
333   Elf_Internal_Shdr *symtab_hdr;
334   struct elf_link_hash_entry **sym_hashes;
335   Elf_Internal_Rela *rel;
336   Elf_Internal_Rela *relend;
337
338   if (info->relocateable)
339     return true;
340
341   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
342   sym_hashes = elf_sym_hashes (input_bfd);
343   relend = relocs + input_section->reloc_count;
344
345   for (rel = relocs; rel < relend; rel++)
346     {
347       reloc_howto_type *howto;
348       unsigned long r_symndx;
349       Elf_Internal_Sym *sym;
350       asection *sec;
351       struct elf_link_hash_entry *h;
352       bfd_vma relocation;
353       bfd_reloc_status_type r;
354       const char *name = NULL;
355       int r_type;
356
357       r_type = ELF32_R_TYPE (rel->r_info);
358       r_symndx = ELF32_R_SYM (rel->r_info);
359
360       if (r_type == R_OPENRISC_GNU_VTINHERIT
361           || r_type == R_OPENRISC_GNU_VTENTRY)
362         continue;
363
364       if ((unsigned int) r_type >
365           (sizeof openrisc_elf_howto_table / sizeof (reloc_howto_type)))
366         abort ();
367
368       /* This is a final link.  */
369       howto = openrisc_elf_howto_table + ELF32_R_TYPE (rel->r_info);
370       h = NULL;
371       sym = NULL;
372       sec = NULL;
373
374       if (r_symndx < symtab_hdr->sh_info)
375         {
376           sym = local_syms + r_symndx;
377           sec = local_sections[r_symndx];
378           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
379
380           name = bfd_elf_string_from_elf_section
381             (input_bfd, symtab_hdr->sh_link, sym->st_name);
382           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
383         }
384       else
385         {
386           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
387
388           while (h->root.type == bfd_link_hash_indirect
389                  || h->root.type == bfd_link_hash_warning)
390             h = (struct elf_link_hash_entry *) h->root.u.i.link;
391
392           name = h->root.root.string;
393
394           if (h->root.type == bfd_link_hash_defined
395               || h->root.type == bfd_link_hash_defweak)
396             {
397               sec = h->root.u.def.section;
398               relocation = (h->root.u.def.value
399                             + sec->output_section->vma + sec->output_offset);
400             }
401           else if (h->root.type == bfd_link_hash_undefweak)
402             {
403               relocation = 0;
404             }
405           else
406             {
407               if (!((*info->callbacks->undefined_symbol)
408                     (info, h->root.root.string, input_bfd,
409                      input_section, rel->r_offset, true)))
410                 return false;
411               relocation = 0;
412             }
413         }
414
415       r = openrisc_final_link_relocate (howto, input_bfd, input_section,
416                                         contents, rel, relocation);
417
418       if (r != bfd_reloc_ok)
419         {
420           const char *msg = (const char *) NULL;
421
422           switch (r)
423             {
424             case bfd_reloc_overflow:
425               r = info->callbacks->reloc_overflow
426                 (info, name, howto->name, (bfd_vma) 0,
427                  input_bfd, input_section, rel->r_offset);
428               break;
429
430             case bfd_reloc_undefined:
431               r = info->callbacks->undefined_symbol
432                 (info, name, input_bfd, input_section, rel->r_offset, true);
433               break;
434
435             case bfd_reloc_outofrange:
436               msg = _("internal error: out of range error");
437               break;
438
439             case bfd_reloc_notsupported:
440               msg = _("internal error: unsupported relocation error");
441               break;
442
443             case bfd_reloc_dangerous:
444               msg = _("internal error: dangerous relocation");
445               break;
446
447             default:
448               msg = _("internal error: unknown error");
449               break;
450             }
451
452           if (msg)
453             r = info->callbacks->warning
454               (info, msg, name, input_bfd, input_section, rel->r_offset);
455
456           if (!r)
457             return false;
458         }
459     }
460
461   return true;
462 }
463
464 /* Return the section that should be marked against GC for a given
465    relocation.  */
466
467 static asection *
468 openrisc_elf_gc_mark_hook (sec, info, rel, h, sym)
469      asection *sec;
470      struct bfd_link_info *info ATTRIBUTE_UNUSED;
471      Elf_Internal_Rela *rel;
472      struct elf_link_hash_entry *h;
473      Elf_Internal_Sym *sym;
474 {
475   if (h != NULL)
476     {
477       switch (ELF32_R_TYPE (rel->r_info))
478         {
479         case R_OPENRISC_GNU_VTINHERIT:
480         case R_OPENRISC_GNU_VTENTRY:
481           break;
482
483         default:
484           switch (h->root.type)
485             {
486             case bfd_link_hash_defined:
487             case bfd_link_hash_defweak:
488               return h->root.u.def.section;
489
490             case bfd_link_hash_common:
491               return h->root.u.c.p->section;
492
493             default:
494               break;
495             }
496         }
497     }
498   else
499     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
500
501   return NULL;
502 }
503
504 /* Update the got entry reference counts for the section being removed.  */
505
506 static boolean
507 openrisc_elf_gc_sweep_hook (abfd, info, sec, relocs)
508      bfd *abfd ATTRIBUTE_UNUSED;
509      struct bfd_link_info *info ATTRIBUTE_UNUSED;
510      asection *sec ATTRIBUTE_UNUSED;
511      const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
512 {
513   return true;
514 }
515
516 /* Look through the relocs for a section during the first phase.
517    Since we don't do .gots or .plts, we just need to consider the
518    virtual table relocs for gc.  */
519
520 static boolean
521 openrisc_elf_check_relocs (abfd, info, sec, relocs)
522      bfd *abfd;
523      struct bfd_link_info *info;
524      asection *sec;
525      const Elf_Internal_Rela *relocs;
526 {
527   Elf_Internal_Shdr *symtab_hdr;
528   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
529   const Elf_Internal_Rela *rel;
530   const Elf_Internal_Rela *rel_end;
531
532   if (info->relocateable)
533     return true;
534
535   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
536   sym_hashes = elf_sym_hashes (abfd);
537   sym_hashes_end =
538     sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
539   if (!elf_bad_symtab (abfd))
540     sym_hashes_end -= symtab_hdr->sh_info;
541
542   rel_end = relocs + sec->reloc_count;
543   for (rel = relocs; rel < rel_end; rel++)
544     {
545       struct elf_link_hash_entry *h;
546       unsigned long r_symndx;
547
548       r_symndx = ELF32_R_SYM (rel->r_info);
549       if (r_symndx < symtab_hdr->sh_info)
550         h = NULL;
551       else
552         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
553
554       switch (ELF32_R_TYPE (rel->r_info))
555         {
556           /* This relocation describes the C++ object vtable hierarchy.
557              Reconstruct it for later use during GC.  */
558         case R_OPENRISC_GNU_VTINHERIT:
559           if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
560             return false;
561           break;
562
563           /* This relocation describes which C++ vtable entries are actually
564              used.  Record for later use during GC.  */
565         case R_OPENRISC_GNU_VTENTRY:
566           if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
567             return false;
568           break;
569         }
570     }
571
572   return true;
573 }
574
575 /* Set the right machine number.  */
576
577 static boolean
578 openrisc_elf_object_p (abfd)
579      bfd *abfd;
580 {
581   switch (elf_elfheader (abfd)->e_flags & 0xf)
582     {
583     default:
584       (void) bfd_default_set_arch_mach (abfd, bfd_arch_openrisc, 0);
585       break;
586     }
587   return true;
588 }
589
590 /* Store the machine number in the flags field.  */
591
592 static void
593 openrisc_elf_final_write_processing (abfd, linker)
594      bfd *abfd;
595      boolean linker ATTRIBUTE_UNUSED;
596 {
597   unsigned long val;
598
599   switch (bfd_get_mach (abfd))
600     {
601     default:
602       val = 0;
603       break;
604     }
605
606   elf_elfheader (abfd)->e_flags &= ~0xf;
607   elf_elfheader (abfd)->e_flags |= val;
608 }
609
610
611 #define ELF_ARCH                        bfd_arch_openrisc
612 #define ELF_MACHINE_CODE                EM_OPENRISC
613 #define ELF_MACHINE_ALT1                EM_OPENRISC_OLD
614 #define ELF_MAXPAGESIZE                 0x1000
615
616 #define TARGET_BIG_SYM                  bfd_elf32_openrisc_vec
617 #define TARGET_BIG_NAME                 "elf32-openrisc"
618
619 #define elf_info_to_howto_rel           NULL
620 #define elf_info_to_howto               openrisc_info_to_howto_rela
621 #define elf_backend_relocate_section    openrisc_elf_relocate_section
622 #define elf_backend_gc_mark_hook        openrisc_elf_gc_mark_hook
623 #define elf_backend_gc_sweep_hook       openrisc_elf_gc_sweep_hook
624 #define elf_backend_check_relocs        openrisc_elf_check_relocs
625
626 #define elf_backend_can_gc_sections     1
627 #define elf_backend_rela_normal         1
628
629 #define bfd_elf32_bfd_reloc_type_lookup openrisc_reloc_type_lookup
630
631 #define elf_backend_object_p                openrisc_elf_object_p
632 #define elf_backend_final_write_processing  openrisc_elf_final_write_processing
633
634 #include "elf32-target.h"