1 /* Xstormy16-specific support for 32-bit ELF.
2    Copyright (C) 2000-2016 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 void
xstormy16_info_to_howto_rela(bfd * abfd ATTRIBUTE_UNUSED,arelent * cache_ptr,Elf_Internal_Rela * dst)379 xstormy16_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
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     cache_ptr->howto
390       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
391   else
392     abort ();
393 }
394 
395 /* We support 16-bit pointers to code above 64k by generating a thunk
396    below 64k containing a JMPF instruction to the final address.  We
397    cannot, unfortunately, minimize the number of thunks unless the
398    -relax switch is given, as otherwise we have no idea where the
399    sections will fall in the address space.  */
400 
401 static bfd_boolean
xstormy16_elf_check_relocs(bfd * abfd,struct bfd_link_info * info,asection * sec,const Elf_Internal_Rela * relocs)402 xstormy16_elf_check_relocs (bfd *abfd,
403 			    struct bfd_link_info *info,
404 			    asection *sec,
405 			    const Elf_Internal_Rela *relocs)
406 {
407   const Elf_Internal_Rela *rel, *relend;
408   struct elf_link_hash_entry **sym_hashes;
409   Elf_Internal_Shdr *symtab_hdr;
410   bfd_vma *local_plt_offsets;
411   asection *splt;
412   bfd *dynobj;
413 
414   if (bfd_link_relocatable (info))
415     return TRUE;
416 
417   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
418   sym_hashes = elf_sym_hashes (abfd);
419   local_plt_offsets = elf_local_got_offsets (abfd);
420   splt = NULL;
421   dynobj = elf_hash_table(info)->dynobj;
422 
423   relend = relocs + sec->reloc_count;
424   for (rel = relocs; rel < relend; ++rel)
425     {
426       unsigned long r_symndx;
427       struct elf_link_hash_entry *h;
428       bfd_vma *offset;
429 
430       r_symndx = ELF32_R_SYM (rel->r_info);
431       if (r_symndx < symtab_hdr->sh_info)
432 	h = NULL;
433       else
434 	{
435 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
436 	  while (h->root.type == bfd_link_hash_indirect
437 		 || h->root.type == bfd_link_hash_warning)
438 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
439 
440 	  /* PR15323, ref flags aren't set for references in the same
441 	     object.  */
442 	  h->root.non_ir_ref = 1;
443 	}
444 
445       switch (ELF32_R_TYPE (rel->r_info))
446         {
447 	  /* This relocation describes a 16-bit pointer to a function.
448 	     We may need to allocate a thunk in low memory; reserve memory
449 	     for it now.  */
450 	case R_XSTORMY16_FPTR16:
451 	  if (rel->r_addend != 0)
452 	    {
453 	      (*info->callbacks->warning)
454 		(info, _("non-zero addend in @fptr reloc"), 0,
455 		 abfd, 0, 0);
456 	    }
457 
458 	  if (dynobj == NULL)
459 	    elf_hash_table (info)->dynobj = dynobj = abfd;
460 	  if (splt == NULL)
461 	    {
462 	      splt = bfd_get_linker_section (dynobj, ".plt");
463 	      if (splt == NULL)
464 		{
465 		  flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
466 				    | SEC_IN_MEMORY | SEC_LINKER_CREATED
467 				    | SEC_READONLY | SEC_CODE);
468 
469 		  splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
470 							     flags);
471 		  if (splt == NULL
472 		      || ! bfd_set_section_alignment (dynobj, splt, 1))
473 		    return FALSE;
474 		}
475 	    }
476 
477 	  if (h != NULL)
478 	    offset = &h->plt.offset;
479 	  else
480 	    {
481 	      if (local_plt_offsets == NULL)
482 		{
483 		  size_t size;
484 		  unsigned int i;
485 
486 		  size = symtab_hdr->sh_info * sizeof (bfd_vma);
487 		  local_plt_offsets = bfd_alloc (abfd, size);
488 		  if (local_plt_offsets == NULL)
489 		    return FALSE;
490 		  elf_local_got_offsets (abfd) = local_plt_offsets;
491 
492 		  for (i = 0; i < symtab_hdr->sh_info; i++)
493 		    local_plt_offsets[i] = (bfd_vma) -1;
494 		}
495 	      offset = &local_plt_offsets[r_symndx];
496 	    }
497 
498 	  if (*offset == (bfd_vma) -1)
499 	    {
500 	      *offset = splt->size;
501 	      splt->size += 4;
502 	    }
503 	  break;
504 
505 	  /* This relocation describes the C++ object vtable hierarchy.
506 	     Reconstruct it for later use during GC.  */
507         case R_XSTORMY16_GNU_VTINHERIT:
508           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
509             return FALSE;
510           break;
511 
512 	  /* This relocation describes which C++ vtable entries are actually
513 	     used.  Record for later use during GC.  */
514         case R_XSTORMY16_GNU_VTENTRY:
515           BFD_ASSERT (h != NULL);
516           if (h != NULL
517               && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
518             return FALSE;
519           break;
520 	}
521     }
522 
523   return TRUE;
524 }
525 
526 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
527    is within the low 64k, remove any entry for it in the plt.  */
528 
529 struct relax_plt_data
530 {
531   asection *splt;
532   bfd_boolean *again;
533 };
534 
535 static bfd_boolean
xstormy16_relax_plt_check(struct elf_link_hash_entry * h,void * xdata)536 xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
537 {
538   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
539 
540   if (h->plt.offset != (bfd_vma) -1)
541     {
542       bfd_vma address;
543 
544       if (h->root.type == bfd_link_hash_undefined
545 	  || h->root.type == bfd_link_hash_undefweak)
546 	address = 0;
547       else
548 	address = (h->root.u.def.section->output_section->vma
549 		   + h->root.u.def.section->output_offset
550 		   + h->root.u.def.value);
551 
552       if (address <= 0xffff)
553 	{
554 	  h->plt.offset = -1;
555 	  data->splt->size -= 4;
556 	  *data->again = TRUE;
557 	}
558     }
559 
560   return TRUE;
561 }
562 
563 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
564    previously had a plt entry, give it a new entry offset.  */
565 
566 static bfd_boolean
xstormy16_relax_plt_realloc(struct elf_link_hash_entry * h,void * xdata)567 xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
568 {
569   bfd_vma *entry = (bfd_vma *) xdata;
570 
571   if (h->plt.offset != (bfd_vma) -1)
572     {
573       h->plt.offset = *entry;
574       *entry += 4;
575     }
576 
577   return TRUE;
578 }
579 
580 static bfd_boolean
xstormy16_elf_relax_section(bfd * dynobj,asection * splt,struct bfd_link_info * info,bfd_boolean * again)581 xstormy16_elf_relax_section (bfd *dynobj,
582 			     asection *splt,
583 			     struct bfd_link_info *info,
584 			     bfd_boolean *again)
585 {
586   struct relax_plt_data relax_plt_data;
587   bfd *ibfd;
588 
589   /* Assume nothing changes.  */
590   *again = FALSE;
591 
592   if (bfd_link_relocatable (info))
593     return TRUE;
594 
595   /* We only relax the .plt section at the moment.  */
596   if (dynobj != elf_hash_table (info)->dynobj
597       || strcmp (splt->name, ".plt") != 0)
598     return TRUE;
599 
600   /* Quick check for an empty plt.  */
601   if (splt->size == 0)
602     return TRUE;
603 
604   /* Map across all global symbols; see which ones happen to
605      fall in the low 64k.  */
606   relax_plt_data.splt = splt;
607   relax_plt_data.again = again;
608   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
609 			  &relax_plt_data);
610 
611   /* Likewise for local symbols, though that's somewhat less convenient
612      as we have to walk the list of input bfds and swap in symbol data.  */
613   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
614     {
615       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
616       Elf_Internal_Shdr *symtab_hdr;
617       Elf_Internal_Sym *isymbuf = NULL;
618       unsigned int idx;
619 
620       if (! local_plt_offsets)
621 	continue;
622 
623       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
624       if (symtab_hdr->sh_info != 0)
625 	{
626 	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
627 	  if (isymbuf == NULL)
628 	    isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
629 					    symtab_hdr->sh_info, 0,
630 					    NULL, NULL, NULL);
631 	  if (isymbuf == NULL)
632 	    return FALSE;
633 	}
634 
635       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
636 	{
637 	  Elf_Internal_Sym *isym;
638 	  asection *tsec;
639 	  bfd_vma address;
640 
641 	  if (local_plt_offsets[idx] == (bfd_vma) -1)
642 	    continue;
643 
644 	  isym = &isymbuf[idx];
645 	  if (isym->st_shndx == SHN_UNDEF)
646 	    continue;
647 	  else if (isym->st_shndx == SHN_ABS)
648 	    tsec = bfd_abs_section_ptr;
649 	  else if (isym->st_shndx == SHN_COMMON)
650 	    tsec = bfd_com_section_ptr;
651 	  else
652 	    tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
653 
654 	  address = (tsec->output_section->vma
655 		     + tsec->output_offset
656 		     + isym->st_value);
657 	  if (address <= 0xffff)
658 	    {
659 	      local_plt_offsets[idx] = -1;
660 	      splt->size -= 4;
661 	      *again = TRUE;
662 	    }
663 	}
664 
665       if (isymbuf != NULL
666 	  && symtab_hdr->contents != (unsigned char *) isymbuf)
667 	{
668 	  if (! info->keep_memory)
669 	    free (isymbuf);
670 	  else
671 	    {
672 	      /* Cache the symbols for elf_link_input_bfd.  */
673 	      symtab_hdr->contents = (unsigned char *) isymbuf;
674 	    }
675 	}
676     }
677 
678   /* If we changed anything, walk the symbols again to reallocate
679      .plt entry addresses.  */
680   if (*again && splt->size > 0)
681     {
682       bfd_vma entry = 0;
683 
684       elf_link_hash_traverse (elf_hash_table (info),
685 			      xstormy16_relax_plt_realloc, &entry);
686 
687       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
688 	{
689 	  bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
690 	  unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
691 	  unsigned int idx;
692 
693 	  if (! local_plt_offsets)
694 	    continue;
695 
696 	  for (idx = 0; idx < nlocals; ++idx)
697 	    if (local_plt_offsets[idx] != (bfd_vma) -1)
698 	      {
699 	        local_plt_offsets[idx] = entry;
700 		entry += 4;
701 	      }
702 	}
703     }
704 
705   return TRUE;
706 }
707 
708 static bfd_boolean
xstormy16_elf_always_size_sections(bfd * output_bfd ATTRIBUTE_UNUSED,struct bfd_link_info * info)709 xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
710 				    struct bfd_link_info *info)
711 {
712   bfd *dynobj;
713   asection *splt;
714 
715   if (bfd_link_relocatable (info))
716     return TRUE;
717 
718   dynobj = elf_hash_table (info)->dynobj;
719   if (dynobj == NULL)
720     return TRUE;
721 
722   splt = bfd_get_linker_section (dynobj, ".plt");
723   BFD_ASSERT (splt != NULL);
724 
725   splt->contents = bfd_zalloc (dynobj, splt->size);
726   if (splt->contents == NULL)
727     return FALSE;
728 
729   return TRUE;
730 }
731 
732 /* Relocate an XSTORMY16 ELF section.
733 
734    The RELOCATE_SECTION function is called by the new ELF backend linker
735    to handle the relocations for a section.
736 
737    The relocs are always passed as Rela structures; if the section
738    actually uses Rel structures, the r_addend field will always be
739    zero.
740 
741    This function is responsible for adjusting the section contents as
742    necessary, and (if using Rela relocs and generating a relocatable
743    output file) adjusting the reloc addend as necessary.
744 
745    This function does not have to worry about setting the reloc
746    address or the reloc symbol index.
747 
748    LOCAL_SYMS is a pointer to the swapped in local symbols.
749 
750    LOCAL_SECTIONS is an array giving the section in the input file
751    corresponding to the st_shndx field of each local symbol.
752 
753    The global hash table entry for the global symbols can be found
754    via elf_sym_hashes (input_bfd).
755 
756    When generating relocatable output, this function must handle
757    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
758    going to be the section symbol corresponding to the output
759    section, which means that the addend must be adjusted
760    accordingly.  */
761 
762 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)763 xstormy16_elf_relocate_section (bfd *                   output_bfd ATTRIBUTE_UNUSED,
764 				struct bfd_link_info *  info,
765 				bfd *                   input_bfd,
766 				asection *              input_section,
767 				bfd_byte *              contents,
768 				Elf_Internal_Rela *     relocs,
769 				Elf_Internal_Sym *      local_syms,
770 				asection **             local_sections)
771 {
772   Elf_Internal_Shdr *           symtab_hdr;
773   struct elf_link_hash_entry ** sym_hashes;
774   Elf_Internal_Rela *           rel;
775   Elf_Internal_Rela *           relend;
776   bfd *dynobj;
777   asection *splt;
778 
779   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
780   sym_hashes = elf_sym_hashes (input_bfd);
781   relend     = relocs + input_section->reloc_count;
782 
783   dynobj = elf_hash_table (info)->dynobj;
784   splt = NULL;
785   if (dynobj != NULL)
786     splt = bfd_get_linker_section (dynobj, ".plt");
787 
788   for (rel = relocs; rel < relend; rel ++)
789     {
790       reloc_howto_type *           howto;
791       unsigned long                r_symndx;
792       Elf_Internal_Sym *           sym;
793       asection *                   sec;
794       struct elf_link_hash_entry * h;
795       bfd_vma                      relocation;
796       bfd_reloc_status_type        r;
797       const char *                 name = NULL;
798       int                          r_type;
799 
800       r_type = ELF32_R_TYPE (rel->r_info);
801 
802       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
803 	  || r_type == R_XSTORMY16_GNU_VTENTRY)
804 	continue;
805 
806       r_symndx = ELF32_R_SYM (rel->r_info);
807       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
808       h      = NULL;
809       sym    = NULL;
810       sec    = NULL;
811 
812       if (r_symndx < symtab_hdr->sh_info)
813 	{
814 	  sym = local_syms + r_symndx;
815 	  sec = local_sections [r_symndx];
816 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
817 	}
818       else
819 	{
820 	  bfd_boolean unresolved_reloc, warned, ignored;
821 
822 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
823 				   r_symndx, symtab_hdr, sym_hashes,
824 				   h, sec, relocation,
825 				   unresolved_reloc, warned, ignored);
826 	}
827 
828       if (sec != NULL && discarded_section (sec))
829 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
830 					 rel, 1, relend, howto, 0, contents);
831 
832       if (bfd_link_relocatable (info))
833 	continue;
834 
835       if (h != NULL)
836 	name = h->root.root.string;
837       else
838 	{
839 	  name = (bfd_elf_string_from_elf_section
840 		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
841 	  if (name == NULL || *name == '\0')
842 	    name = bfd_section_name (input_bfd, sec);
843 	}
844 
845       switch (ELF32_R_TYPE (rel->r_info))
846 	{
847 	case R_XSTORMY16_24:
848 	  {
849 	    bfd_vma reloc = relocation + rel->r_addend;
850 	    unsigned int x;
851 
852 	    x = bfd_get_32 (input_bfd, contents + rel->r_offset);
853 	    x &= 0x0000ff00;
854 	    x |= reloc & 0xff;
855 	    x |= (reloc << 8) & 0xffff0000;
856 	    bfd_put_32 (input_bfd, x, contents + rel->r_offset);
857 
858 	    if (reloc & ~0xffffff)
859 	      r = bfd_reloc_overflow;
860 	    else
861 	      r = bfd_reloc_ok;
862 	    break;
863 	  }
864 
865 	case R_XSTORMY16_FPTR16:
866 	  {
867 	    bfd_vma *plt_offset;
868 
869 	    if (h != NULL)
870 	      plt_offset = &h->plt.offset;
871 	    else
872 	      plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
873 
874 	    if (relocation <= 0xffff)
875 	      {
876 	        /* If the symbol is in range for a 16-bit address, we should
877 		   have deallocated the plt entry in relax_section.  */
878 	        BFD_ASSERT (*plt_offset == (bfd_vma) -1);
879 	      }
880 	    else
881 	      {
882 		/* If the symbol is out of range for a 16-bit address,
883 		   we must have allocated a plt entry.  */
884 		BFD_ASSERT (*plt_offset != (bfd_vma) -1);
885 
886 		/* If this is the first time we've processed this symbol,
887 		   fill in the plt entry with the correct symbol address.  */
888 		if ((*plt_offset & 1) == 0)
889 		  {
890 		    unsigned int x;
891 
892 		    x = 0x00000200;  /* jmpf */
893 		    x |= relocation & 0xff;
894 		    x |= (relocation << 8) & 0xffff0000;
895 		    bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
896 		    *plt_offset |= 1;
897 		  }
898 
899 		relocation = (splt->output_section->vma
900 			      + splt->output_offset
901 			      + (*plt_offset & -2));
902 	      }
903 	    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
904 					  contents, rel->r_offset,
905 					  relocation, 0);
906 	    break;
907 	  }
908 
909 	default:
910 	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
911 					contents, rel->r_offset,
912 					relocation, rel->r_addend);
913 	  break;
914 	}
915 
916       if (r != bfd_reloc_ok)
917 	{
918 	  const char * msg = NULL;
919 
920 	  switch (r)
921 	    {
922 	    case bfd_reloc_overflow:
923 	      (*info->callbacks->reloc_overflow)
924 		(info, (h ? &h->root : NULL), name, howto->name,
925 		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
926 	      break;
927 
928 	    case bfd_reloc_undefined:
929 	      (*info->callbacks->undefined_symbol)
930 		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
931 	      break;
932 
933 	    case bfd_reloc_outofrange:
934 	      msg = _("internal error: out of range error");
935 	      break;
936 
937 	    case bfd_reloc_notsupported:
938 	      msg = _("internal error: unsupported relocation error");
939 	      break;
940 
941 	    case bfd_reloc_dangerous:
942 	      msg = _("internal error: dangerous relocation");
943 	      break;
944 
945 	    default:
946 	      msg = _("internal error: unknown error");
947 	      break;
948 	    }
949 
950 	  if (msg)
951 	    (*info->callbacks->warning) (info, msg, name, input_bfd,
952 					 input_section, rel->r_offset);
953 	}
954     }
955 
956   return TRUE;
957 }
958 
959 /* This must exist if dynobj is ever set.  */
960 
961 static bfd_boolean
xstormy16_elf_finish_dynamic_sections(bfd * abfd ATTRIBUTE_UNUSED,struct bfd_link_info * info)962 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
963 				       struct bfd_link_info *info)
964 {
965   bfd *dynobj;
966   asection *splt;
967 
968   /* As an extra sanity check, verify that all plt entries have
969      been filled in.  */
970 
971   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
972       && (splt = bfd_get_linker_section (dynobj, ".plt")) != NULL)
973     {
974       bfd_byte *contents = splt->contents;
975       unsigned int i, size = splt->size;
976 
977       for (i = 0; i < size; i += 4)
978 	{
979 	  unsigned int x = bfd_get_32 (dynobj, contents + i);
980 
981 	  BFD_ASSERT (x != 0);
982 	}
983     }
984 
985   return TRUE;
986 }
987 
988 /* Return the section that should be marked against GC for a given
989    relocation.  */
990 
991 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)992 xstormy16_elf_gc_mark_hook (asection *sec,
993 			    struct bfd_link_info *info,
994 			    Elf_Internal_Rela *rel,
995 			    struct elf_link_hash_entry *h,
996 			    Elf_Internal_Sym *sym)
997 {
998   if (h != NULL)
999     switch (ELF32_R_TYPE (rel->r_info))
1000       {
1001       case R_XSTORMY16_GNU_VTINHERIT:
1002       case R_XSTORMY16_GNU_VTENTRY:
1003 	return NULL;
1004       }
1005 
1006   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
1007 }
1008 
1009 #define ELF_ARCH		bfd_arch_xstormy16
1010 #define ELF_MACHINE_CODE	EM_XSTORMY16
1011 #define ELF_MAXPAGESIZE		0x100
1012 
1013 #define TARGET_LITTLE_SYM       xstormy16_elf32_vec
1014 #define TARGET_LITTLE_NAME	"elf32-xstormy16"
1015 
1016 #define elf_info_to_howto_rel			NULL
1017 #define elf_info_to_howto			xstormy16_info_to_howto_rela
1018 #define elf_backend_relocate_section		xstormy16_elf_relocate_section
1019 #define elf_backend_gc_mark_hook		xstormy16_elf_gc_mark_hook
1020 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1021 #define elf_backend_always_size_sections \
1022   xstormy16_elf_always_size_sections
1023 #define elf_backend_omit_section_dynsym \
1024   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
1025 #define elf_backend_finish_dynamic_sections \
1026   xstormy16_elf_finish_dynamic_sections
1027 
1028 #define elf_backend_can_gc_sections		1
1029 #define elf_backend_rela_normal			1
1030 
1031 #define bfd_elf32_bfd_reloc_type_lookup		xstormy16_reloc_type_lookup
1032 #define bfd_elf32_bfd_reloc_name_lookup \
1033   xstormy16_reloc_name_lookup
1034 #define bfd_elf32_bfd_relax_section		xstormy16_elf_relax_section
1035 
1036 #include "elf32-target.h"
1037