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