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 
30 static bfd_reloc_status_type
31 xstormy16_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 
71 static 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 
269 static 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 
305 typedef 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 
312 static 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 
331 static reloc_howto_type *
332 xstormy16_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 
353 static void
354 xstormy16_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 
376 static bfd_boolean
377 xstormy16_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 
501 struct relax_plt_data
502 {
503   asection *splt;
504   bfd_boolean *again;
505 };
506 
507 static bfd_boolean
508 xstormy16_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 
541 static bfd_boolean
542 xstormy16_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 
558 static bfd_boolean
559 xstormy16_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 
686 static bfd_boolean
687 xstormy16_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 
740 static bfd_boolean
741 xstormy16_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 
939 static bfd_boolean
940 xstormy16_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 
969 static asection *
970 xstormy16_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 
1007 static bfd_boolean
1008 xstormy16_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