1 /* Xstormy16-specific support for 32-bit ELF.
2    Copyright (C) 2000-2020 Free Software Foundation, Inc.
3 
4    This file is part of BFD, the Binary File Descriptor library.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "sysdep.h"
22 #include "bfd.h"
23 #include "libbfd.h"
24 #include "elf-bfd.h"
25 #include "elf/xstormy16.h"
26 #include "libiberty.h"
27 
28 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement.  */
29 
30 static bfd_reloc_status_type
xstormy16_elf_24_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol,void * data,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)31 xstormy16_elf_24_reloc (bfd *abfd,
32 			arelent *reloc_entry,
33 			asymbol *symbol,
34 			void * data,
35 			asection *input_section,
36 			bfd *output_bfd,
37 			char **error_message ATTRIBUTE_UNUSED)
38 {
39   bfd_vma relocation, x;
40 
41   if (output_bfd != NULL)
42     {
43       reloc_entry->address += input_section->output_offset;
44       return bfd_reloc_ok;
45     }
46 
47   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
48     return bfd_reloc_outofrange;
49 
50   if (bfd_is_com_section (symbol->section))
51     relocation = 0;
52   else
53     relocation = symbol->value;
54 
55   relocation += symbol->section->output_section->vma;
56   relocation += symbol->section->output_offset;
57   relocation += reloc_entry->addend;
58 
59   x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
60   x &= 0x0000ff00;
61   x |= relocation & 0xff;
62   x |= (relocation << 8) & 0xffff0000;
63   bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
64 
65   if (relocation & ~ (bfd_vma) 0xffffff)
66     return bfd_reloc_overflow;
67 
68   return bfd_reloc_ok;
69 }
70 
71 static reloc_howto_type xstormy16_elf_howto_table [] =
72 {
73   /* This reloc does nothing.  */
74   HOWTO (R_XSTORMY16_NONE,	/* type */
75 	 0,			/* rightshift */
76 	 3,			/* size (0 = byte, 1 = short, 2 = long) */
77 	 0,			/* bitsize */
78 	 FALSE,			/* pc_relative */
79 	 0,			/* bitpos */
80 	 complain_overflow_dont, /* complain_on_overflow */
81 	 bfd_elf_generic_reloc,	/* special_function */
82 	 "R_XSTORMY16_NONE",	/* name */
83 	 FALSE,			/* partial_inplace */
84 	 0,			/* src_mask */
85 	 0,			/* dst_mask */
86 	 FALSE),		/* pcrel_offset */
87 
88   /* A 32 bit absolute relocation.  */
89   HOWTO (R_XSTORMY16_32,	/* type */
90 	 0,			/* rightshift */
91 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
92 	 32,			/* bitsize */
93 	 FALSE,			/* pc_relative */
94 	 0,			/* bitpos */
95 	 complain_overflow_dont, /* complain_on_overflow */
96 	 bfd_elf_generic_reloc,	/* special_function */
97 	 "R_XSTORMY16_32",	/* name */
98 	 FALSE,			/* partial_inplace */
99 	 0,			/* src_mask */
100 	 0xffffffff,		/* dst_mask */
101 	 FALSE),		/* pcrel_offset */
102 
103   /* A 16 bit absolute relocation.  */
104   HOWTO (R_XSTORMY16_16,	/* type */
105 	 0,			/* rightshift */
106 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
107 	 16,			/* bitsize */
108 	 FALSE,			/* pc_relative */
109 	 0,			/* bitpos */
110 	 complain_overflow_bitfield, /* complain_on_overflow */
111 	 bfd_elf_generic_reloc,	/* special_function */
112 	 "R_XSTORMY16_16",	/* name */
113 	 FALSE,			/* partial_inplace */
114 	 0,			/* src_mask */
115 	 0xffff,		/* dst_mask */
116 	 FALSE),		/* pcrel_offset */
117 
118   /* An 8 bit absolute relocation.  */
119   HOWTO (R_XSTORMY16_8,		/* type */
120 	 0,			/* rightshift */
121 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
122 	 8,			/* bitsize */
123 	 FALSE,			/* pc_relative */
124 	 0,			/* bitpos */
125 	 complain_overflow_unsigned, /* complain_on_overflow */
126 	 bfd_elf_generic_reloc,	/* special_function */
127 	 "R_XSTORMY16_8",	/* name */
128 	 FALSE,			/* partial_inplace */
129 	 0,			/* src_mask */
130 	 0xff,			/* dst_mask */
131 	 FALSE),		/* pcrel_offset */
132 
133   /* A 32 bit pc-relative relocation.  */
134   HOWTO (R_XSTORMY16_PC32,	/* type */
135 	 0,			/* rightshift */
136 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
137 	 32,			/* bitsize */
138 	 TRUE,			/* pc_relative */
139 	 0,			/* bitpos */
140 	 complain_overflow_dont, /* complain_on_overflow */
141 	 bfd_elf_generic_reloc,	/* special_function */
142 	 "R_XSTORMY16_PC32",	/* name */
143 	 FALSE,			/* partial_inplace */
144 	 0,			/* src_mask */
145 	 0xffffffff,		/* dst_mask */
146 	 TRUE),			/* pcrel_offset */
147 
148   /* A 16 bit pc-relative relocation.  */
149   HOWTO (R_XSTORMY16_PC16,	/* type */
150 	 0,			/* rightshift */
151 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
152 	 16,			/* bitsize */
153 	 TRUE,			/* pc_relative */
154 	 0,			/* bitpos */
155 	 complain_overflow_signed, /* complain_on_overflow */
156 	 bfd_elf_generic_reloc,	/* special_function */
157 	 "R_XSTORMY16_PC16",	/* name */
158 	 FALSE,			/* partial_inplace */
159 	 0,			/* src_mask */
160 	 0xffffffff,		/* dst_mask */
161 	 TRUE),			/* pcrel_offset */
162 
163   /* An 8 bit pc-relative relocation.  */
164   HOWTO (R_XSTORMY16_PC8,	/* type */
165 	 0,			/* rightshift */
166 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
167 	 8,			/* bitsize */
168 	 TRUE,			/* pc_relative */
169 	 0,			/* bitpos */
170 	 complain_overflow_signed, /* complain_on_overflow */
171 	 bfd_elf_generic_reloc,	/* special_function */
172 	 "R_XSTORMY16_PC8",	/* name */
173 	 FALSE,			/* partial_inplace */
174 	 0,			/* src_mask */
175 	 0xffffffff,		/* dst_mask */
176 	 TRUE),			/* pcrel_offset */
177 
178   /* A 12-bit pc-relative relocation suitable for the branch instructions.  */
179   HOWTO (R_XSTORMY16_REL_12,	/* type */
180 	 1,			/* rightshift */
181 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
182 	 11,			/* bitsize */
183 	 TRUE,			/* pc_relative */
184 	 1,			/* bitpos */
185 	 complain_overflow_signed, /* complain_on_overflow */
186 	 bfd_elf_generic_reloc,	/* special_function */
187 	 "R_XSTORMY16_REL_12",	/* name */
188 	 FALSE,			/* partial_inplace */
189 	 0,			/* src_mask */
190 	 0x0ffe,		/* dst_mask */
191 	 TRUE),			/* pcrel_offset */
192 
193   /* A 24-bit absolute relocation suitable for the jump instructions.  */
194   HOWTO (R_XSTORMY16_24,	/* type */
195 	 0,			/* rightshift */
196 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
197 	 24,			/* bitsize */
198 	 FALSE,			/* pc_relative */
199 	 0,			/* bitpos */
200 	 complain_overflow_unsigned, /* complain_on_overflow */
201 	 xstormy16_elf_24_reloc,	/* special_function */
202 	 "R_XSTORMY16_24",	/* name */
203 	 TRUE,			/* partial_inplace */
204 	 0,			/* src_mask */
205 	 0xffff00ff,		/* dst_mask */
206 	 TRUE),			/* pcrel_offset */
207 
208   /* A 16 bit absolute relocation to a function pointer.  */
209   HOWTO (R_XSTORMY16_FPTR16,	/* type */
210 	 0,			/* rightshift */
211 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
212 	 16,			/* bitsize */
213 	 FALSE,			/* pc_relative */
214 	 0,			/* bitpos */
215 	 complain_overflow_bitfield, /* complain_on_overflow */
216 	 bfd_elf_generic_reloc,	/* special_function */
217 	 "R_XSTORMY16_FPTR16",	/* name */
218 	 FALSE,			/* partial_inplace */
219 	 0,			/* src_mask */
220 	 0xffffffff,		/* dst_mask */
221 	 FALSE),		/* pcrel_offset */
222 
223   /* Low order 16 bit value of a high memory address.  */
224   HOWTO (R_XSTORMY16_LO16,	/* type */
225 	 0,			/* rightshift */
226 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
227 	 16,			/* bitsize */
228 	 FALSE,			/* pc_relative */
229 	 0,			/* bitpos */
230 	 complain_overflow_dont, /* complain_on_overflow */
231 	 bfd_elf_generic_reloc,	/* special_function */
232 	 "R_XSTORMY16_LO16",	/* name */
233 	 FALSE,			/* partial_inplace */
234 	 0,			/* src_mask */
235 	 0xffff,		/* dst_mask */
236 	 FALSE),		/* pcrel_offset */
237 
238   /* High order 16 bit value of a high memory address.  */
239   HOWTO (R_XSTORMY16_HI16,	/* type */
240 	 16,			/* rightshift */
241 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
242 	 16,			/* bitsize */
243 	 FALSE,			/* pc_relative */
244 	 0,			/* bitpos */
245 	 complain_overflow_dont, /* complain_on_overflow */
246 	 bfd_elf_generic_reloc,	/* special_function */
247 	 "R_XSTORMY16_HI16",	/* name */
248 	 FALSE,			/* partial_inplace */
249 	 0,			/* src_mask */
250 	 0xffff,		/* dst_mask */
251 	 FALSE),		/* pcrel_offset */
252 
253   /* A 12 bit absolute relocation.  */
254   HOWTO (R_XSTORMY16_12,	/* type */
255 	 0,			/* rightshift */
256 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
257 	 12,			/* bitsize */
258 	 FALSE,			/* pc_relative */
259 	 0,			/* bitpos */
260 	 complain_overflow_signed, /* complain_on_overflow */
261 	 bfd_elf_generic_reloc,	/* special_function */
262 	 "R_XSTORMY16_12",	/* name */
263 	 FALSE,			/* partial_inplace */
264 	 0x0000,		/* src_mask */
265 	 0x0fff,		/* dst_mask */
266 	 FALSE),		/* pcrel_offset */
267 };
268 
269 static reloc_howto_type xstormy16_elf_howto_table2 [] =
270 {
271   /* GNU extension to record C++ vtable hierarchy */
272   HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
273 	 0,			/* rightshift */
274 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
275 	 0,			/* bitsize */
276 	 FALSE,			/* pc_relative */
277 	 0,			/* bitpos */
278 	 complain_overflow_dont, /* complain_on_overflow */
279 	 NULL,			/* special_function */
280 	 "R_XSTORMY16_GNU_VTINHERIT", /* name */
281 	 FALSE,			/* partial_inplace */
282 	 0,			/* src_mask */
283 	 0,			/* dst_mask */
284 	 FALSE),		/* pcrel_offset */
285 
286   /* GNU extension to record C++ vtable member usage */
287   HOWTO (R_XSTORMY16_GNU_VTENTRY,     /* type */
288 	 0,			/* rightshift */
289 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
290 	 0,			/* bitsize */
291 	 FALSE,			/* pc_relative */
292 	 0,			/* bitpos */
293 	 complain_overflow_dont, /* complain_on_overflow */
294 	 _bfd_elf_rel_vtable_reloc_fn,	/* special_function */
295 	 "R_XSTORMY16_GNU_VTENTRY",   /* name */
296 	 FALSE,			/* partial_inplace */
297 	 0,			/* src_mask */
298 	 0,			/* dst_mask */
299 	 FALSE),		/* pcrel_offset */
300 
301 };
302 
303 /* Map BFD reloc types to XSTORMY16 ELF reloc types.  */
304 
305 typedef struct xstormy16_reloc_map
306 {
307   bfd_reloc_code_real_type  bfd_reloc_val;
308   unsigned int		    xstormy16_reloc_val;
309   reloc_howto_type *	    table;
310 } reloc_map;
311 
312 static const reloc_map xstormy16_reloc_map [] =
313 {
314   { BFD_RELOC_NONE,		    R_XSTORMY16_NONE,	       xstormy16_elf_howto_table },
315   { BFD_RELOC_32,		    R_XSTORMY16_32,	       xstormy16_elf_howto_table },
316   { BFD_RELOC_16,		    R_XSTORMY16_16,	       xstormy16_elf_howto_table },
317   { BFD_RELOC_8,		    R_XSTORMY16_8,	       xstormy16_elf_howto_table },
318   { BFD_RELOC_32_PCREL,		    R_XSTORMY16_PC32,	       xstormy16_elf_howto_table },
319   { BFD_RELOC_16_PCREL,		    R_XSTORMY16_PC16,	       xstormy16_elf_howto_table },
320   { BFD_RELOC_8_PCREL,		    R_XSTORMY16_PC8,	       xstormy16_elf_howto_table },
321   { BFD_RELOC_XSTORMY16_REL_12,	    R_XSTORMY16_REL_12,	       xstormy16_elf_howto_table },
322   { BFD_RELOC_XSTORMY16_24,	    R_XSTORMY16_24,	       xstormy16_elf_howto_table },
323   { BFD_RELOC_XSTORMY16_FPTR16,	    R_XSTORMY16_FPTR16,	       xstormy16_elf_howto_table },
324   { BFD_RELOC_LO16,		    R_XSTORMY16_LO16,	       xstormy16_elf_howto_table },
325   { BFD_RELOC_HI16,		    R_XSTORMY16_HI16,	       xstormy16_elf_howto_table },
326   { BFD_RELOC_XSTORMY16_12,	    R_XSTORMY16_12,	       xstormy16_elf_howto_table },
327   { BFD_RELOC_VTABLE_INHERIT,	    R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
328   { BFD_RELOC_VTABLE_ENTRY,	    R_XSTORMY16_GNU_VTENTRY,   xstormy16_elf_howto_table2 },
329 };
330 
331 static reloc_howto_type *
xstormy16_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)332 xstormy16_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
333 			     bfd_reloc_code_real_type code)
334 {
335   unsigned int i;
336 
337   for (i = ARRAY_SIZE (xstormy16_reloc_map); i--;)
338     {
339       const reloc_map * entry;
340 
341       entry = xstormy16_reloc_map + i;
342 
343       if (entry->bfd_reloc_val == code)
344 	return entry->table + (entry->xstormy16_reloc_val
345 			       - entry->table[0].type);
346     }
347 
348   return NULL;
349 }
350 
351 static reloc_howto_type *
xstormy16_reloc_name_lookup(bfd * abfd ATTRIBUTE_UNUSED,const char * r_name)352 xstormy16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
353 			     const char *r_name)
354 {
355   unsigned int i;
356 
357   for (i = 0;
358        i < (sizeof (xstormy16_elf_howto_table)
359 	    / sizeof (xstormy16_elf_howto_table[0]));
360        i++)
361     if (xstormy16_elf_howto_table[i].name != NULL
362 	&& strcasecmp (xstormy16_elf_howto_table[i].name, r_name) == 0)
363       return &xstormy16_elf_howto_table[i];
364 
365   for (i = 0;
366        i < (sizeof (xstormy16_elf_howto_table2)
367 	    / sizeof (xstormy16_elf_howto_table2[0]));
368        i++)
369     if (xstormy16_elf_howto_table2[i].name != NULL
370 	&& strcasecmp (xstormy16_elf_howto_table2[i].name, r_name) == 0)
371       return &xstormy16_elf_howto_table2[i];
372 
373   return NULL;
374 }
375 
376 /* Set the howto pointer for an XSTORMY16 ELF reloc.  */
377 
378 static bfd_boolean
xstormy16_info_to_howto_rela(bfd * abfd,arelent * cache_ptr,Elf_Internal_Rela * dst)379 xstormy16_info_to_howto_rela (bfd * abfd,
380 			      arelent * cache_ptr,
381 			      Elf_Internal_Rela * dst)
382 {
383   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
384 
385   if (r_type <= (unsigned int) R_XSTORMY16_12)
386     cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
387   else if (r_type - R_XSTORMY16_GNU_VTINHERIT
388 	   <= ((unsigned int) R_XSTORMY16_GNU_VTENTRY
389 	       - (unsigned int) R_XSTORMY16_GNU_VTINHERIT))
390     cache_ptr->howto
391       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
392   else
393     {
394       /* xgettext:c-format */
395       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
396 			  abfd, r_type);
397       bfd_set_error (bfd_error_bad_value);
398       return FALSE;
399     }
400   return TRUE;
401 }
402 
403 /* We support 16-bit pointers to code above 64k by generating a thunk
404    below 64k containing a JMPF instruction to the final address.  We
405    cannot, unfortunately, minimize the number of thunks unless the
406    -relax switch is given, as otherwise we have no idea where the
407    sections will fall in the address space.  */
408 
409 static bfd_boolean
xstormy16_elf_check_relocs(bfd * abfd,struct bfd_link_info * info,asection * sec,const Elf_Internal_Rela * relocs)410 xstormy16_elf_check_relocs (bfd *abfd,
411 			    struct bfd_link_info *info,
412 			    asection *sec,
413 			    const Elf_Internal_Rela *relocs)
414 {
415   const Elf_Internal_Rela *rel, *relend;
416   struct elf_link_hash_entry **sym_hashes;
417   Elf_Internal_Shdr *symtab_hdr;
418   bfd_vma *local_plt_offsets;
419   asection *splt;
420   bfd *dynobj;
421 
422   if (bfd_link_relocatable (info))
423     return TRUE;
424 
425   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
426   sym_hashes = elf_sym_hashes (abfd);
427   local_plt_offsets = elf_local_got_offsets (abfd);
428   dynobj = elf_hash_table(info)->dynobj;
429 
430   relend = relocs + sec->reloc_count;
431   for (rel = relocs; rel < relend; ++rel)
432     {
433       unsigned long r_symndx;
434       struct elf_link_hash_entry *h;
435       bfd_vma *offset;
436 
437       r_symndx = ELF32_R_SYM (rel->r_info);
438       if (r_symndx < symtab_hdr->sh_info)
439 	h = NULL;
440       else
441 	{
442 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
443 	  while (h->root.type == bfd_link_hash_indirect
444 		 || h->root.type == bfd_link_hash_warning)
445 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
446 	}
447 
448       switch (ELF32_R_TYPE (rel->r_info))
449 	{
450 	  /* This relocation describes a 16-bit pointer to a function.
451 	     We may need to allocate a thunk in low memory; reserve memory
452 	     for it now.  */
453 	case R_XSTORMY16_FPTR16:
454 	  if (rel->r_addend != 0)
455 	    {
456 	      (*info->callbacks->warning)
457 		(info, _("non-zero addend in @fptr reloc"), 0,
458 		 abfd, 0, 0);
459 	    }
460 
461 	  if (dynobj == NULL)
462 	    elf_hash_table (info)->dynobj = dynobj = abfd;
463 	  splt = elf_hash_table (info)->splt;
464 	  if (splt == NULL)
465 	    {
466 	      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
467 				| SEC_IN_MEMORY | SEC_LINKER_CREATED
468 				| SEC_READONLY | SEC_CODE);
469 
470 	      splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
471 							 flags);
472 	      elf_hash_table (info)->splt = splt;
473 	      if (splt == NULL
474 		  || !bfd_set_section_alignment (splt, 1))
475 		return FALSE;
476 	    }
477 
478 	  if (h != NULL)
479 	    offset = &h->plt.offset;
480 	  else
481 	    {
482 	      if (local_plt_offsets == NULL)
483 		{
484 		  size_t size;
485 		  unsigned int i;
486 
487 		  size = symtab_hdr->sh_info * sizeof (bfd_vma);
488 		  local_plt_offsets = bfd_alloc (abfd, size);
489 		  if (local_plt_offsets == NULL)
490 		    return FALSE;
491 		  elf_local_got_offsets (abfd) = local_plt_offsets;
492 
493 		  for (i = 0; i < symtab_hdr->sh_info; i++)
494 		    local_plt_offsets[i] = (bfd_vma) -1;
495 		}
496 	      offset = &local_plt_offsets[r_symndx];
497 	    }
498 
499 	  if (*offset == (bfd_vma) -1)
500 	    {
501 	      *offset = splt->size;
502 	      splt->size += 4;
503 	    }
504 	  break;
505 
506 	  /* This relocation describes the C++ object vtable hierarchy.
507 	     Reconstruct it for later use during GC.  */
508 	case R_XSTORMY16_GNU_VTINHERIT:
509 	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
510 	    return FALSE;
511 	  break;
512 
513 	  /* This relocation describes which C++ vtable entries are actually
514 	     used.  Record for later use during GC.  */
515 	case R_XSTORMY16_GNU_VTENTRY:
516 	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
517 	    return FALSE;
518 	  break;
519 	}
520     }
521 
522   return TRUE;
523 }
524 
525 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
526    is within the low 64k, remove any entry for it in the plt.  */
527 
528 struct relax_plt_data
529 {
530   asection *splt;
531   bfd_boolean *again;
532 };
533 
534 static bfd_boolean
xstormy16_relax_plt_check(struct elf_link_hash_entry * h,void * xdata)535 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
536 {
537   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
538 
539   if (h->plt.offset != (bfd_vma) -1)
540     {
541       bfd_vma address;
542 
543       if (h->root.type == bfd_link_hash_undefined
544 	  || h->root.type == bfd_link_hash_undefweak)
545 	address = 0;
546       else
547 	address = (h->root.u.def.section->output_section->vma
548 		   + h->root.u.def.section->output_offset
549 		   + h->root.u.def.value);
550 
551       if (address <= 0xffff)
552 	{
553 	  h->plt.offset = -1;
554 	  data->splt->size -= 4;
555 	  *data->again = TRUE;
556 	}
557     }
558 
559   return TRUE;
560 }
561 
562 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
563    previously had a plt entry, give it a new entry offset.  */
564 
565 static bfd_boolean
xstormy16_relax_plt_realloc(struct elf_link_hash_entry * h,void * xdata)566 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
567 {
568   bfd_vma *entry = (bfd_vma *) xdata;
569 
570   if (h->plt.offset != (bfd_vma) -1)
571     {
572       h->plt.offset = *entry;
573       *entry += 4;
574     }
575 
576   return TRUE;
577 }
578 
579 static bfd_boolean
xstormy16_elf_relax_section(bfd * dynobj,asection * splt,struct bfd_link_info * info,bfd_boolean * again)580 xstormy16_elf_relax_section (bfd *dynobj,
581 			     asection *splt,
582 			     struct bfd_link_info *info,
583 			     bfd_boolean *again)
584 {
585   struct relax_plt_data relax_plt_data;
586   bfd *ibfd;
587 
588   /* Assume nothing changes.  */
589   *again = FALSE;
590 
591   if (bfd_link_relocatable (info))
592     return TRUE;
593 
594   /* We only relax the .plt section at the moment.  */
595   if (dynobj != elf_hash_table (info)->dynobj
596       || strcmp (splt->name, ".plt") != 0)
597     return TRUE;
598 
599   /* Quick check for an empty plt.  */
600   if (splt->size == 0)
601     return TRUE;
602 
603   /* Map across all global symbols; see which ones happen to
604      fall in the low 64k.  */
605   relax_plt_data.splt = splt;
606   relax_plt_data.again = again;
607   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
608 			  &relax_plt_data);
609 
610   /* Likewise for local symbols, though that's somewhat less convenient
611      as we have to walk the list of input bfds and swap in symbol data.  */
612   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
613     {
614       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
615       Elf_Internal_Shdr *symtab_hdr;
616       Elf_Internal_Sym *isymbuf = NULL;
617       unsigned int idx;
618 
619       if (! local_plt_offsets)
620 	continue;
621 
622       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
623       if (symtab_hdr->sh_info != 0)
624 	{
625 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
626 	  if (isymbuf == NULL)
627 	    isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
628 					    symtab_hdr->sh_info, 0,
629 					    NULL, NULL, NULL);
630 	  if (isymbuf == NULL)
631 	    return FALSE;
632 	}
633 
634       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
635 	{
636 	  Elf_Internal_Sym *isym;
637 	  asection *tsec;
638 	  bfd_vma address;
639 
640 	  if (local_plt_offsets[idx] == (bfd_vma) -1)
641 	    continue;
642 
643 	  isym = &isymbuf[idx];
644 	  if (isym->st_shndx == SHN_UNDEF)
645 	    continue;
646 	  else if (isym->st_shndx == SHN_ABS)
647 	    tsec = bfd_abs_section_ptr;
648 	  else if (isym->st_shndx == SHN_COMMON)
649 	    tsec = bfd_com_section_ptr;
650 	  else
651 	    tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
652 
653 	  address = (tsec->output_section->vma
654 		     + tsec->output_offset
655 		     + isym->st_value);
656 	  if (address <= 0xffff)
657 	    {
658 	      local_plt_offsets[idx] = -1;
659 	      splt->size -= 4;
660 	      *again = TRUE;
661 	    }
662 	}
663 
664       if (isymbuf != NULL
665 	  && symtab_hdr->contents != (unsigned char *) isymbuf)
666 	{
667 	  if (! info->keep_memory)
668 	    free (isymbuf);
669 	  else
670 	    {
671 	      /* Cache the symbols for elf_link_input_bfd.  */
672 	      symtab_hdr->contents = (unsigned char *) isymbuf;
673 	    }
674 	}
675     }
676 
677   /* If we changed anything, walk the symbols again to reallocate
678      .plt entry addresses.  */
679   if (*again && splt->size > 0)
680     {
681       bfd_vma entry = 0;
682 
683       elf_link_hash_traverse (elf_hash_table (info),
684 			      xstormy16_relax_plt_realloc, &entry);
685 
686       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
687 	{
688 	  bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
689 	  unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
690 	  unsigned int idx;
691 
692 	  if (! local_plt_offsets)
693 	    continue;
694 
695 	  for (idx = 0; idx < nlocals; ++idx)
696 	    if (local_plt_offsets[idx] != (bfd_vma) -1)
697 	      {
698 		local_plt_offsets[idx] = entry;
699 		entry += 4;
700 	      }
701 	}
702     }
703 
704   return TRUE;
705 }
706 
707 static bfd_boolean
xstormy16_elf_always_size_sections(bfd * output_bfd ATTRIBUTE_UNUSED,struct bfd_link_info * info)708 xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
709 				    struct bfd_link_info *info)
710 {
711   bfd *dynobj;
712   asection *splt;
713 
714   if (bfd_link_relocatable (info))
715     return TRUE;
716 
717   dynobj = elf_hash_table (info)->dynobj;
718   if (dynobj == NULL)
719     return TRUE;
720 
721   splt = elf_hash_table (info)->splt;
722   BFD_ASSERT (splt != NULL);
723 
724   splt->contents = bfd_zalloc (dynobj, splt->size);
725   if (splt->contents == NULL)
726     return FALSE;
727 
728   return TRUE;
729 }
730 
731 /* Relocate an XSTORMY16 ELF section.
732 
733    The RELOCATE_SECTION function is called by the new ELF backend linker
734    to handle the relocations for a section.
735 
736    The relocs are always passed as Rela structures; if the section
737    actually uses Rel structures, the r_addend field will always be
738    zero.
739 
740    This function is responsible for adjusting the section contents as
741    necessary, and (if using Rela relocs and generating a relocatable
742    output file) adjusting the reloc addend as necessary.
743 
744    This function does not have to worry about setting the reloc
745    address or the reloc symbol index.
746 
747    LOCAL_SYMS is a pointer to the swapped in local symbols.
748 
749    LOCAL_SECTIONS is an array giving the section in the input file
750    corresponding to the st_shndx field of each local symbol.
751 
752    The global hash table entry for the global symbols can be found
753    via elf_sym_hashes (input_bfd).
754 
755    When generating relocatable output, this function must handle
756    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
757    going to be the section symbol corresponding to the output
758    section, which means that the addend must be adjusted
759    accordingly.  */
760 
761 static bfd_boolean
xstormy16_elf_relocate_section(bfd * output_bfd ATTRIBUTE_UNUSED,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)762 xstormy16_elf_relocate_section (bfd *			output_bfd ATTRIBUTE_UNUSED,
763 				struct bfd_link_info *	info,
764 				bfd *			input_bfd,
765 				asection *		input_section,
766 				bfd_byte *		contents,
767 				Elf_Internal_Rela *	relocs,
768 				Elf_Internal_Sym *	local_syms,
769 				asection **		local_sections)
770 {
771   Elf_Internal_Shdr *		symtab_hdr;
772   struct elf_link_hash_entry ** sym_hashes;
773   Elf_Internal_Rela *		rel;
774   Elf_Internal_Rela *		relend;
775   asection *splt;
776 
777   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
778   sym_hashes = elf_sym_hashes (input_bfd);
779   relend     = relocs + input_section->reloc_count;
780 
781   splt = elf_hash_table (info)->splt;
782 
783   for (rel = relocs; rel < relend; rel ++)
784     {
785       reloc_howto_type *	   howto;
786       unsigned long		   r_symndx;
787       Elf_Internal_Sym *	   sym;
788       asection *		   sec;
789       struct elf_link_hash_entry * h;
790       bfd_vma			   relocation;
791       bfd_reloc_status_type	   r;
792       const char *		   name = NULL;
793       int			   r_type;
794 
795       r_type = ELF32_R_TYPE (rel->r_info);
796 
797       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
798 	  || r_type == R_XSTORMY16_GNU_VTENTRY)
799 	continue;
800 
801       r_symndx = ELF32_R_SYM (rel->r_info);
802       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
803       h      = NULL;
804       sym    = NULL;
805       sec    = NULL;
806 
807       if (r_symndx < symtab_hdr->sh_info)
808 	{
809 	  sym = local_syms + r_symndx;
810 	  sec = local_sections [r_symndx];
811 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
812 	}
813       else
814 	{
815 	  bfd_boolean unresolved_reloc, warned, ignored;
816 
817 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
818 				   r_symndx, symtab_hdr, sym_hashes,
819 				   h, sec, relocation,
820 				   unresolved_reloc, warned, ignored);
821 	}
822 
823       if (sec != NULL && discarded_section (sec))
824 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
825 					 rel, 1, relend, howto, 0, contents);
826 
827       if (bfd_link_relocatable (info))
828 	continue;
829 
830       if (h != NULL)
831 	name = h->root.root.string;
832       else
833 	{
834 	  name = (bfd_elf_string_from_elf_section
835 		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
836 	  if (name == NULL || *name == '\0')
837 	    name = bfd_section_name (sec);
838 	}
839 
840       switch (ELF32_R_TYPE (rel->r_info))
841 	{
842 	case R_XSTORMY16_24:
843 	  {
844 	    bfd_vma reloc = relocation + rel->r_addend;
845 	    unsigned int x;
846 
847 	    x = bfd_get_32 (input_bfd, contents + rel->r_offset);
848 	    x &= 0x0000ff00;
849 	    x |= reloc & 0xff;
850 	    x |= (reloc << 8) & 0xffff0000;
851 	    bfd_put_32 (input_bfd, x, contents + rel->r_offset);
852 
853 	    if (reloc & ~0xffffff)
854 	      r = bfd_reloc_overflow;
855 	    else
856 	      r = bfd_reloc_ok;
857 	    break;
858 	  }
859 
860 	case R_XSTORMY16_FPTR16:
861 	  {
862 	    bfd_vma *plt_offset;
863 
864 	    if (h != NULL)
865 	      plt_offset = &h->plt.offset;
866 	    else
867 	      plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
868 
869 	    if (relocation <= 0xffff)
870 	      {
871 		/* If the symbol is in range for a 16-bit address, we should
872 		   have deallocated the plt entry in relax_section.  */
873 		BFD_ASSERT (*plt_offset == (bfd_vma) -1);
874 	      }
875 	    else
876 	      {
877 		/* If the symbol is out of range for a 16-bit address,
878 		   we must have allocated a plt entry.  */
879 		BFD_ASSERT (*plt_offset != (bfd_vma) -1);
880 
881 		/* If this is the first time we've processed this symbol,
882 		   fill in the plt entry with the correct symbol address.  */
883 		if ((*plt_offset & 1) == 0)
884 		  {
885 		    unsigned int x;
886 
887 		    x = 0x00000200;  /* jmpf */
888 		    x |= relocation & 0xff;
889 		    x |= (relocation << 8) & 0xffff0000;
890 		    bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
891 		    *plt_offset |= 1;
892 		  }
893 
894 		relocation = (splt->output_section->vma
895 			      + splt->output_offset
896 			      + (*plt_offset & -2));
897 	      }
898 	    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
899 					  contents, rel->r_offset,
900 					  relocation, 0);
901 	    break;
902 	  }
903 
904 	default:
905 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
906 					contents, rel->r_offset,
907 					relocation, rel->r_addend);
908 	  break;
909 	}
910 
911       if (r != bfd_reloc_ok)
912 	{
913 	  const char * msg = NULL;
914 
915 	  switch (r)
916 	    {
917 	    case bfd_reloc_overflow:
918 	      (*info->callbacks->reloc_overflow)
919 		(info, (h ? &h->root : NULL), name, howto->name,
920 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
921 	      break;
922 
923 	    case bfd_reloc_undefined:
924 	      (*info->callbacks->undefined_symbol)
925 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
926 	      break;
927 
928 	    case bfd_reloc_outofrange:
929 	      msg = _("internal error: out of range error");
930 	      break;
931 
932 	    case bfd_reloc_notsupported:
933 	      msg = _("internal error: unsupported relocation error");
934 	      break;
935 
936 	    case bfd_reloc_dangerous:
937 	      msg = _("internal error: dangerous relocation");
938 	      break;
939 
940 	    default:
941 	      msg = _("internal error: unknown error");
942 	      break;
943 	    }
944 
945 	  if (msg)
946 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
947 					 input_section, rel->r_offset);
948 	}
949     }
950 
951   return TRUE;
952 }
953 
954 /* This must exist if dynobj is ever set.  */
955 
956 static bfd_boolean
xstormy16_elf_finish_dynamic_sections(bfd * abfd ATTRIBUTE_UNUSED,struct bfd_link_info * info)957 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
958 				       struct bfd_link_info *info)
959 {
960   bfd *dynobj = elf_hash_table (info)->dynobj;
961   asection *splt = elf_hash_table (info)->splt;
962 
963   /* As an extra sanity check, verify that all plt entries have
964      been filled in.  */
965 
966   if (dynobj != NULL && splt != NULL)
967     {
968       bfd_byte *contents = splt->contents;
969       unsigned int i, size = splt->size;
970 
971       for (i = 0; i < size; i += 4)
972 	{
973 	  unsigned int x = bfd_get_32 (dynobj, contents + i);
974 
975 	  BFD_ASSERT (x != 0);
976 	}
977     }
978 
979   return TRUE;
980 }
981 
982 /* Return the section that should be marked against GC for a given
983    relocation.  */
984 
985 static asection *
xstormy16_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)986 xstormy16_elf_gc_mark_hook (asection *sec,
987 			    struct bfd_link_info *info,
988 			    Elf_Internal_Rela *rel,
989 			    struct elf_link_hash_entry *h,
990 			    Elf_Internal_Sym *sym)
991 {
992   if (h != NULL)
993     switch (ELF32_R_TYPE (rel->r_info))
994       {
995       case R_XSTORMY16_GNU_VTINHERIT:
996       case R_XSTORMY16_GNU_VTENTRY:
997 	return NULL;
998       }
999 
1000   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
1001 }
1002 
1003 #define ELF_ARCH		bfd_arch_xstormy16
1004 #define ELF_MACHINE_CODE	EM_XSTORMY16
1005 #define ELF_MAXPAGESIZE		0x100
1006 
1007 #define TARGET_LITTLE_SYM       xstormy16_elf32_vec
1008 #define TARGET_LITTLE_NAME	"elf32-xstormy16"
1009 
1010 #define elf_info_to_howto_rel			NULL
1011 #define elf_info_to_howto			xstormy16_info_to_howto_rela
1012 #define elf_backend_relocate_section		xstormy16_elf_relocate_section
1013 #define elf_backend_gc_mark_hook		xstormy16_elf_gc_mark_hook
1014 #define elf_backend_check_relocs		xstormy16_elf_check_relocs
1015 #define elf_backend_always_size_sections \
1016   xstormy16_elf_always_size_sections
1017 #define elf_backend_omit_section_dynsym \
1018   _bfd_elf_omit_section_dynsym_all
1019 #define elf_backend_finish_dynamic_sections \
1020   xstormy16_elf_finish_dynamic_sections
1021 
1022 #define elf_backend_can_gc_sections		1
1023 #define elf_backend_rela_normal			1
1024 
1025 #define bfd_elf32_bfd_reloc_type_lookup		xstormy16_reloc_type_lookup
1026 #define bfd_elf32_bfd_reloc_name_lookup \
1027   xstormy16_reloc_name_lookup
1028 #define bfd_elf32_bfd_relax_section		xstormy16_elf_relax_section
1029 
1030 #include "elf32-target.h"
1031