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