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