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