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