*** empty log message ***
[external/binutils.git] / bfd / elf32-d10v.c
1 /* D10V-specific support for 32-bit ELF
2    Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003
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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 #include "bfd.h"
23 #include "sysdep.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/d10v.h"
27
28 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
29   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
30 static void d10v_info_to_howto_rel
31   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
32 static asection * elf32_d10v_gc_mark_hook
33   PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
34            struct elf_link_hash_entry *, Elf_Internal_Sym *));
35 static bfd_boolean elf32_d10v_gc_sweep_hook
36   PARAMS ((bfd *, struct bfd_link_info *, asection *,
37            const Elf_Internal_Rela *));
38 static bfd_boolean elf32_d10v_check_relocs
39   PARAMS ((bfd *, struct bfd_link_info *, asection *,
40            const Elf_Internal_Rela *));
41 static bfd_vma extract_rel_addend
42   PARAMS ((bfd *, bfd_byte *, reloc_howto_type *));
43 static void insert_rel_addend
44   PARAMS ((bfd *, bfd_byte *, reloc_howto_type *, bfd_vma));
45 static bfd_boolean elf32_d10v_relocate_section
46   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
47            bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *,
48            asection **));
49
50 /* Use REL instead of RELA to save space.  */
51 #define USE_REL 1
52
53 static reloc_howto_type elf_d10v_howto_table[] =
54   {
55     /* This reloc does nothing.  */
56     HOWTO (R_D10V_NONE,         /* type */
57            0,                   /* rightshift */
58            2,                   /* size (0 = byte, 1 = short, 2 = long) */
59            32,                  /* bitsize */
60            FALSE,               /* pc_relative */
61            0,                   /* bitpos */
62            complain_overflow_dont, /* complain_on_overflow */
63            bfd_elf_generic_reloc, /* special_function */
64            "R_D10V_NONE",       /* name */
65            FALSE,               /* partial_inplace */
66            0,                   /* src_mask */
67            0,                   /* dst_mask */
68            FALSE),              /* pcrel_offset */
69
70     /* An PC Relative 10-bit relocation, shifted by 2  */
71     /* right container */
72     HOWTO (R_D10V_10_PCREL_R,   /* type */
73            2,                   /* rightshift */
74            2,                   /* size (0 = byte, 1 = short, 2 = long) */
75            7,                   /* bitsize */
76            TRUE,                /* pc_relative */
77            0,                   /* bitpos */
78            complain_overflow_bitfield, /* complain_on_overflow */
79            bfd_elf_generic_reloc, /* special_function */
80            "R_D10V_10_PCREL_R", /* name */
81            FALSE,               /* partial_inplace */
82            0xff,                /* src_mask */
83            0xff,                /* dst_mask */
84            TRUE),               /* pcrel_offset */
85
86     /* An PC Relative 10-bit relocation, shifted by 2  */
87     /* left container */
88     HOWTO (R_D10V_10_PCREL_L,   /* type */
89            2,                   /* rightshift */
90            2,                   /* size (0 = byte, 1 = short, 2 = long) */
91            7,                   /* bitsize */
92            TRUE,                /* pc_relative */
93            15,                  /* bitpos */
94            complain_overflow_bitfield, /* complain_on_overflow */
95            bfd_elf_generic_reloc, /* special_function */
96            "R_D10V_10_PCREL_L", /* name */
97            FALSE,               /* partial_inplace */
98            0x07f8000,           /* src_mask */
99            0x07f8000,           /* dst_mask */
100            TRUE),               /* pcrel_offset */
101
102     /* A 16 bit absolute relocation */
103     HOWTO (R_D10V_16,           /* type */
104            0,                   /* rightshift */
105            1,                   /* size (0 = byte, 1 = short, 2 = long) */
106            16,                  /* bitsize */
107            FALSE,               /* pc_relative */
108            0,                   /* bitpos */
109            complain_overflow_dont, /* complain_on_overflow */
110            bfd_elf_generic_reloc, /* special_function */
111            "R_D10V_16",         /* name */
112            FALSE,               /* partial_inplace */
113            0xffff,              /* src_mask */
114            0xffff,              /* dst_mask */
115            FALSE),              /* pcrel_offset */
116
117     /* An 18 bit absolute relocation, right shifted 2 */
118     HOWTO (R_D10V_18,           /* type */
119            2,                   /* rightshift */
120            1,                   /* size (0 = byte, 1 = short, 2 = long) */
121            16,                  /* bitsize */
122            FALSE,               /* pc_relative */
123            0,                   /* bitpos */
124            complain_overflow_dont, /* complain_on_overflow */
125            bfd_elf_generic_reloc, /* special_function */
126            "R_D10V_18",         /* name */
127            FALSE,               /* partial_inplace */
128            0xffff,              /* src_mask */
129            0xffff,              /* dst_mask */
130            FALSE),              /* pcrel_offset */
131
132     /* A relative 18 bit relocation, right shifted by 2  */
133     HOWTO (R_D10V_18_PCREL,     /* type */
134            2,                   /* rightshift */
135            2,                   /* size (0 = byte, 1 = short, 2 = long) */
136            15,                  /* bitsize */
137            TRUE,                /* pc_relative */
138            0,                   /* bitpos */
139            complain_overflow_bitfield, /* complain_on_overflow */
140            bfd_elf_generic_reloc, /* special_function */
141            "R_D10V_18_PCREL",   /* name */
142            FALSE,               /* partial_inplace */
143            0xffff,              /* src_mask */
144            0xffff,              /* dst_mask */
145            TRUE),                       /* pcrel_offset */
146
147     /* A 32 bit absolute relocation */
148     HOWTO (R_D10V_32,           /* type */
149            0,                   /* rightshift */
150            2,                   /* size (0 = byte, 1 = short, 2 = long) */
151            32,                  /* bitsize */
152            FALSE,               /* pc_relative */
153            0,                   /* bitpos */
154            complain_overflow_dont, /* complain_on_overflow */
155            bfd_elf_generic_reloc, /* special_function */
156            "R_D10V_32",         /* name */
157            FALSE,               /* partial_inplace */
158            0xffffffff,          /* src_mask */
159            0xffffffff,          /* dst_mask */
160            FALSE),              /* pcrel_offset */
161
162     /* GNU extension to record C++ vtable hierarchy */
163     HOWTO (R_D10V_GNU_VTINHERIT, /* type */
164            0,                     /* rightshift */
165            2,                     /* size (0 = byte, 1 = short, 2 = long) */
166            0,                     /* bitsize */
167            FALSE,                 /* pc_relative */
168            0,                     /* bitpos */
169            complain_overflow_dont, /* complain_on_overflow */
170            NULL,                  /* special_function */
171            "R_D10V_GNU_VTINHERIT", /* name */
172            FALSE,                 /* partial_inplace */
173            0,                     /* src_mask */
174            0,                     /* dst_mask */
175            FALSE),                /* pcrel_offset */
176
177     /* GNU extension to record C++ vtable member usage */
178     HOWTO (R_D10V_GNU_VTENTRY,     /* type */
179            0,                     /* rightshift */
180            2,                     /* size (0 = byte, 1 = short, 2 = long) */
181            0,                     /* bitsize */
182            FALSE,                 /* pc_relative */
183            0,                     /* bitpos */
184            complain_overflow_dont, /* complain_on_overflow */
185            _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
186            "R_D10V_GNU_VTENTRY",   /* name */
187            FALSE,                 /* partial_inplace */
188            0,                     /* src_mask */
189            0,                     /* dst_mask */
190            FALSE),                /* pcrel_offset */
191   };
192
193 /* Map BFD reloc types to D10V ELF reloc types.  */
194
195 struct d10v_reloc_map
196   {
197     bfd_reloc_code_real_type bfd_reloc_val;
198     unsigned char elf_reloc_val;
199   };
200
201 static const struct d10v_reloc_map d10v_reloc_map[] =
202   {
203     { BFD_RELOC_NONE, R_D10V_NONE, },
204     { BFD_RELOC_D10V_10_PCREL_R, R_D10V_10_PCREL_R },
205     { BFD_RELOC_D10V_10_PCREL_L, R_D10V_10_PCREL_L },
206     { BFD_RELOC_16, R_D10V_16 },
207     { BFD_RELOC_D10V_18, R_D10V_18 },
208     { BFD_RELOC_D10V_18_PCREL, R_D10V_18_PCREL },
209     { BFD_RELOC_32, R_D10V_32 },
210     { BFD_RELOC_VTABLE_INHERIT, R_D10V_GNU_VTINHERIT },
211     { BFD_RELOC_VTABLE_ENTRY, R_D10V_GNU_VTENTRY },
212   };
213
214 static reloc_howto_type *
215 bfd_elf32_bfd_reloc_type_lookup (abfd, code)
216      bfd *abfd ATTRIBUTE_UNUSED;
217      bfd_reloc_code_real_type code;
218 {
219   unsigned int i;
220
221   for (i = 0;
222        i < sizeof (d10v_reloc_map) / sizeof (struct d10v_reloc_map);
223        i++)
224     {
225       if (d10v_reloc_map[i].bfd_reloc_val == code)
226         return &elf_d10v_howto_table[d10v_reloc_map[i].elf_reloc_val];
227     }
228
229   return NULL;
230 }
231
232 /* Set the howto pointer for an D10V ELF reloc.  */
233
234 static void
235 d10v_info_to_howto_rel (abfd, cache_ptr, dst)
236      bfd *abfd ATTRIBUTE_UNUSED;
237      arelent *cache_ptr;
238      Elf_Internal_Rela *dst;
239 {
240   unsigned int r_type;
241
242   r_type = ELF32_R_TYPE (dst->r_info);
243   BFD_ASSERT (r_type < (unsigned int) R_D10V_max);
244   cache_ptr->howto = &elf_d10v_howto_table[r_type];
245 }
246
247 static asection *
248 elf32_d10v_gc_mark_hook (sec, info, rel, h, sym)
249      asection *sec;
250      struct bfd_link_info *info ATTRIBUTE_UNUSED;
251      Elf_Internal_Rela *rel;
252      struct elf_link_hash_entry *h;
253      Elf_Internal_Sym *sym;
254 {
255   if (h != NULL)
256     {
257       switch (ELF32_R_TYPE (rel->r_info))
258       {
259       case R_D10V_GNU_VTINHERIT:
260       case R_D10V_GNU_VTENTRY:
261         break;
262
263       default:
264         switch (h->root.type)
265           {
266           case bfd_link_hash_defined:
267           case bfd_link_hash_defweak:
268             return h->root.u.def.section;
269
270           case bfd_link_hash_common:
271             return h->root.u.c.p->section;
272
273           default:
274             break;
275           }
276        }
277      }
278    else
279      return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
280
281   return NULL;
282 }
283
284 static bfd_boolean
285 elf32_d10v_gc_sweep_hook (abfd, info, sec, relocs)
286      bfd *abfd ATTRIBUTE_UNUSED;
287      struct bfd_link_info *info ATTRIBUTE_UNUSED;
288      asection *sec ATTRIBUTE_UNUSED;
289      const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
290 {
291   /* we don't use got and plt entries for d10v */
292   return TRUE;
293 }
294
295 /* Look through the relocs for a section during the first phase.
296    Since we don't do .gots or .plts, we just need to consider the
297    virtual table relocs for gc.  */
298
299 static bfd_boolean
300 elf32_d10v_check_relocs (abfd, info, sec, relocs)
301      bfd *abfd;
302      struct bfd_link_info *info;
303      asection *sec;
304      const Elf_Internal_Rela *relocs;
305 {
306   Elf_Internal_Shdr *symtab_hdr;
307   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
308   const Elf_Internal_Rela *rel;
309   const Elf_Internal_Rela *rel_end;
310
311   if (info->relocatable)
312     return TRUE;
313
314   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
315   sym_hashes = elf_sym_hashes (abfd);
316   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
317   if (!elf_bad_symtab (abfd))
318     sym_hashes_end -= symtab_hdr->sh_info;
319
320   rel_end = relocs + sec->reloc_count;
321   for (rel = relocs; rel < rel_end; rel++)
322     {
323       struct elf_link_hash_entry *h;
324       unsigned long r_symndx;
325
326       r_symndx = ELF32_R_SYM (rel->r_info);
327       if (r_symndx < symtab_hdr->sh_info)
328         h = NULL;
329       else
330         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
331
332       switch (ELF32_R_TYPE (rel->r_info))
333         {
334         /* This relocation describes the C++ object vtable hierarchy.
335            Reconstruct it for later use during GC.  */
336         case R_D10V_GNU_VTINHERIT:
337           if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
338             return FALSE;
339           break;
340
341         /* This relocation describes which C++ vtable entries are actually
342            used.  Record for later use during GC.  */
343         case R_D10V_GNU_VTENTRY:
344           if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
345             return FALSE;
346           break;
347         }
348     }
349
350   return TRUE;
351 }
352
353 static bfd_vma
354 extract_rel_addend (abfd, where, howto)
355      bfd *abfd;
356      bfd_byte *where;
357      reloc_howto_type *howto;
358 {
359   bfd_vma insn, val;
360
361   switch (howto->size)
362     {
363     case 0:
364       insn = bfd_get_8 (abfd, where);
365       break;
366     case 1:
367       insn = bfd_get_16 (abfd, where);
368       break;
369     case 2:
370       insn = bfd_get_32 (abfd, where);
371       break;
372     default:
373       abort ();
374     }
375
376   val = (insn & howto->dst_mask) >> howto->bitpos << howto->rightshift;
377   /* We should really be testing for signed addends here, but we don't
378      have that info directly in the howto.  */
379   if (howto->pc_relative)
380     {
381       bfd_vma sign;
382       sign = howto->dst_mask & (~howto->dst_mask >> 1 | ~(-(bfd_vma) 1 >> 1));
383       sign = sign >> howto->bitpos << howto->rightshift;
384       val = (val ^ sign) - sign;
385     }
386   return val;
387 }
388
389 static void
390 insert_rel_addend (abfd, where, howto, addend)
391      bfd *abfd;
392      bfd_byte *where;
393      reloc_howto_type *howto;
394      bfd_vma addend;
395 {
396   bfd_vma insn;
397
398   addend = (addend >> howto->rightshift << howto->bitpos) & howto->dst_mask;
399   insn = ~howto->dst_mask;
400   switch (howto->size)
401     {
402     case 0:
403       insn &= bfd_get_8 (abfd, where);
404       insn |= addend;
405       bfd_put_8 (abfd, insn, where);
406       break;
407     case 1:
408       insn &= bfd_get_16 (abfd, where);
409       insn |= addend;
410       bfd_put_16 (abfd, insn, where);
411       break;
412     case 2:
413       insn &= bfd_get_32 (abfd, where);
414       insn |= addend;
415       bfd_put_32 (abfd, insn, where);
416       break;
417     default:
418       abort ();
419     }
420 }
421
422 /* Relocate a D10V ELF section.  */
423 static bfd_boolean
424 elf32_d10v_relocate_section (output_bfd, info, input_bfd, input_section,
425                             contents, relocs, local_syms, local_sections)
426      bfd *output_bfd;
427      struct bfd_link_info *info;
428      bfd *input_bfd;
429      asection *input_section;
430      bfd_byte *contents;
431      Elf_Internal_Rela *relocs;
432      Elf_Internal_Sym *local_syms;
433      asection **local_sections;
434 {
435   Elf_Internal_Shdr *symtab_hdr;
436   struct elf_link_hash_entry **sym_hashes;
437   Elf_Internal_Rela *rel, *relend;
438   const char *name;
439
440   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
441   sym_hashes = elf_sym_hashes (input_bfd);
442
443   rel = relocs;
444   relend = relocs + input_section->reloc_count;
445   for (; rel < relend; rel++)
446     {
447       int r_type;
448       reloc_howto_type *howto;
449       unsigned long r_symndx;
450       Elf_Internal_Sym *sym;
451       asection *sec;
452       struct elf_link_hash_entry *h;
453       bfd_vma relocation;
454       bfd_reloc_status_type r;
455
456       r_symndx = ELF32_R_SYM (rel->r_info);
457       r_type = ELF32_R_TYPE (rel->r_info);
458
459       if (r_type == R_D10V_GNU_VTENTRY
460           || r_type == R_D10V_GNU_VTINHERIT )
461         continue;
462
463       howto = elf_d10v_howto_table + r_type;
464
465       if (info->relocatable)
466         {
467           bfd_vma val;
468           bfd_byte *where;
469
470           /* This is a relocatable link.  We don't have to change
471              anything, unless the reloc is against a section symbol,
472              in which case we have to adjust according to where the
473              section symbol winds up in the output section.  */
474           if (r_symndx >= symtab_hdr->sh_info)
475             continue;
476
477           sym = local_syms + r_symndx;
478           if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
479             continue;
480
481           sec = local_sections[r_symndx];
482           val = sec->output_offset;
483           if (val == 0)
484             continue;
485
486           where = contents + rel->r_offset;
487           val += extract_rel_addend (input_bfd, where, howto);
488           insert_rel_addend (input_bfd, where, howto, val);
489           continue;
490         }
491
492       /* This is a final link.  */
493       h = NULL;
494       sym = NULL;
495       sec = NULL;
496       if (r_symndx < symtab_hdr->sh_info)
497         {
498           sym = local_syms + r_symndx;
499           sec = local_sections[r_symndx];
500           relocation = (sec->output_section->vma
501                         + sec->output_offset
502                         + sym->st_value);
503           if ((sec->flags & SEC_MERGE)
504               && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
505             {
506               asection *msec;
507               bfd_vma addend;
508               bfd_byte *where = contents + rel->r_offset;
509
510               addend = extract_rel_addend (input_bfd, where, howto);
511               msec = sec;
512               addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
513               addend -= relocation;
514               addend += msec->output_section->vma + msec->output_offset;
515               insert_rel_addend (input_bfd, where, howto, addend);
516             }
517         }
518       else
519         {
520           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
521           while (h->root.type == bfd_link_hash_indirect
522                  || h->root.type == bfd_link_hash_warning)
523             h = (struct elf_link_hash_entry *) h->root.u.i.link;
524           if (h->root.type == bfd_link_hash_defined
525               || h->root.type == bfd_link_hash_defweak)
526             {
527               sec = h->root.u.def.section;
528               relocation = (h->root.u.def.value
529                             + sec->output_section->vma
530                             + sec->output_offset);
531             }
532           else if (h->root.type == bfd_link_hash_undefweak)
533             relocation = 0;
534           else
535             {
536               if (!((*info->callbacks->undefined_symbol)
537                     (info, h->root.root.string, input_bfd,
538                      input_section, rel->r_offset, TRUE)))
539                 return FALSE;
540               relocation = 0;
541             }
542         }
543
544       if (h != NULL)
545         name = h->root.root.string;
546       else
547         {
548           name = (bfd_elf_string_from_elf_section
549                   (input_bfd, symtab_hdr->sh_link, sym->st_name));
550           if (name == NULL || *name == '\0')
551             name = bfd_section_name (input_bfd, sec);
552         }
553
554       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
555                                     contents, rel->r_offset,
556                                     relocation, (bfd_vma) 0);
557
558       if (r != bfd_reloc_ok)
559         {
560           const char * msg = (const char *) 0;
561
562           switch (r)
563             {
564             case bfd_reloc_overflow:
565               if (!((*info->callbacks->reloc_overflow)
566                     (info, name, howto->name, (bfd_vma) 0,
567                      input_bfd, input_section, rel->r_offset)))
568                 return FALSE;
569               break;
570
571             case bfd_reloc_undefined:
572               if (!((*info->callbacks->undefined_symbol)
573                     (info, name, input_bfd, input_section,
574                      rel->r_offset, TRUE)))
575                 return FALSE;
576               break;
577
578             case bfd_reloc_outofrange:
579               msg = _("internal error: out of range error");
580               goto common_error;
581
582             case bfd_reloc_notsupported:
583               msg = _("internal error: unsupported relocation error");
584               goto common_error;
585
586             case bfd_reloc_dangerous:
587               msg = _("internal error: dangerous error");
588               goto common_error;
589
590             default:
591               msg = _("internal error: unknown error");
592               /* fall through */
593
594             common_error:
595               if (!((*info->callbacks->warning)
596                     (info, msg, name, input_bfd, input_section,
597                      rel->r_offset)))
598                 return FALSE;
599               break;
600             }
601         }
602     }
603
604   return TRUE;
605 }
606 #define ELF_ARCH                bfd_arch_d10v
607 #define ELF_MACHINE_CODE        EM_D10V
608 #define ELF_MACHINE_ALT1        EM_CYGNUS_D10V
609 #define ELF_MAXPAGESIZE         0x1000
610
611 #define TARGET_BIG_SYM          bfd_elf32_d10v_vec
612 #define TARGET_BIG_NAME         "elf32-d10v"
613
614 #define elf_info_to_howto                    0
615 #define elf_info_to_howto_rel                d10v_info_to_howto_rel
616 #define elf_backend_object_p                 0
617 #define elf_backend_final_write_processing   0
618 #define elf_backend_gc_mark_hook             elf32_d10v_gc_mark_hook
619 #define elf_backend_gc_sweep_hook            elf32_d10v_gc_sweep_hook
620 #define elf_backend_check_relocs             elf32_d10v_check_relocs
621 #define elf_backend_relocate_section         elf32_d10v_relocate_section
622 #define elf_backend_can_gc_sections          1
623
624 #include "elf32-target.h"