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