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