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