bfd/
[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 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         RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
836                                          rel, relend, howto, contents);
837
838       if (info->relocatable)
839         continue;
840
841       if (h != NULL)
842         name = h->root.root.string;
843       else
844         {
845           name = (bfd_elf_string_from_elf_section
846                   (input_bfd, symtab_hdr->sh_link, sym->st_name));
847           if (name == NULL || *name == '\0')
848             name = bfd_section_name (input_bfd, sec);
849         }
850
851       switch (ELF32_R_TYPE (rel->r_info))
852         {
853         case R_XSTORMY16_24:
854           {
855             bfd_vma reloc = relocation + rel->r_addend;
856             unsigned int x;
857
858             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
859             x &= 0x0000ff00;
860             x |= reloc & 0xff;
861             x |= (reloc << 8) & 0xffff0000;
862             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
863
864             if (reloc & ~0xffffff)
865               r = bfd_reloc_overflow;
866             else
867               r = bfd_reloc_ok;
868             break;
869           }
870
871         case R_XSTORMY16_FPTR16:
872           {
873             bfd_vma *plt_offset;
874
875             if (h != NULL)
876               plt_offset = &h->plt.offset;
877             else
878               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
879
880             if (relocation <= 0xffff)
881               {
882                 /* If the symbol is in range for a 16-bit address, we should
883                    have deallocated the plt entry in relax_section.  */
884                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
885               }
886             else
887               {
888                 /* If the symbol is out of range for a 16-bit address,
889                    we must have allocated a plt entry.  */
890                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
891
892                 /* If this is the first time we've processed this symbol,
893                    fill in the plt entry with the correct symbol address.  */
894                 if ((*plt_offset & 1) == 0)
895                   {
896                     unsigned int x;
897
898                     x = 0x00000200;  /* jmpf */
899                     x |= relocation & 0xff;
900                     x |= (relocation << 8) & 0xffff0000;
901                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
902                     *plt_offset |= 1;
903                   }
904
905                 relocation = (splt->output_section->vma
906                               + splt->output_offset
907                               + (*plt_offset & -2));
908               }
909             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
910                                           contents, rel->r_offset,
911                                           relocation, 0);
912             break;
913           }
914
915         default:
916           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
917                                         contents, rel->r_offset,
918                                         relocation, rel->r_addend);
919           break;
920         }
921
922       if (r != bfd_reloc_ok)
923         {
924           const char * msg = NULL;
925
926           switch (r)
927             {
928             case bfd_reloc_overflow:
929               r = info->callbacks->reloc_overflow
930                 (info, (h ? &h->root : NULL), name, howto->name,
931                  (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
932               break;
933
934             case bfd_reloc_undefined:
935               r = info->callbacks->undefined_symbol
936                 (info, name, input_bfd, input_section, rel->r_offset,
937                  TRUE);
938               break;
939
940             case bfd_reloc_outofrange:
941               msg = _("internal error: out of range error");
942               break;
943
944             case bfd_reloc_notsupported:
945               msg = _("internal error: unsupported relocation error");
946               break;
947
948             case bfd_reloc_dangerous:
949               msg = _("internal error: dangerous relocation");
950               break;
951
952             default:
953               msg = _("internal error: unknown error");
954               break;
955             }
956
957           if (msg)
958             r = info->callbacks->warning
959               (info, msg, name, input_bfd, input_section, rel->r_offset);
960
961           if (! r)
962             return FALSE;
963         }
964     }
965
966   return TRUE;
967 }
968
969 /* This must exist if dynobj is ever set.  */
970
971 static bfd_boolean
972 xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
973                                        struct bfd_link_info *info)
974 {
975   bfd *dynobj;
976   asection *splt;
977
978   /* As an extra sanity check, verify that all plt entries have
979      been filled in.  */
980
981   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
982       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
983     {
984       bfd_byte *contents = splt->contents;
985       unsigned int i, size = splt->size;
986
987       for (i = 0; i < size; i += 4)
988         {
989           unsigned int x = bfd_get_32 (dynobj, contents + i);
990
991           BFD_ASSERT (x != 0);
992         }
993     }
994
995   return TRUE;
996 }
997 \f
998 /* Return the section that should be marked against GC for a given
999    relocation.  */
1000
1001 static asection *
1002 xstormy16_elf_gc_mark_hook (asection *sec,
1003                             struct bfd_link_info *info,
1004                             Elf_Internal_Rela *rel,
1005                             struct elf_link_hash_entry *h,
1006                             Elf_Internal_Sym *sym)
1007 {
1008   if (h != NULL)
1009     switch (ELF32_R_TYPE (rel->r_info))
1010       {
1011       case R_XSTORMY16_GNU_VTINHERIT:
1012       case R_XSTORMY16_GNU_VTENTRY:
1013         return NULL;
1014       }
1015
1016   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
1017 }
1018 \f
1019 #define ELF_ARCH                bfd_arch_xstormy16
1020 #define ELF_MACHINE_CODE        EM_XSTORMY16
1021 #define ELF_MAXPAGESIZE         0x100
1022
1023 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1024 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1025
1026 #define elf_info_to_howto_rel                   NULL
1027 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1028 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1029 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1030 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1031 #define elf_backend_always_size_sections \
1032   xstormy16_elf_always_size_sections
1033 #define elf_backend_omit_section_dynsym \
1034   ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
1035 #define elf_backend_finish_dynamic_sections \
1036   xstormy16_elf_finish_dynamic_sections
1037
1038 #define elf_backend_can_gc_sections             1
1039 #define elf_backend_rela_normal                 1
1040
1041 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1042 #define bfd_elf32_bfd_reloc_name_lookup \
1043   xstormy16_reloc_name_lookup
1044 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1045
1046 #include "elf32-target.h"