1 /* moxie-specific support for 32-bit ELF.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
3 
4    Copied from elf32-fr30.c which is..
5    Copyright (C) 1998-2014 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 
32 static reloc_howto_type moxie_elf_howto_table [] =
33 {
34   /* This reloc does nothing.  */
35   HOWTO (R_MOXIE_NONE,		/* type */
36 	 0,			/* rightshift */
37 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
38 	 32,			/* bitsize */
39 	 FALSE,			/* pc_relative */
40 	 0,			/* bitpos */
41 	 complain_overflow_bitfield, /* 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 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
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 	 1,			/* size (0 = byte, 1 = short, 2 = long).  */
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 
82 struct moxie_reloc_map
83 {
84   bfd_reloc_code_real_type bfd_reloc_val;
85   unsigned int moxie_reloc_val;
86 };
87 
88 static 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 
95 static reloc_howto_type *
moxie_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)96 moxie_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 
109 static reloc_howto_type *
moxie_reloc_name_lookup(bfd * abfd ATTRIBUTE_UNUSED,const char * r_name)110 moxie_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 
126 static void
moxie_info_to_howto_rela(bfd * abfd ATTRIBUTE_UNUSED,arelent * cache_ptr,Elf_Internal_Rela * dst)127 moxie_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
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   BFD_ASSERT (r_type < (unsigned int) R_MOXIE_max);
135   cache_ptr->howto = & moxie_elf_howto_table [r_type];
136 }
137 
138 /* Perform a single relocation.  By default we use the standard BFD
139    routines, but a few relocs, we have to do them ourselves.  */
140 
141 static bfd_reloc_status_type
moxie_final_link_relocate(reloc_howto_type * howto,bfd * input_bfd,asection * input_section,bfd_byte * contents,Elf_Internal_Rela * rel,bfd_vma relocation)142 moxie_final_link_relocate (reloc_howto_type *howto,
143 			   bfd *input_bfd,
144 			   asection *input_section,
145 			   bfd_byte *contents,
146 			   Elf_Internal_Rela *rel,
147 			   bfd_vma relocation)
148 {
149   bfd_reloc_status_type r = bfd_reloc_ok;
150 
151   switch (howto->type)
152     {
153     default:
154       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
155 				    contents, rel->r_offset,
156 				    relocation, rel->r_addend);
157     }
158 
159   return r;
160 }
161 
162 /* Relocate an MOXIE ELF section.
163 
164    The RELOCATE_SECTION function is called by the new ELF backend linker
165    to handle the relocations for a section.
166 
167    The relocs are always passed as Rela structures; if the section
168    actually uses Rel structures, the r_addend field will always be
169    zero.
170 
171    This function is responsible for adjusting the section contents as
172    necessary, and (if using Rela relocs and generating a relocatable
173    output file) adjusting the reloc addend as necessary.
174 
175    This function does not have to worry about setting the reloc
176    address or the reloc symbol index.
177 
178    LOCAL_SYMS is a pointer to the swapped in local symbols.
179 
180    LOCAL_SECTIONS is an array giving the section in the input file
181    corresponding to the st_shndx field of each local symbol.
182 
183    The global hash table entry for the global symbols can be found
184    via elf_sym_hashes (input_bfd).
185 
186    When generating relocatable output, this function must handle
187    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
188    going to be the section symbol corresponding to the output
189    section, which means that the addend must be adjusted
190    accordingly.  */
191 
192 static bfd_boolean
moxie_elf_relocate_section(bfd * output_bfd,struct bfd_link_info * info,bfd * input_bfd,asection * input_section,bfd_byte * contents,Elf_Internal_Rela * relocs,Elf_Internal_Sym * local_syms,asection ** local_sections)193 moxie_elf_relocate_section (bfd *output_bfd,
194 			    struct bfd_link_info *info,
195 			    bfd *input_bfd,
196 			    asection *input_section,
197 			    bfd_byte *contents,
198 			    Elf_Internal_Rela *relocs,
199 			    Elf_Internal_Sym *local_syms,
200 			    asection **local_sections)
201 {
202   Elf_Internal_Shdr *symtab_hdr;
203   struct elf_link_hash_entry **sym_hashes;
204   Elf_Internal_Rela *rel;
205   Elf_Internal_Rela *relend;
206 
207   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
208   sym_hashes = elf_sym_hashes (input_bfd);
209   relend     = relocs + input_section->reloc_count;
210 
211   for (rel = relocs; rel < relend; rel ++)
212     {
213       reloc_howto_type *howto;
214       unsigned long r_symndx;
215       Elf_Internal_Sym *sym;
216       asection *sec;
217       struct elf_link_hash_entry *h;
218       bfd_vma relocation;
219       bfd_reloc_status_type r;
220       const char *name;
221       int r_type;
222 
223       r_type = ELF32_R_TYPE (rel->r_info);
224       r_symndx = ELF32_R_SYM (rel->r_info);
225       howto  = moxie_elf_howto_table + r_type;
226       h      = NULL;
227       sym    = NULL;
228       sec    = NULL;
229 
230       if (r_symndx < symtab_hdr->sh_info)
231 	{
232 	  sym = local_syms + r_symndx;
233 	  sec = local_sections [r_symndx];
234 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
235 
236 	  name = bfd_elf_string_from_elf_section
237 	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
238 	  name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
239 	}
240       else
241 	{
242 	  bfd_boolean unresolved_reloc, warned, ignored;
243 
244 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
245 				   r_symndx, symtab_hdr, sym_hashes,
246 				   h, sec, relocation,
247 				   unresolved_reloc, warned, ignored);
248 
249 	  name = h->root.root.string;
250 	}
251 
252       if (sec != NULL && discarded_section (sec))
253 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
254 					 rel, 1, relend, howto, 0, contents);
255 
256       if (info->relocatable)
257 	continue;
258 
259       r = moxie_final_link_relocate (howto, input_bfd, input_section,
260 				     contents, rel, relocation);
261 
262       if (r != bfd_reloc_ok)
263 	{
264 	  const char * msg = NULL;
265 
266 	  switch (r)
267 	    {
268 	    case bfd_reloc_overflow:
269 	      r = info->callbacks->reloc_overflow
270 		(info, (h ? &h->root : NULL), name, howto->name,
271 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
272 	      break;
273 
274 	    case bfd_reloc_undefined:
275 	      r = info->callbacks->undefined_symbol
276 		(info, name, input_bfd, input_section, rel->r_offset,
277 		 TRUE);
278 	      break;
279 
280 	    case bfd_reloc_outofrange:
281 	      msg = _("internal error: out of range error");
282 	      break;
283 
284 	    case bfd_reloc_notsupported:
285 	      msg = _("internal error: unsupported relocation error");
286 	      break;
287 
288 	    case bfd_reloc_dangerous:
289 	      msg = _("internal error: dangerous relocation");
290 	      break;
291 
292 	    default:
293 	      msg = _("internal error: unknown error");
294 	      break;
295 	    }
296 
297 	  if (msg)
298 	    r = info->callbacks->warning
299 	      (info, msg, name, input_bfd, input_section, rel->r_offset);
300 
301 	  if (! r)
302 	    return FALSE;
303 	}
304     }
305 
306   return TRUE;
307 }
308 
309 /* Return the section that should be marked against GC for a given
310    relocation.  */
311 
312 static asection *
moxie_elf_gc_mark_hook(asection * sec,struct bfd_link_info * info,Elf_Internal_Rela * rel,struct elf_link_hash_entry * h,Elf_Internal_Sym * sym)313 moxie_elf_gc_mark_hook (asection *sec,
314 			struct bfd_link_info *info,
315 			Elf_Internal_Rela *rel,
316 			struct elf_link_hash_entry *h,
317 			Elf_Internal_Sym *sym)
318 {
319   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
320 }
321 
322 /* Look through the relocs for a section during the first phase.
323    Since we don't do .gots or .plts, we just need to consider the
324    virtual table relocs for gc.  */
325 
326 static bfd_boolean
moxie_elf_check_relocs(bfd * abfd,struct bfd_link_info * info,asection * sec,const Elf_Internal_Rela * relocs)327 moxie_elf_check_relocs (bfd *abfd,
328 			struct bfd_link_info *info,
329 			asection *sec,
330 			const Elf_Internal_Rela *relocs)
331 {
332   Elf_Internal_Shdr *symtab_hdr;
333   struct elf_link_hash_entry **sym_hashes;
334   const Elf_Internal_Rela *rel;
335   const Elf_Internal_Rela *rel_end;
336 
337   if (info->relocatable)
338     return TRUE;
339 
340   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
341   sym_hashes = elf_sym_hashes (abfd);
342 
343   rel_end = relocs + sec->reloc_count;
344   for (rel = relocs; rel < rel_end; rel++)
345     {
346       struct elf_link_hash_entry *h;
347       unsigned long r_symndx;
348 
349       r_symndx = ELF32_R_SYM (rel->r_info);
350       if (r_symndx < symtab_hdr->sh_info)
351         h = NULL;
352       else
353 	{
354 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
355 	  while (h->root.type == bfd_link_hash_indirect
356 		 || h->root.type == bfd_link_hash_warning)
357 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
358 
359 	  /* PR15323, ref flags aren't set for references in the same
360 	     object.  */
361 	  h->root.non_ir_ref = 1;
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_MAXPAGESIZE		0x1
371 
372 #define TARGET_BIG_SYM          moxie_elf32_be_vec
373 #define TARGET_BIG_NAME		"elf32-bigmoxie"
374 #define TARGET_LITTLE_SYM       moxie_elf32_le_vec
375 #define TARGET_LITTLE_NAME	"elf32-littlemoxie"
376 
377 #define elf_info_to_howto_rel			NULL
378 #define elf_info_to_howto			moxie_info_to_howto_rela
379 #define elf_backend_relocate_section		moxie_elf_relocate_section
380 #define elf_backend_gc_mark_hook		moxie_elf_gc_mark_hook
381 #define elf_backend_check_relocs                moxie_elf_check_relocs
382 
383 #define elf_backend_can_gc_sections		1
384 #define elf_backend_rela_normal			1
385 
386 #define bfd_elf32_bfd_reloc_type_lookup		moxie_reloc_type_lookup
387 #define bfd_elf32_bfd_reloc_name_lookup		moxie_reloc_name_lookup
388 
389 #include "elf32-target.h"
390