OSDN Git Service

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