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