1/* moxie-specific support for 32-bit ELF.
2   Copyright (C) 2009-2022 Free Software Foundation, Inc.
3
4   Copied from elf32-fr30.c which is..
5   Copyright (C) 1998-2022 Free Software Foundation, Inc.
6
7   This file is part of BFD, the Binary File Descriptor library.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22   MA 02110-1301, USA.  */
23
24#include "sysdep.h"
25#include "bfd.h"
26#include "libbfd.h"
27#include "elf-bfd.h"
28#include "elf/moxie.h"
29
30/* Forward declarations.  */
31
32static reloc_howto_type moxie_elf_howto_table [] =
33{
34  /* This reloc does nothing.  */
35  HOWTO (R_MOXIE_NONE,		/* type */
36	 0,			/* rightshift */
37	 0,			/* size */
38	 0,			/* bitsize */
39	 false,			/* pc_relative */
40	 0,			/* bitpos */
41	 complain_overflow_dont, /* complain_on_overflow */
42	 bfd_elf_generic_reloc,	/* special_function */
43	 "R_MOXIE_NONE",		/* name */
44	 false,			/* partial_inplace */
45	 0,			/* src_mask */
46	 0,			/* dst_mask */
47	 false),		/* pcrel_offset */
48
49  /* A 32 bit absolute relocation.  */
50  HOWTO (R_MOXIE_32,		/* type */
51	 0,			/* rightshift */
52	 4,			/* size */
53	 32,			/* bitsize */
54	 false,			/* pc_relative */
55	 0,			/* bitpos */
56	 complain_overflow_bitfield, /* complain_on_overflow */
57	 bfd_elf_generic_reloc,	/* special_function */
58	 "R_MOXIE_32",		/* name */
59	 false,			/* partial_inplace */
60	 0x00000000,		/* src_mask */
61	 0xffffffff,		/* dst_mask */
62	 false),		/* pcrel_offset */
63
64  /* A 10 bit PC-relative relocation.  */
65  HOWTO (R_MOXIE_PCREL10,	/* type.  */
66	 1,			/* rightshift.  */
67	 2,			/* size.  */
68	 10,			/* bitsize.  */
69	 true,			/* pc_relative.  */
70	 0,			/* bitpos.  */
71	 complain_overflow_signed, /* complain_on_overflow.  */
72	 bfd_elf_generic_reloc,	/* special_function.  */
73	 "R_MOXIE_PCREL10",		/* name.  */
74	 false,			/* partial_inplace.  */
75	 0,			/* src_mask.  */
76	 0x000003FF,		/* dst_mask.  */
77	 true),			/* pcrel_offset.  */
78};
79
80/* Map BFD reloc types to MOXIE ELF reloc types.  */
81
82struct moxie_reloc_map
83{
84  bfd_reloc_code_real_type bfd_reloc_val;
85  unsigned int moxie_reloc_val;
86};
87
88static const struct moxie_reloc_map moxie_reloc_map [] =
89{
90  { BFD_RELOC_NONE,	       R_MOXIE_NONE },
91  { BFD_RELOC_32,	       R_MOXIE_32 },
92  { BFD_RELOC_MOXIE_10_PCREL,  R_MOXIE_PCREL10 },
93};
94
95static reloc_howto_type *
96moxie_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
97			 bfd_reloc_code_real_type code)
98{
99  unsigned int i;
100
101  for (i = sizeof (moxie_reloc_map) / sizeof (moxie_reloc_map[0]);
102       i--;)
103    if (moxie_reloc_map [i].bfd_reloc_val == code)
104      return & moxie_elf_howto_table [moxie_reloc_map[i].moxie_reloc_val];
105
106  return NULL;
107}
108
109static reloc_howto_type *
110moxie_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
111{
112  unsigned int i;
113
114  for (i = 0;
115       i < sizeof (moxie_elf_howto_table) / sizeof (moxie_elf_howto_table[0]);
116       i++)
117    if (moxie_elf_howto_table[i].name != NULL
118	&& strcasecmp (moxie_elf_howto_table[i].name, r_name) == 0)
119      return &moxie_elf_howto_table[i];
120
121  return NULL;
122}
123
124/* Set the howto pointer for an MOXIE ELF reloc.  */
125
126static bool
127moxie_info_to_howto_rela (bfd *abfd,
128			  arelent *cache_ptr,
129			  Elf_Internal_Rela *dst)
130{
131  unsigned int r_type;
132
133  r_type = ELF32_R_TYPE (dst->r_info);
134  if (r_type >= (unsigned int) R_MOXIE_max)
135    {
136      /* xgettext:c-format */
137      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
138			  abfd, r_type);
139      bfd_set_error (bfd_error_bad_value);
140      return false;
141    }
142  cache_ptr->howto = & moxie_elf_howto_table [r_type];
143  return true;
144}
145
146/* Perform a single relocation.  By default we use the standard BFD
147   routines, but a few relocs, we have to do them ourselves.  */
148
149static bfd_reloc_status_type
150moxie_final_link_relocate (reloc_howto_type *howto,
151			   bfd *input_bfd,
152			   asection *input_section,
153			   bfd_byte *contents,
154			   Elf_Internal_Rela *rel,
155			   bfd_vma relocation)
156{
157  bfd_reloc_status_type r = bfd_reloc_ok;
158
159  switch (howto->type)
160    {
161    default:
162      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
163				    contents, rel->r_offset,
164				    relocation, rel->r_addend);
165    }
166
167  return r;
168}
169
170/* Relocate an MOXIE ELF section.
171
172   The RELOCATE_SECTION function is called by the new ELF backend linker
173   to handle the relocations for a section.
174
175   The relocs are always passed as Rela structures; if the section
176   actually uses Rel structures, the r_addend field will always be
177   zero.
178
179   This function is responsible for adjusting the section contents as
180   necessary, and (if using Rela relocs and generating a relocatable
181   output file) adjusting the reloc addend as necessary.
182
183   This function does not have to worry about setting the reloc
184   address or the reloc symbol index.
185
186   LOCAL_SYMS is a pointer to the swapped in local symbols.
187
188   LOCAL_SECTIONS is an array giving the section in the input file
189   corresponding to the st_shndx field of each local symbol.
190
191   The global hash table entry for the global symbols can be found
192   via elf_sym_hashes (input_bfd).
193
194   When generating relocatable output, this function must handle
195   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
196   going to be the section symbol corresponding to the output
197   section, which means that the addend must be adjusted
198   accordingly.  */
199
200static int
201moxie_elf_relocate_section (bfd *output_bfd,
202			    struct bfd_link_info *info,
203			    bfd *input_bfd,
204			    asection *input_section,
205			    bfd_byte *contents,
206			    Elf_Internal_Rela *relocs,
207			    Elf_Internal_Sym *local_syms,
208			    asection **local_sections)
209{
210  Elf_Internal_Shdr *symtab_hdr;
211  struct elf_link_hash_entry **sym_hashes;
212  Elf_Internal_Rela *rel;
213  Elf_Internal_Rela *relend;
214
215  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
216  sym_hashes = elf_sym_hashes (input_bfd);
217  relend     = relocs + input_section->reloc_count;
218
219  for (rel = relocs; rel < relend; rel ++)
220    {
221      reloc_howto_type *howto;
222      unsigned long r_symndx;
223      Elf_Internal_Sym *sym;
224      asection *sec;
225      struct elf_link_hash_entry *h;
226      bfd_vma relocation;
227      bfd_reloc_status_type r;
228      const char *name;
229      int r_type;
230
231      r_type = ELF32_R_TYPE (rel->r_info);
232      r_symndx = ELF32_R_SYM (rel->r_info);
233      howto  = moxie_elf_howto_table + r_type;
234      h      = NULL;
235      sym    = NULL;
236      sec    = NULL;
237
238      if (r_symndx < symtab_hdr->sh_info)
239	{
240	  sym = local_syms + r_symndx;
241	  sec = local_sections [r_symndx];
242	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
243
244	  name = bfd_elf_string_from_elf_section
245	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
246	  name = name == NULL ? bfd_section_name (sec) : name;
247	}
248      else
249	{
250	  bool unresolved_reloc, warned, ignored;
251
252	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
253				   r_symndx, symtab_hdr, sym_hashes,
254				   h, sec, relocation,
255				   unresolved_reloc, warned, ignored);
256
257	  name = h->root.root.string;
258	}
259
260      if (sec != NULL && discarded_section (sec))
261	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
262					 rel, 1, relend, howto, 0, contents);
263
264      if (bfd_link_relocatable (info))
265	continue;
266
267      r = moxie_final_link_relocate (howto, input_bfd, input_section,
268				     contents, rel, relocation);
269
270      if (r != bfd_reloc_ok)
271	{
272	  const char * msg = NULL;
273
274	  switch (r)
275	    {
276	    case bfd_reloc_overflow:
277	      (*info->callbacks->reloc_overflow)
278		(info, (h ? &h->root : NULL), name, howto->name,
279		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
280	      break;
281
282	    case bfd_reloc_undefined:
283	      (*info->callbacks->undefined_symbol)
284		(info, name, input_bfd, input_section, rel->r_offset, true);
285	      break;
286
287	    case bfd_reloc_outofrange:
288	      msg = _("internal error: out of range error");
289	      break;
290
291	    case bfd_reloc_notsupported:
292	      msg = _("internal error: unsupported relocation error");
293	      break;
294
295	    case bfd_reloc_dangerous:
296	      msg = _("internal error: dangerous relocation");
297	      break;
298
299	    default:
300	      msg = _("internal error: unknown error");
301	      break;
302	    }
303
304	  if (msg)
305	    (*info->callbacks->warning) (info, msg, name, input_bfd,
306					 input_section, rel->r_offset);
307	}
308    }
309
310  return true;
311}
312
313/* Return the section that should be marked against GC for a given
314   relocation.  */
315
316static asection *
317moxie_elf_gc_mark_hook (asection *sec,
318			struct bfd_link_info *info,
319			Elf_Internal_Rela *rel,
320			struct elf_link_hash_entry *h,
321			Elf_Internal_Sym *sym)
322{
323  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
324}
325
326/* Look through the relocs for a section during the first phase.
327   Since we don't do .gots or .plts, we just need to consider the
328   virtual table relocs for gc.  */
329
330static bool
331moxie_elf_check_relocs (bfd *abfd,
332			struct bfd_link_info *info,
333			asection *sec,
334			const Elf_Internal_Rela *relocs)
335{
336  Elf_Internal_Shdr *symtab_hdr;
337  struct elf_link_hash_entry **sym_hashes;
338  const Elf_Internal_Rela *rel;
339  const Elf_Internal_Rela *rel_end;
340
341  if (bfd_link_relocatable (info))
342    return true;
343
344  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
345  sym_hashes = elf_sym_hashes (abfd);
346
347  rel_end = relocs + sec->reloc_count;
348  for (rel = relocs; rel < rel_end; rel++)
349    {
350      struct elf_link_hash_entry *h;
351      unsigned long r_symndx;
352
353      r_symndx = ELF32_R_SYM (rel->r_info);
354      if (r_symndx < symtab_hdr->sh_info)
355	h = NULL;
356      else
357	{
358	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
359	  while (h->root.type == bfd_link_hash_indirect
360		 || h->root.type == bfd_link_hash_warning)
361	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
362	}
363    }
364
365  return true;
366}
367
368#define ELF_ARCH		bfd_arch_moxie
369#define ELF_MACHINE_CODE	EM_MOXIE
370#define ELF_MACHINE_ALT1	EM_MOXIE_OLD
371#define ELF_MAXPAGESIZE		0x1
372
373#define TARGET_BIG_SYM		moxie_elf32_be_vec
374#define TARGET_BIG_NAME		"elf32-bigmoxie"
375#define TARGET_LITTLE_SYM	moxie_elf32_le_vec
376#define TARGET_LITTLE_NAME	"elf32-littlemoxie"
377
378#define elf_info_to_howto_rel			NULL
379#define elf_info_to_howto			moxie_info_to_howto_rela
380#define elf_backend_relocate_section		moxie_elf_relocate_section
381#define elf_backend_gc_mark_hook		moxie_elf_gc_mark_hook
382#define elf_backend_check_relocs		moxie_elf_check_relocs
383
384#define elf_backend_can_gc_sections		1
385#define elf_backend_rela_normal			1
386
387#define bfd_elf32_bfd_reloc_type_lookup		moxie_reloc_type_lookup
388#define bfd_elf32_bfd_reloc_name_lookup		moxie_reloc_name_lookup
389
390#include "elf32-target.h"
391