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