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