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