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