daily update
[platform/upstream/binutils.git] / bfd / elf32-xstormy16.c
1 /* Xstormy16-specific support for 32-bit ELF.
2    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2010, 2011, 2012
3    Free Software Foundation, Inc.
4
5    This file is part of BFD, the Binary File Descriptor library.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #include "sysdep.h"
23 #include "bfd.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/xstormy16.h"
27 #include "libiberty.h"
28
29 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement.  */
30
31 static bfd_reloc_status_type
32 xstormy16_elf_24_reloc (bfd *abfd,
33                         arelent *reloc_entry,
34                         asymbol *symbol,
35                         void * data,
36                         asection *input_section,
37                         bfd *output_bfd,
38                         char **error_message ATTRIBUTE_UNUSED)
39 {
40   bfd_vma relocation, x;
41
42   if (output_bfd != NULL)
43     {
44       reloc_entry->address += input_section->output_offset;
45       return bfd_reloc_ok;
46     }
47
48   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
49     return bfd_reloc_outofrange;
50
51   if (bfd_is_com_section (symbol->section))
52     relocation = 0;
53   else
54     relocation = symbol->value;
55
56   relocation += symbol->section->output_section->vma;
57   relocation += symbol->section->output_offset;
58   relocation += reloc_entry->addend;
59
60   x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
61   x &= 0x0000ff00;
62   x |= relocation & 0xff;
63   x |= (relocation << 8) & 0xffff0000;
64   bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
65
66   if (relocation & ~ (bfd_vma) 0xffffff)
67     return bfd_reloc_overflow;
68
69   return bfd_reloc_ok;
70 }
71
72 static reloc_howto_type xstormy16_elf_howto_table [] =
73 {
74   /* This reloc does nothing.  */
75   HOWTO (R_XSTORMY16_NONE,      /* type */
76          0,                     /* rightshift */
77          2,                     /* size (0 = byte, 1 = short, 2 = long) */
78          32,                    /* bitsize */
79          FALSE,                 /* pc_relative */
80          0,                     /* bitpos */
81          complain_overflow_bitfield, /* complain_on_overflow */
82          bfd_elf_generic_reloc, /* special_function */
83          "R_XSTORMY16_NONE",    /* name */
84          FALSE,                 /* partial_inplace */
85          0,                     /* src_mask */
86          0,                     /* dst_mask */
87          FALSE),                /* pcrel_offset */
88
89   /* A 32 bit absolute relocation.  */
90   HOWTO (R_XSTORMY16_32,        /* type */
91          0,                     /* rightshift */
92          2,                     /* size (0 = byte, 1 = short, 2 = long) */
93          32,                    /* bitsize */
94          FALSE,                 /* pc_relative */
95          0,                     /* bitpos */
96          complain_overflow_dont, /* complain_on_overflow */
97          bfd_elf_generic_reloc, /* special_function */
98          "R_XSTORMY16_32",      /* name */
99          FALSE,                 /* partial_inplace */
100          0,                     /* src_mask */
101          0xffffffff,            /* dst_mask */
102          FALSE),                /* pcrel_offset */
103
104   /* A 16 bit absolute relocation.  */
105   HOWTO (R_XSTORMY16_16,        /* type */
106          0,                     /* rightshift */
107          1,                     /* size (0 = byte, 1 = short, 2 = long) */
108          16,                    /* bitsize */
109          FALSE,                 /* pc_relative */
110          0,                     /* bitpos */
111          complain_overflow_bitfield, /* complain_on_overflow */
112          bfd_elf_generic_reloc, /* special_function */
113          "R_XSTORMY16_16",      /* name */
114          FALSE,                 /* partial_inplace */
115          0,                     /* src_mask */
116          0xffff,                /* dst_mask */
117          FALSE),                /* pcrel_offset */
118
119   /* An 8 bit absolute relocation.  */
120   HOWTO (R_XSTORMY16_8,         /* type */
121          0,                     /* rightshift */
122          0,                     /* size (0 = byte, 1 = short, 2 = long) */
123          8,                     /* bitsize */
124          FALSE,                 /* pc_relative */
125          0,                     /* bitpos */
126          complain_overflow_unsigned, /* complain_on_overflow */
127          bfd_elf_generic_reloc, /* special_function */
128          "R_XSTORMY16_8",       /* name */
129          FALSE,                 /* partial_inplace */
130          0,                     /* src_mask */
131          0xff,                  /* dst_mask */
132          FALSE),                /* pcrel_offset */
133
134   /* A 32 bit pc-relative relocation.  */
135   HOWTO (R_XSTORMY16_PC32,      /* type */
136          0,                     /* rightshift */
137          2,                     /* size (0 = byte, 1 = short, 2 = long) */
138          32,                    /* bitsize */
139          TRUE,                  /* pc_relative */
140          0,                     /* bitpos */
141          complain_overflow_dont, /* complain_on_overflow */
142          bfd_elf_generic_reloc, /* special_function */
143          "R_XSTORMY16_PC32",    /* name */
144          FALSE,                 /* partial_inplace */
145          0,                     /* src_mask */
146          0xffffffff,            /* dst_mask */
147          TRUE),                 /* pcrel_offset */
148
149   /* A 16 bit pc-relative relocation.  */
150   HOWTO (R_XSTORMY16_PC16,      /* type */
151          0,                     /* rightshift */
152          1,                     /* size (0 = byte, 1 = short, 2 = long) */
153          16,                    /* bitsize */
154          TRUE,                  /* pc_relative */
155          0,                     /* bitpos */
156          complain_overflow_signed, /* complain_on_overflow */
157          bfd_elf_generic_reloc, /* special_function */
158          "R_XSTORMY16_PC16",    /* name */
159          FALSE,                 /* partial_inplace */
160          0,                     /* src_mask */
161          0xffffffff,            /* dst_mask */
162          TRUE),                 /* pcrel_offset */
163
164   /* An 8 bit pc-relative relocation.  */
165   HOWTO (R_XSTORMY16_PC8,       /* type */
166          0,                     /* rightshift */
167          0,                     /* size (0 = byte, 1 = short, 2 = long) */
168          8,                     /* bitsize */
169          TRUE,                  /* pc_relative */
170          0,                     /* bitpos */
171          complain_overflow_signed, /* complain_on_overflow */
172          bfd_elf_generic_reloc, /* special_function */
173          "R_XSTORMY16_PC8",     /* name */
174          FALSE,                 /* partial_inplace */
175          0,                     /* src_mask */
176          0xffffffff,            /* dst_mask */
177          TRUE),                 /* pcrel_offset */
178
179   /* A 12-bit pc-relative relocation suitable for the branch instructions.  */
180   HOWTO (R_XSTORMY16_REL_12,    /* type */
181          1,                     /* rightshift */
182          1,                     /* size (0 = byte, 1 = short, 2 = long) */
183          11,                    /* bitsize */
184          TRUE,                  /* pc_relative */
185          1,                     /* bitpos */
186          complain_overflow_signed, /* complain_on_overflow */
187          bfd_elf_generic_reloc, /* special_function */
188          "R_XSTORMY16_REL_12",  /* name */
189          FALSE,                 /* partial_inplace */
190          0,                     /* src_mask */
191          0x0ffe,                /* dst_mask */
192          TRUE),                 /* pcrel_offset */
193
194   /* A 24-bit absolute relocation suitable for the jump instructions.  */
195   HOWTO (R_XSTORMY16_24,        /* type */
196          0,                     /* rightshift */
197          2,                     /* size (0 = byte, 1 = short, 2 = long) */
198          24,                    /* bitsize */
199          FALSE,                 /* pc_relative */
200          0,                     /* bitpos */
201          complain_overflow_unsigned, /* complain_on_overflow */
202          xstormy16_elf_24_reloc,        /* special_function */
203          "R_XSTORMY16_24",      /* name */
204          TRUE,                  /* partial_inplace */
205          0,                     /* src_mask */
206          0xffff00ff,            /* dst_mask */
207          TRUE),                 /* pcrel_offset */
208
209   /* A 16 bit absolute relocation to a function pointer.  */
210   HOWTO (R_XSTORMY16_FPTR16,    /* type */
211          0,                     /* rightshift */
212          1,                     /* size (0 = byte, 1 = short, 2 = long) */
213          16,                    /* bitsize */
214          FALSE,                 /* pc_relative */
215          0,                     /* bitpos */
216          complain_overflow_bitfield, /* complain_on_overflow */
217          bfd_elf_generic_reloc, /* special_function */
218          "R_XSTORMY16_FPTR16",  /* name */
219          FALSE,                 /* partial_inplace */
220          0,                     /* src_mask */
221          0xffffffff,            /* dst_mask */
222          FALSE),                /* pcrel_offset */
223
224   /* Low order 16 bit value of a high memory address.  */
225   HOWTO (R_XSTORMY16_LO16,      /* type */
226          0,                     /* rightshift */
227          1,                     /* size (0 = byte, 1 = short, 2 = long) */
228          16,                    /* bitsize */
229          FALSE,                 /* pc_relative */
230          0,                     /* bitpos */
231          complain_overflow_dont, /* complain_on_overflow */
232          bfd_elf_generic_reloc, /* special_function */
233          "R_XSTORMY16_LO16",    /* name */
234          FALSE,                 /* partial_inplace */
235          0,                     /* src_mask */
236          0xffff,                /* dst_mask */
237          FALSE),                /* pcrel_offset */
238
239   /* High order 16 bit value of a high memory address.  */
240   HOWTO (R_XSTORMY16_HI16,      /* type */
241          16,                    /* rightshift */
242          1,                     /* size (0 = byte, 1 = short, 2 = long) */
243          16,                    /* bitsize */
244          FALSE,                 /* pc_relative */
245          0,                     /* bitpos */
246          complain_overflow_dont, /* complain_on_overflow */
247          bfd_elf_generic_reloc, /* special_function */
248          "R_XSTORMY16_HI16",    /* name */
249          FALSE,                 /* partial_inplace */
250          0,                     /* src_mask */
251          0xffff,                /* dst_mask */
252          FALSE),                /* pcrel_offset */
253
254   /* A 12 bit absolute relocation.  */
255   HOWTO (R_XSTORMY16_12,        /* type */
256          0,                     /* rightshift */
257          1,                     /* size (0 = byte, 1 = short, 2 = long) */
258          12,                    /* bitsize */
259          FALSE,                 /* pc_relative */
260          0,                     /* bitpos */
261          complain_overflow_signed, /* complain_on_overflow */
262          bfd_elf_generic_reloc, /* special_function */
263          "R_XSTORMY16_12",      /* name */
264          FALSE,                 /* partial_inplace */
265          0x0000,                /* src_mask */
266          0x0fff,                /* dst_mask */
267          FALSE),                /* pcrel_offset */
268 };
269
270 static reloc_howto_type xstormy16_elf_howto_table2 [] =
271 {
272   /* GNU extension to record C++ vtable hierarchy */
273   HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
274          0,                     /* rightshift */
275          2,                     /* size (0 = byte, 1 = short, 2 = long) */
276          0,                     /* bitsize */
277          FALSE,                 /* pc_relative */
278          0,                     /* bitpos */
279          complain_overflow_dont, /* complain_on_overflow */
280          NULL,                  /* special_function */
281          "R_XSTORMY16_GNU_VTINHERIT", /* name */
282          FALSE,                 /* partial_inplace */
283          0,                     /* src_mask */
284          0,                     /* dst_mask */
285          FALSE),                /* pcrel_offset */
286
287   /* GNU extension to record C++ vtable member usage */
288   HOWTO (R_XSTORMY16_GNU_VTENTRY,     /* type */
289          0,                     /* rightshift */
290          2,                     /* size (0 = byte, 1 = short, 2 = long) */
291          0,                     /* bitsize */
292          FALSE,                 /* pc_relative */
293          0,                     /* bitpos */
294          complain_overflow_dont, /* complain_on_overflow */
295          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
296          "R_XSTORMY16_GNU_VTENTRY",   /* name */
297          FALSE,                 /* partial_inplace */
298          0,                     /* src_mask */
299          0,                     /* dst_mask */
300          FALSE),                /* pcrel_offset */
301
302 };
303 \f
304 /* Map BFD reloc types to XSTORMY16 ELF reloc types.  */
305
306 typedef struct xstormy16_reloc_map
307 {
308   bfd_reloc_code_real_type  bfd_reloc_val;
309   unsigned int              xstormy16_reloc_val;
310   reloc_howto_type *        table;
311 } reloc_map;
312
313 static const reloc_map xstormy16_reloc_map [] =
314 {
315   { BFD_RELOC_NONE,                 R_XSTORMY16_NONE,          xstormy16_elf_howto_table },
316   { BFD_RELOC_32,                   R_XSTORMY16_32,            xstormy16_elf_howto_table },
317   { BFD_RELOC_16,                   R_XSTORMY16_16,            xstormy16_elf_howto_table },
318   { BFD_RELOC_8,                    R_XSTORMY16_8,             xstormy16_elf_howto_table },
319   { BFD_RELOC_32_PCREL,             R_XSTORMY16_PC32,          xstormy16_elf_howto_table },
320   { BFD_RELOC_16_PCREL,             R_XSTORMY16_PC16,          xstormy16_elf_howto_table },
321   { BFD_RELOC_8_PCREL,              R_XSTORMY16_PC8,           xstormy16_elf_howto_table },
322   { BFD_RELOC_XSTORMY16_REL_12,     R_XSTORMY16_REL_12,        xstormy16_elf_howto_table },
323   { BFD_RELOC_XSTORMY16_24,         R_XSTORMY16_24,            xstormy16_elf_howto_table },
324   { BFD_RELOC_XSTORMY16_FPTR16,     R_XSTORMY16_FPTR16,        xstormy16_elf_howto_table },
325   { BFD_RELOC_LO16,                 R_XSTORMY16_LO16,          xstormy16_elf_howto_table },
326   { BFD_RELOC_HI16,                 R_XSTORMY16_HI16,          xstormy16_elf_howto_table },
327   { BFD_RELOC_XSTORMY16_12,         R_XSTORMY16_12,            xstormy16_elf_howto_table },
328   { BFD_RELOC_VTABLE_INHERIT,       R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
329   { BFD_RELOC_VTABLE_ENTRY,         R_XSTORMY16_GNU_VTENTRY,   xstormy16_elf_howto_table2 },
330 };
331
332 static reloc_howto_type *
333 xstormy16_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
334                              bfd_reloc_code_real_type code)
335 {
336   unsigned int i;
337
338   for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
339     {
340       const reloc_map * entry;
341
342       entry = xstormy16_reloc_map + i;
343
344       if (entry->bfd_reloc_val == code)
345         return entry->table + (entry->xstormy16_reloc_val
346                                - entry->table[0].type);
347     }
348
349   return NULL;
350 }
351
352 static reloc_howto_type *
353 xstormy16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
354                              const char *r_name)
355 {
356   unsigned int i;
357
358   for (i = 0;
359        i < (sizeof (xstormy16_elf_howto_table)
360             / sizeof (xstormy16_elf_howto_table[0]));
361        i++)
362     if (xstormy16_elf_howto_table[i].name != NULL
363         && strcasecmp (xstormy16_elf_howto_table[i].name, r_name) == 0)
364       return &xstormy16_elf_howto_table[i];
365
366   for (i = 0;
367        i < (sizeof (xstormy16_elf_howto_table2)
368             / sizeof (xstormy16_elf_howto_table2[0]));
369        i++)
370     if (xstormy16_elf_howto_table2[i].name != NULL
371         && strcasecmp (xstormy16_elf_howto_table2[i].name, r_name) == 0)
372       return &xstormy16_elf_howto_table2[i];
373
374   return NULL;
375 }
376
377 /* Set the howto pointer for an XSTORMY16 ELF reloc.  */
378
379 static void
380 xstormy16_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
381                               arelent * cache_ptr,
382                               Elf_Internal_Rela * dst)
383 {
384   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
385
386   if (r_type <= (unsigned int) R_XSTORMY16_12)
387     cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
388   else if (r_type - R_XSTORMY16_GNU_VTINHERIT
389            <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
390     cache_ptr->howto
391       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
392   else
393     abort ();
394 }
395 \f
396 /* We support 16-bit pointers to code above 64k by generating a thunk
397    below 64k containing a JMPF instruction to the final address.  We
398    cannot, unfortunately, minimize the number of thunks unless the
399    -relax switch is given, as otherwise we have no idea where the
400    sections will fall in the address space.  */
401
402 static bfd_boolean
403 xstormy16_elf_check_relocs (bfd *abfd,
404                             struct bfd_link_info *info,
405                             asection *sec,
406                             const Elf_Internal_Rela *relocs)
407 {
408   const Elf_Internal_Rela *rel, *relend;
409   struct elf_link_hash_entry **sym_hashes;
410   Elf_Internal_Shdr *symtab_hdr;
411   bfd_vma *local_plt_offsets;
412   asection *splt;
413   bfd *dynobj;
414
415   if (info->relocatable)
416     return TRUE;
417
418   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
419   sym_hashes = elf_sym_hashes (abfd);
420   local_plt_offsets = elf_local_got_offsets (abfd);
421   splt = NULL;
422   dynobj = elf_hash_table(info)->dynobj;
423
424   relend = relocs + sec->reloc_count;
425   for (rel = relocs; rel < relend; ++rel)
426     {
427       unsigned long r_symndx;
428       struct elf_link_hash_entry *h;
429       bfd_vma *offset;
430
431       r_symndx = ELF32_R_SYM (rel->r_info);
432       if (r_symndx < symtab_hdr->sh_info)
433         h = NULL;
434       else
435         {
436           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
437           while (h->root.type == bfd_link_hash_indirect
438                  || h->root.type == bfd_link_hash_warning)
439             h = (struct elf_link_hash_entry *) h->root.u.i.link;
440
441           /* PR15323, ref flags aren't set for references in the same
442              object.  */
443           h->root.non_ir_ref = 1;
444         }
445
446       switch (ELF32_R_TYPE (rel->r_info))
447         {
448           /* This relocation describes a 16-bit pointer to a function.
449              We may need to allocate a thunk in low memory; reserve memory
450              for it now.  */
451         case R_XSTORMY16_FPTR16:
452           if (rel->r_addend != 0)
453             {
454               (*info->callbacks->warning)
455                 (info, _("non-zero addend in @fptr reloc"), 0,
456                  abfd, 0, 0);
457             }
458
459           if (dynobj == NULL)
460             elf_hash_table (info)->dynobj = dynobj = abfd;
461           if (splt == NULL)
462             {
463               splt = bfd_get_linker_section (dynobj, ".plt");
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                   if (splt == NULL
473                       || ! bfd_set_section_alignment (dynobj, splt, 1))
474                     return FALSE;
475                 }
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 (info->relocatable)
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 (info->relocatable)
717     return TRUE;
718
719   dynobj = elf_hash_table (info)->dynobj;
720   if (dynobj == NULL)
721     return TRUE;
722
723   splt = bfd_get_linker_section (dynobj, ".plt");
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   bfd *dynobj;
778   asection *splt;
779
780   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
781   sym_hashes = elf_sym_hashes (input_bfd);
782   relend     = relocs + input_section->reloc_count;
783
784   dynobj = elf_hash_table (info)->dynobj;
785   splt = NULL;
786   if (dynobj != NULL)
787     splt = bfd_get_linker_section (dynobj, ".plt");
788
789   for (rel = relocs; rel < relend; rel ++)
790     {
791       reloc_howto_type *           howto;
792       unsigned long                r_symndx;
793       Elf_Internal_Sym *           sym;
794       asection *                   sec;
795       struct elf_link_hash_entry * h;
796       bfd_vma                      relocation;
797       bfd_reloc_status_type        r;
798       const char *                 name = NULL;
799       int                          r_type;
800
801       r_type = ELF32_R_TYPE (rel->r_info);
802
803       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
804           || r_type == R_XSTORMY16_GNU_VTENTRY)
805         continue;
806
807       r_symndx = ELF32_R_SYM (rel->r_info);
808       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
809       h      = NULL;
810       sym    = NULL;
811       sec    = NULL;
812
813       if (r_symndx < symtab_hdr->sh_info)
814         {
815           sym = local_syms + r_symndx;
816           sec = local_sections [r_symndx];
817           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
818         }
819       else
820         {
821           bfd_boolean unresolved_reloc, warned;
822
823           RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
824                                    r_symndx, symtab_hdr, sym_hashes,
825                                    h, sec, relocation,
826                                    unresolved_reloc, warned);
827         }
828
829       if (sec != NULL && discarded_section (sec))
830         RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
831                                          rel, 1, relend, howto, 0, contents);
832
833       if (info->relocatable)
834         continue;
835
836       if (h != NULL)
837         name = h->root.root.string;
838       else
839         {
840           name = (bfd_elf_string_from_elf_section
841                   (input_bfd, symtab_hdr->sh_link, sym->st_name));
842           if (name == NULL || *name == '\0')
843             name = bfd_section_name (input_bfd, sec);
844         }
845
846       switch (ELF32_R_TYPE (rel->r_info))
847         {
848         case R_XSTORMY16_24:
849           {
850             bfd_vma reloc = relocation + rel->r_addend;
851             unsigned int x;
852
853             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
854             x &= 0x0000ff00;
855             x |= reloc & 0xff;
856             x |= (reloc << 8) & 0xffff0000;
857             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
858
859             if (reloc & ~0xffffff)
860               r = bfd_reloc_overflow;
861             else
862               r = bfd_reloc_ok;
863             break;
864           }
865
866         case R_XSTORMY16_FPTR16:
867           {
868             bfd_vma *plt_offset;
869
870             if (h != NULL)
871               plt_offset = &h->plt.offset;
872             else
873               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
874
875             if (relocation <= 0xffff)
876               {
877                 /* If the symbol is in range for a 16-bit address, we should
878                    have deallocated the plt entry in relax_section.  */
879                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
880               }
881             else
882               {
883                 /* If the symbol is out of range for a 16-bit address,
884                    we must have allocated a plt entry.  */
885                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
886
887                 /* If this is the first time we've processed this symbol,
888                    fill in the plt entry with the correct symbol address.  */
889                 if ((*plt_offset & 1) == 0)
890                   {
891                     unsigned int x;
892
893                     x = 0x00000200;  /* jmpf */
894                     x |= relocation & 0xff;
895                     x |= (relocation << 8) & 0xffff0000;
896                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
897                     *plt_offset |= 1;
898                   }
899
900                 relocation = (splt->output_section->vma
901                               + splt->output_offset
902                               + (*plt_offset & -2));
903               }
904             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
905                                           contents, rel->r_offset,
906                                           relocation, 0);
907             break;
908           }
909
910         default:
911           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
912                                         contents, rel->r_offset,
913                                         relocation, rel->r_addend);
914           break;
915         }
916
917       if (r != bfd_reloc_ok)
918         {
919           const char * msg = NULL;
920
921           switch (r)
922             {
923             case bfd_reloc_overflow:
924               r = info->callbacks->reloc_overflow
925                 (info, (h ? &h->root : NULL), name, howto->name,
926                  (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
927               break;
928
929             case bfd_reloc_undefined:
930               r = info->callbacks->undefined_symbol
931                 (info, name, input_bfd, input_section, rel->r_offset,
932                  TRUE);
933               break;
934
935             case bfd_reloc_outofrange:
936               msg = _("internal error: out of range error");
937               break;
938
939             case bfd_reloc_notsupported:
940               msg = _("internal error: unsupported relocation error");
941               break;
942
943             case bfd_reloc_dangerous:
944               msg = _("internal error: dangerous relocation");
945               break;
946
947             default:
948               msg = _("internal error: unknown error");
949               break;
950             }
951
952           if (msg)
953             r = info->callbacks->warning
954               (info, msg, name, input_bfd, input_section, rel->r_offset);
955
956           if (! r)
957             return FALSE;
958         }
959     }
960
961   return TRUE;
962 }
963
964 /* This must exist if dynobj is ever set.  */
965
966 static bfd_boolean
967 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
968                                        struct bfd_link_info *info)
969 {
970   bfd *dynobj;
971   asection *splt;
972
973   /* As an extra sanity check, verify that all plt entries have
974      been filled in.  */
975
976   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
977       && (splt = bfd_get_linker_section (dynobj, ".plt")) != NULL)
978     {
979       bfd_byte *contents = splt->contents;
980       unsigned int i, size = splt->size;
981
982       for (i = 0; i < size; i += 4)
983         {
984           unsigned int x = bfd_get_32 (dynobj, contents + i);
985
986           BFD_ASSERT (x != 0);
987         }
988     }
989
990   return TRUE;
991 }
992 \f
993 /* Return the section that should be marked against GC for a given
994    relocation.  */
995
996 static asection *
997 xstormy16_elf_gc_mark_hook (asection *sec,
998                             struct bfd_link_info *info,
999                             Elf_Internal_Rela *rel,
1000                             struct elf_link_hash_entry *h,
1001                             Elf_Internal_Sym *sym)
1002 {
1003   if (h != NULL)
1004     switch (ELF32_R_TYPE (rel->r_info))
1005       {
1006       case R_XSTORMY16_GNU_VTINHERIT:
1007       case R_XSTORMY16_GNU_VTENTRY:
1008         return NULL;
1009       }
1010
1011   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
1012 }
1013 \f
1014 #define ELF_ARCH                bfd_arch_xstormy16
1015 #define ELF_MACHINE_CODE        EM_XSTORMY16
1016 #define ELF_MAXPAGESIZE         0x100
1017
1018 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1019 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1020
1021 #define elf_info_to_howto_rel                   NULL
1022 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1023 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1024 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1025 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1026 #define elf_backend_always_size_sections \
1027   xstormy16_elf_always_size_sections
1028 #define elf_backend_omit_section_dynsym \
1029   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
1030 #define elf_backend_finish_dynamic_sections \
1031   xstormy16_elf_finish_dynamic_sections
1032
1033 #define elf_backend_can_gc_sections             1
1034 #define elf_backend_rela_normal                 1
1035
1036 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1037 #define bfd_elf32_bfd_reloc_name_lookup \
1038   xstormy16_reloc_name_lookup
1039 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1040
1041 #include "elf32-target.h"