include/elf/ChangeLog
[external/binutils.git] / bfd / elf32-xstormy16.c
1 /* XSTORMY16-specific support for 32-bit ELF.
2    Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/xstormy16.h"
25 #include "libiberty.h"
26
27 /* Forward declarations.  */
28 static reloc_howto_type * xstormy16_reloc_type_lookup
29   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
30 static void xstormy16_info_to_howto_rela
31   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
32 static bfd_reloc_status_type xstormy16_elf_24_reloc
33   PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol,
34            PTR data, asection *input_section, bfd *output_bfd,
35            char **error_message));
36 static boolean xstormy16_elf_check_relocs
37   PARAMS ((bfd *, struct bfd_link_info *, asection *,
38            const Elf_Internal_Rela *));
39 static boolean xstormy16_relax_plt_check
40   PARAMS ((struct elf_link_hash_entry *, PTR));
41 static boolean xstormy16_relax_plt_realloc
42   PARAMS ((struct elf_link_hash_entry *, PTR));
43 static boolean xstormy16_elf_relax_section
44   PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
45            boolean *again));
46 static boolean xstormy16_elf_always_size_sections
47   PARAMS ((bfd *, struct bfd_link_info *));
48 static boolean xstormy16_elf_relocate_section
49   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
50            Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
51 static boolean xstormy16_elf_finish_dynamic_sections
52   PARAMS((bfd *, struct bfd_link_info *));
53 static boolean xstormy16_elf_gc_sweep_hook
54   PARAMS ((bfd *, struct bfd_link_info *, asection *,
55            const Elf_Internal_Rela *));
56 static asection * xstormy16_elf_gc_mark_hook
57   PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
58            struct elf_link_hash_entry *, Elf_Internal_Sym *));
59
60 static reloc_howto_type xstormy16_elf_howto_table [] =
61 {
62   /* This reloc does nothing.  */
63   HOWTO (R_XSTORMY16_NONE,      /* type */
64          0,                     /* rightshift */
65          2,                     /* size (0 = byte, 1 = short, 2 = long) */
66          32,                    /* bitsize */
67          false,                 /* pc_relative */
68          0,                     /* bitpos */
69          complain_overflow_bitfield, /* complain_on_overflow */
70          bfd_elf_generic_reloc, /* special_function */
71          "R_XSTORMY16_NONE",    /* name */
72          false,                 /* partial_inplace */
73          0,                     /* src_mask */
74          0,                     /* dst_mask */
75          false),                /* pcrel_offset */
76
77   /* A 32 bit absolute relocation.  */
78   HOWTO (R_XSTORMY16_32,        /* type */
79          0,                     /* rightshift */
80          2,                     /* size (0 = byte, 1 = short, 2 = long) */
81          32,                    /* bitsize */
82          false,                 /* pc_relative */
83          0,                     /* bitpos */
84          complain_overflow_dont, /* complain_on_overflow */
85          bfd_elf_generic_reloc, /* special_function */
86          "R_XSTORMY16_32",      /* name */
87          false,                 /* partial_inplace */
88          0,                     /* src_mask */
89          0xffffffff,            /* dst_mask */
90          false),                /* pcrel_offset */
91
92   /* A 16 bit absolute relocation.  */
93   HOWTO (R_XSTORMY16_16,        /* type */
94          0,                     /* rightshift */
95          1,                     /* size (0 = byte, 1 = short, 2 = long) */
96          16,                    /* bitsize */
97          false,                 /* pc_relative */
98          0,                     /* bitpos */
99          complain_overflow_bitfield, /* complain_on_overflow */
100          bfd_elf_generic_reloc, /* special_function */
101          "R_XSTORMY16_16",      /* name */
102          false,                 /* partial_inplace */
103          0,                     /* src_mask */
104          0xffffffff,            /* dst_mask */
105          false),                /* pcrel_offset */
106
107   /* An 8 bit absolute relocation.  */
108   HOWTO (R_XSTORMY16_8, /* type */
109          0,                     /* rightshift */
110          0,                     /* size (0 = byte, 1 = short, 2 = long) */
111          8,                     /* bitsize */
112          false,                 /* pc_relative */
113          0,                     /* bitpos */
114          complain_overflow_bitfield, /* complain_on_overflow */
115          bfd_elf_generic_reloc, /* special_function */
116          "R_XSTORMY16_8",       /* name */
117          false,                 /* partial_inplace */
118          0,                     /* src_mask */
119          0xffffffff,            /* dst_mask */
120          false),                /* pcrel_offset */
121
122   /* A 32 bit pc-relative relocation.  */
123   HOWTO (R_XSTORMY16_PC32,      /* type */
124          0,                     /* rightshift */
125          2,                     /* size (0 = byte, 1 = short, 2 = long) */
126          32,                    /* bitsize */
127          true,                  /* pc_relative */
128          0,                     /* bitpos */
129          complain_overflow_dont, /* complain_on_overflow */
130          bfd_elf_generic_reloc, /* special_function */
131          "R_XSTORMY16_PC32",    /* name */
132          false,                 /* partial_inplace */
133          0,                     /* src_mask */
134          0xffffffff,            /* dst_mask */
135          true),         /* pcrel_offset */
136
137   /* A 16 bit pc-relative relocation.  */
138   HOWTO (R_XSTORMY16_PC16,      /* type */
139          0,                     /* rightshift */
140          1,                     /* size (0 = byte, 1 = short, 2 = long) */
141          16,                    /* bitsize */
142          true,                  /* pc_relative */
143          0,                     /* bitpos */
144          complain_overflow_signed, /* complain_on_overflow */
145          bfd_elf_generic_reloc, /* special_function */
146          "R_XSTORMY16_PC16",    /* name */
147          false,                 /* partial_inplace */
148          0,                     /* src_mask */
149          0xffffffff,            /* dst_mask */
150          true),         /* pcrel_offset */
151
152   /* An 8 bit pc-relative relocation.  */
153   HOWTO (R_XSTORMY16_PC8,       /* type */
154          0,                     /* rightshift */
155          0,                     /* size (0 = byte, 1 = short, 2 = long) */
156          8,                     /* bitsize */
157          true,                  /* pc_relative */
158          0,                     /* bitpos */
159          complain_overflow_signed, /* complain_on_overflow */
160          bfd_elf_generic_reloc, /* special_function */
161          "R_XSTORMY16_PC8",     /* name */
162          false,                 /* partial_inplace */
163          0,                     /* src_mask */
164          0xffffffff,            /* dst_mask */
165          true),         /* pcrel_offset */
166
167   /* A 12-bit pc-relative relocation suitable for the branch instructions.  */
168   HOWTO (R_XSTORMY16_REL_12,    /* type */
169          1,                     /* rightshift */
170          1,                     /* size (0 = byte, 1 = short, 2 = long) */
171          11,                    /* bitsize */
172          true,                  /* pc_relative */
173          1,                     /* bitpos */
174          complain_overflow_signed, /* complain_on_overflow */
175          bfd_elf_generic_reloc, /* special_function */
176          "R_XSTORMY16_REL_12",  /* name */
177          true,                  /* partial_inplace */
178          0,                     /* src_mask */
179          0x0fff,                /* dst_mask */
180          true),         /* pcrel_offset */
181
182   /* A 24-bit absolute relocation suitable for the jump instructions.  */
183   HOWTO (R_XSTORMY16_24,        /* type */
184          0,                     /* rightshift */
185          2,                     /* size (0 = byte, 1 = short, 2 = long) */
186          24,                    /* bitsize */
187          false,                 /* pc_relative */
188          0,                     /* bitpos */
189          complain_overflow_unsigned, /* complain_on_overflow */
190          xstormy16_elf_24_reloc,        /* special_function */
191          "R_XSTORMY16_24",      /* name */
192          true,                  /* partial_inplace */
193          0,                     /* src_mask */
194          0xffff00ff,            /* dst_mask */
195          true),         /* pcrel_offset */
196
197   /* A 16 bit absolute relocation to a function pointer.  */
198   HOWTO (R_XSTORMY16_FPTR16,    /* type */
199          0,                     /* rightshift */
200          1,                     /* size (0 = byte, 1 = short, 2 = long) */
201          16,                    /* bitsize */
202          false,                 /* pc_relative */
203          0,                     /* bitpos */
204          complain_overflow_bitfield, /* complain_on_overflow */
205          bfd_elf_generic_reloc, /* special_function */
206          "R_XSTORMY16_FPTR16",  /* name */
207          false,                 /* partial_inplace */
208          0,                     /* src_mask */
209          0xffffffff,            /* dst_mask */
210          false),                /* pcrel_offset */
211 };
212
213 static reloc_howto_type xstormy16_elf_howto_table2 [] =
214 {
215   /* GNU extension to record C++ vtable hierarchy */
216   HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
217          0,                     /* rightshift */
218          2,                     /* size (0 = byte, 1 = short, 2 = long) */
219          0,                     /* bitsize */
220          false,                 /* pc_relative */
221          0,                     /* bitpos */
222          complain_overflow_dont, /* complain_on_overflow */
223          NULL,                  /* special_function */
224          "R_XSTORMY16_GNU_VTINHERIT", /* name */
225          false,                 /* partial_inplace */
226          0,                     /* src_mask */
227          0,                     /* dst_mask */
228          false),                /* pcrel_offset */
229
230   /* GNU extension to record C++ vtable member usage */
231   HOWTO (R_XSTORMY16_GNU_VTENTRY,     /* type */
232          0,                     /* rightshift */
233          2,                     /* size (0 = byte, 1 = short, 2 = long) */
234          0,                     /* bitsize */
235          false,                 /* pc_relative */
236          0,                     /* bitpos */
237          complain_overflow_dont, /* complain_on_overflow */
238          _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
239          "R_XSTORMY16_GNU_VTENTRY",   /* name */
240          false,                 /* partial_inplace */
241          0,                     /* src_mask */
242          0,                     /* dst_mask */
243          false),                /* pcrel_offset */
244
245 };
246 \f
247 /* Map BFD reloc types to XSTORMY16 ELF reloc types.  */
248
249 typedef struct xstormy16_reloc_map
250 {
251   bfd_reloc_code_real_type  bfd_reloc_val;
252   unsigned int              xstormy16_reloc_val;
253   reloc_howto_type *        table;
254 } reloc_map;
255
256 static const reloc_map xstormy16_reloc_map [] =
257 {
258   { BFD_RELOC_NONE,                 R_XSTORMY16_NONE,          xstormy16_elf_howto_table },
259   { BFD_RELOC_32,                   R_XSTORMY16_32,            xstormy16_elf_howto_table },
260   { BFD_RELOC_16,                   R_XSTORMY16_16,            xstormy16_elf_howto_table },
261   { BFD_RELOC_8,                    R_XSTORMY16_8,             xstormy16_elf_howto_table },
262   { BFD_RELOC_32_PCREL,             R_XSTORMY16_PC32,          xstormy16_elf_howto_table },
263   { BFD_RELOC_16_PCREL,             R_XSTORMY16_PC16,          xstormy16_elf_howto_table },
264   { BFD_RELOC_8_PCREL,              R_XSTORMY16_PC8,           xstormy16_elf_howto_table },
265   { BFD_RELOC_XSTORMY16_REL_12,     R_XSTORMY16_REL_12,        xstormy16_elf_howto_table },
266   { BFD_RELOC_XSTORMY16_24,         R_XSTORMY16_24,            xstormy16_elf_howto_table },
267   { BFD_RELOC_XSTORMY16_FPTR16,     R_XSTORMY16_FPTR16,        xstormy16_elf_howto_table },
268   { BFD_RELOC_VTABLE_INHERIT,       R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 },
269   { BFD_RELOC_VTABLE_ENTRY,         R_XSTORMY16_GNU_VTENTRY,   xstormy16_elf_howto_table2 },
270 };
271
272 static reloc_howto_type *
273 xstormy16_reloc_type_lookup (abfd, code)
274      bfd * abfd ATTRIBUTE_UNUSED;
275      bfd_reloc_code_real_type code;
276 {
277   unsigned int i;
278
279   for (i = ARRAY_SIZE (xstormy16_reloc_map); --i;)
280     {
281       const reloc_map * entry;
282
283       entry = xstormy16_reloc_map + i;
284
285       if (entry->bfd_reloc_val == code)
286         return entry->table + (entry->xstormy16_reloc_val
287                                - entry->table[0].type);
288     }
289
290   return NULL;
291 }
292
293 /* Set the howto pointer for an XSTORMY16 ELF reloc.  */
294
295 static void
296 xstormy16_info_to_howto_rela (abfd, cache_ptr, dst)
297      bfd * abfd ATTRIBUTE_UNUSED;
298      arelent * cache_ptr;
299      Elf_Internal_Rela * dst;
300 {
301   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
302
303   if (r_type <= (unsigned int) R_XSTORMY16_FPTR16)
304     cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
305   else if (r_type - R_XSTORMY16_GNU_VTINHERIT
306            <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
307     cache_ptr->howto
308       = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
309   else
310     abort ();
311 }
312
313 /* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement.  */
314
315 static bfd_reloc_status_type
316 xstormy16_elf_24_reloc (abfd, reloc_entry, symbol, data, input_section,
317                          output_bfd, error_message)
318      bfd *abfd;
319      arelent *reloc_entry;
320      asymbol *symbol;
321      PTR data;
322      asection *input_section;
323      bfd *output_bfd;
324      char **error_message ATTRIBUTE_UNUSED;
325 {
326   bfd_vma relocation, x;
327
328   if (output_bfd != NULL)
329     {
330       reloc_entry->address += input_section->output_offset;
331       return bfd_reloc_ok;
332     }
333
334   if (reloc_entry->address > input_section->_cooked_size)
335     return bfd_reloc_outofrange;
336
337   if (bfd_is_com_section (symbol->section))
338     relocation = 0;
339   else
340     relocation = symbol->value;
341
342   relocation += symbol->section->output_section->vma;
343   relocation += symbol->section->output_offset;
344   relocation += reloc_entry->addend;
345
346   x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
347   x &= 0x0000ff00;
348   x |= relocation & 0xff;
349   x |= (relocation << 8) & 0xffff0000;
350   bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
351
352   if (relocation & ~ (bfd_vma) 0xffffff)
353     return bfd_reloc_overflow;
354
355   return bfd_reloc_ok;
356 }
357 \f
358 /* We support 16-bit pointers to code above 64k by generating a thunk
359    below 64k containing a JMPF instruction to the final address.  We
360    cannot, unfortunately, minimize the number of thunks unless the
361    -relax switch is given, as otherwise we have no idea where the
362    sections will fall in the address space.  */
363
364 static boolean
365 xstormy16_elf_check_relocs (abfd, info, sec, relocs)
366      bfd *abfd;
367      struct bfd_link_info *info;
368      asection *sec;
369      const Elf_Internal_Rela *relocs;
370 {
371   const Elf_Internal_Rela *rel, *relend;
372   struct elf_link_hash_entry **sym_hashes;
373   Elf_Internal_Shdr *symtab_hdr;
374   bfd_vma *local_plt_offsets;
375   asection *splt;
376   bfd *dynobj;
377
378   if (info->relocateable)
379     return true;
380
381   symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
382   sym_hashes = elf_sym_hashes (abfd);
383   local_plt_offsets = elf_local_got_offsets (abfd);
384   splt = NULL;
385   dynobj = elf_hash_table(info)->dynobj;
386
387   relend = relocs + sec->reloc_count;
388   for (rel = relocs; rel < relend; ++rel)
389     {
390       unsigned long r_symndx;
391       struct elf_link_hash_entry *h;
392       bfd_vma *offset;
393
394       r_symndx = ELF32_R_SYM (rel->r_info);
395       if (r_symndx < symtab_hdr->sh_info)
396         h = NULL;
397       else
398         {
399           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
400           while (h->root.type == bfd_link_hash_indirect
401                  || h->root.type == bfd_link_hash_warning)
402             h = (struct elf_link_hash_entry *) h->root.u.i.link;
403         }
404
405       switch (ELF32_R_TYPE (rel->r_info))
406         {
407           /* This relocation describes a 16-bit pointer to a function.
408              We may need to allocate a thunk in low memory; reserve memory
409              for it now.  */
410         case R_XSTORMY16_FPTR16:
411           if (rel->r_addend != 0)
412             {
413               (*info->callbacks->warning)
414                 (info, _("non-zero addend in @fptr reloc"), 0,
415                  abfd, 0, 0);
416             }
417
418           if (dynobj == NULL)
419             elf_hash_table (info)->dynobj = dynobj = abfd;
420           if (splt == NULL)
421             {
422               splt = bfd_get_section_by_name (dynobj, ".plt");
423               if (splt == NULL)
424                 {
425                   splt = bfd_make_section (dynobj, ".plt");
426                   if (splt == NULL
427                       || ! bfd_set_section_flags (dynobj, splt,
428                                                   (SEC_ALLOC
429                                                    | SEC_LOAD
430                                                    | SEC_HAS_CONTENTS
431                                                    | SEC_IN_MEMORY
432                                                    | SEC_LINKER_CREATED
433                                                    | SEC_READONLY
434                                                    | SEC_CODE))
435                       || ! bfd_set_section_alignment (dynobj, splt, 1))
436                     return false;
437                 }
438             }
439
440           if (h != NULL)
441             offset = &h->plt.offset;
442           else
443             {
444               if (local_plt_offsets == NULL)
445                 {
446                   size_t size;
447                   unsigned int i;
448
449                   size = symtab_hdr->sh_info * sizeof (bfd_vma);
450                   local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size);
451                   if (local_plt_offsets == NULL)
452                     return false;
453                   elf_local_got_offsets (abfd) = local_plt_offsets;
454
455                   for (i = 0; i < symtab_hdr->sh_info; i++)
456                     local_plt_offsets[i] = (bfd_vma) -1;
457                 }
458               offset = &local_plt_offsets[r_symndx];
459             }
460
461           if (*offset == (bfd_vma) -1)
462             {
463               *offset = splt->_raw_size;
464               splt->_raw_size += 4;
465             }
466           break;
467
468           /* This relocation describes the C++ object vtable hierarchy.
469              Reconstruct it for later use during GC.  */
470         case R_XSTORMY16_GNU_VTINHERIT:
471           if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
472             return false;
473           break;
474
475           /* This relocation describes which C++ vtable entries are actually
476              used.  Record for later use during GC.  */
477         case R_XSTORMY16_GNU_VTENTRY:
478           if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
479             return false;
480           break;
481         }
482     }
483
484   return true;
485 }
486
487 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
488    is within the low 64k, remove any entry for it in the plt.  */
489
490 struct relax_plt_data
491 {
492   asection *splt;
493   boolean *again;
494 };
495
496 static boolean
497 xstormy16_relax_plt_check (h, xdata)
498      struct elf_link_hash_entry *h;
499      PTR xdata;
500 {
501   struct relax_plt_data *data = (struct relax_plt_data *) xdata;
502
503   if (h->root.type == bfd_link_hash_warning)
504     h = (struct elf_link_hash_entry *) h->root.u.i.link;
505
506   if (h->plt.offset != (bfd_vma) -1)
507     {
508       bfd_vma address;
509
510       if (h->root.type == bfd_link_hash_undefined
511           || h->root.type == bfd_link_hash_undefweak)
512         address = 0;
513       else
514         address = (h->root.u.def.section->output_section->vma
515                    + h->root.u.def.section->output_offset
516                    + h->root.u.def.value);
517
518       if (address <= 0xffff)
519         {
520           h->plt.offset = -1;
521           data->splt->_cooked_size -= 4;
522           *data->again = true;
523         }
524     }
525
526   return true;
527 }
528
529 /* A subroutine of xstormy16_elf_relax_section.  If the global symbol H
530    previously had a plt entry, give it a new entry offset.  */
531
532 static boolean
533 xstormy16_relax_plt_realloc (h, xdata)
534      struct elf_link_hash_entry *h;
535      PTR xdata;
536 {
537   bfd_vma *entry = (bfd_vma *) xdata;
538
539   if (h->root.type == bfd_link_hash_warning)
540     h = (struct elf_link_hash_entry *) h->root.u.i.link;
541
542   if (h->plt.offset != (bfd_vma) -1)
543     {
544       h->plt.offset = *entry;
545       *entry += 4;
546     }
547
548   return true;
549 }
550
551 static boolean
552 xstormy16_elf_relax_section (dynobj, splt, info, again)
553      bfd *dynobj;
554      asection *splt;
555      struct bfd_link_info *info;
556      boolean *again;
557 {
558   struct relax_plt_data relax_plt_data;
559   bfd *ibfd;
560
561   /* Assume nothing changes.  */
562   *again = false;
563
564   if (info->relocateable)
565     return true;
566
567   /* We only relax the .plt section at the moment.  */
568   if (dynobj != elf_hash_table (info)->dynobj
569       || strcmp (splt->name, ".plt") != 0)
570     return true;
571
572   /* Quick check for an empty plt.  */
573   if (splt->_raw_size == 0)
574     return true;
575
576   /* If this is the first time we have been called for this section,
577      initialize the cooked size.  */
578   if (splt->_cooked_size == 0)
579     splt->_cooked_size = splt->_raw_size;
580
581   /* Map across all global symbols; see which ones happen to
582      fall in the low 64k.  */
583   relax_plt_data.splt = splt;
584   relax_plt_data.again = again;
585   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
586                           &relax_plt_data);
587
588   /* Likewise for local symbols, though that's somewhat less convenient
589      as we have to walk the list of input bfds and swap in symbol data.  */
590   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
591     {
592       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
593       Elf_Internal_Shdr *symtab_hdr;
594       Elf_Internal_Sym *isymbuf = NULL;
595       unsigned int idx;
596
597       if (! local_plt_offsets)
598         continue;
599
600       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
601       if (symtab_hdr->sh_info != 0)
602         {
603           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
604           if (isymbuf == NULL)
605             isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
606                                             symtab_hdr->sh_info, 0,
607                                             NULL, NULL, NULL);
608           if (isymbuf == NULL)
609             return false;
610         }
611
612       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
613         {
614           Elf_Internal_Sym *isym;
615           asection *tsec;
616           bfd_vma address;
617
618           if (local_plt_offsets[idx] == (bfd_vma) -1)
619             continue;
620
621           isym = &isymbuf[idx];
622           if (isym->st_shndx == SHN_UNDEF)
623             continue;
624           else if (isym->st_shndx == SHN_ABS)
625             tsec = bfd_abs_section_ptr;
626           else if (isym->st_shndx == SHN_COMMON)
627             tsec = bfd_com_section_ptr;
628           else
629             tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
630
631           address = (tsec->output_section->vma
632                      + tsec->output_offset
633                      + isym->st_value);
634           if (address <= 0xffff)
635             {
636               local_plt_offsets[idx] = -1;
637               splt->_cooked_size -= 4;
638               *again = true;
639             }
640         }
641
642       if (isymbuf != NULL
643           && symtab_hdr->contents != (unsigned char *) isymbuf)
644         {
645           if (! info->keep_memory)
646             free (isymbuf);
647           else
648             {
649               /* Cache the symbols for elf_link_input_bfd.  */
650               symtab_hdr->contents = (unsigned char *) isymbuf;
651             }
652         }
653     }
654
655   /* If we changed anything, walk the symbols again to reallocate
656      .plt entry addresses.  */
657   if (*again && splt->_cooked_size > 0)
658     {
659       bfd_vma entry = 0;
660
661       elf_link_hash_traverse (elf_hash_table (info),
662                               xstormy16_relax_plt_realloc, &entry);
663
664       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
665         {
666           bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
667           unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
668           unsigned int idx;
669
670           if (! local_plt_offsets)
671             continue;
672
673           for (idx = 0; idx < nlocals; ++idx)
674             if (local_plt_offsets[idx] != (bfd_vma) -1)
675               {
676                 local_plt_offsets[idx] = entry;
677                 entry += 4;
678               }
679         }
680     }
681
682   splt->_raw_size = splt->_cooked_size;
683   return true;
684 }
685
686 static boolean
687 xstormy16_elf_always_size_sections (output_bfd, info)
688      bfd *output_bfd ATTRIBUTE_UNUSED;
689      struct bfd_link_info *info;
690 {
691   bfd *dynobj;
692   asection *splt;
693
694   if (info->relocateable)
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_byte *) bfd_zalloc (dynobj, splt->_raw_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 relocateable
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 relocateable 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 boolean
742 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
743                            contents, relocs, local_syms, local_sections)
744      bfd *                   output_bfd ATTRIBUTE_UNUSED;
745      struct bfd_link_info *  info;
746      bfd *                   input_bfd;
747      asection *              input_section;
748      bfd_byte *              contents;
749      Elf_Internal_Rela *     relocs;
750      Elf_Internal_Sym *      local_syms;
751      asection **             local_sections;
752 {
753   Elf_Internal_Shdr *           symtab_hdr;
754   struct elf_link_hash_entry ** sym_hashes;
755   Elf_Internal_Rela *           rel;
756   Elf_Internal_Rela *           relend;
757   bfd *dynobj;
758   asection *splt;
759
760   if (info->relocateable)
761     return true;
762
763   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
764   sym_hashes = elf_sym_hashes (input_bfd);
765   relend     = relocs + input_section->reloc_count;
766
767   dynobj = elf_hash_table (info)->dynobj;
768   splt = NULL;
769   if (dynobj != NULL)
770     splt = bfd_get_section_by_name (dynobj, ".plt");
771
772   for (rel = relocs; rel < relend; rel ++)
773     {
774       reloc_howto_type *           howto;
775       unsigned long                r_symndx;
776       Elf_Internal_Sym *           sym;
777       asection *                   sec;
778       struct elf_link_hash_entry * h;
779       bfd_vma                      relocation;
780       bfd_reloc_status_type        r;
781       const char *                 name = NULL;
782       int                          r_type;
783
784       r_type = ELF32_R_TYPE (rel->r_info);
785
786       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
787           || r_type == R_XSTORMY16_GNU_VTENTRY)
788         continue;
789
790       r_symndx = ELF32_R_SYM (rel->r_info);
791       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
792       h      = NULL;
793       sym    = NULL;
794       sec    = NULL;
795
796       if (r_symndx < symtab_hdr->sh_info)
797         {
798           sym = local_syms + r_symndx;
799           sec = local_sections [r_symndx];
800           relocation = (sec->output_section->vma
801                         + sec->output_offset
802                         + sym->st_value);
803
804           name = bfd_elf_string_from_elf_section
805             (input_bfd, symtab_hdr->sh_link, sym->st_name);
806           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
807         }
808       else
809         {
810           h = sym_hashes [r_symndx - symtab_hdr->sh_info];
811
812           while (h->root.type == bfd_link_hash_indirect
813                  || h->root.type == bfd_link_hash_warning)
814             h = (struct elf_link_hash_entry *) h->root.u.i.link;
815
816           name = h->root.root.string;
817
818           if (h->root.type == bfd_link_hash_defined
819               || h->root.type == bfd_link_hash_defweak)
820             {
821               sec = h->root.u.def.section;
822               relocation = (h->root.u.def.value
823                             + sec->output_section->vma
824                             + sec->output_offset);
825             }
826           else if (h->root.type == bfd_link_hash_undefweak)
827             {
828               relocation = 0;
829             }
830           else
831             {
832               if (! ((*info->callbacks->undefined_symbol)
833                      (info, h->root.root.string, input_bfd,
834                       input_section, rel->r_offset, true)))
835                 return false;
836               relocation = 0;
837             }
838         }
839
840       switch (ELF32_R_TYPE (rel->r_info))
841         {
842         case R_XSTORMY16_24:
843           {
844             bfd_vma reloc = relocation + rel->r_addend;
845             unsigned int x;
846
847             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
848             x &= 0x0000ff00;
849             x |= reloc & 0xff;
850             x |= (reloc << 8) & 0xffff0000;
851             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
852
853             if (reloc & ~0xffffff)
854               r = bfd_reloc_overflow;
855             else
856               r = bfd_reloc_ok;
857             break;
858           }
859
860         case R_XSTORMY16_FPTR16:
861           {
862             bfd_vma *plt_offset;
863
864             if (h != NULL)
865               plt_offset = &h->plt.offset;
866             else
867               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
868
869             if (relocation <= 0xffff)
870               {
871                 /* If the symbol is in range for a 16-bit address, we should
872                    have deallocated the plt entry in relax_section.  */
873                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
874               }
875             else
876               {
877                 /* If the symbol is out of range for a 16-bit address,
878                    we must have allocated a plt entry.  */
879                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
880
881                 /* If this is the first time we've processed this symbol,
882                    fill in the plt entry with the correct symbol address.  */
883                 if ((*plt_offset & 1) == 0)
884                   {
885                     unsigned int x;
886
887                     x = 0x00000200;  /* jmpf */
888                     x |= relocation & 0xff;
889                     x |= (relocation << 8) & 0xffff0000;
890                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
891                     *plt_offset |= 1;
892                   }
893
894                 relocation = (splt->output_section->vma
895                               + splt->output_offset
896                               + (*plt_offset & -2));
897               }
898             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
899                                           contents, rel->r_offset,
900                                           relocation, 0);
901             break;
902           }
903
904         default:
905           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
906                                         contents, rel->r_offset,
907                                         relocation, rel->r_addend);
908           break;
909         }
910
911       if (r != bfd_reloc_ok)
912         {
913           const char * msg = (const char *) NULL;
914
915           switch (r)
916             {
917             case bfd_reloc_overflow:
918               r = info->callbacks->reloc_overflow
919                 (info, name, howto->name, (bfd_vma) 0,
920                  input_bfd, input_section, rel->r_offset);
921               break;
922
923             case bfd_reloc_undefined:
924               r = info->callbacks->undefined_symbol
925                 (info, name, input_bfd, input_section, rel->r_offset,
926                  true);
927               break;
928
929             case bfd_reloc_outofrange:
930               msg = _("internal error: out of range error");
931               break;
932
933             case bfd_reloc_notsupported:
934               msg = _("internal error: unsupported relocation error");
935               break;
936
937             case bfd_reloc_dangerous:
938               msg = _("internal error: dangerous relocation");
939               break;
940
941             default:
942               msg = _("internal error: unknown error");
943               break;
944             }
945
946           if (msg)
947             r = info->callbacks->warning
948               (info, msg, name, input_bfd, input_section, rel->r_offset);
949
950           if (! r)
951             return false;
952         }
953     }
954
955   return true;
956 }
957
958 /* This must exist if dynobj is ever set.  */
959
960 static boolean
961 xstormy16_elf_finish_dynamic_sections (abfd, info)
962      bfd *abfd ATTRIBUTE_UNUSED;
963      struct bfd_link_info *info;
964 {
965   bfd *dynobj;
966   asection *splt;
967
968   /* As an extra sanity check, verify that all plt entries have
969      been filled in.  */
970
971   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
972       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
973     {
974       bfd_byte *contents = splt->contents;
975       unsigned int i, size = splt->_raw_size;
976       for (i = 0; i < size; i += 4)
977         {
978           unsigned int x = bfd_get_32 (dynobj, contents + i);
979           BFD_ASSERT (x != 0);
980         }
981     }
982
983   return true;
984 }
985 \f
986 /* Return the section that should be marked against GC for a given
987    relocation.  */
988
989 static asection *
990 xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
991      asection *                   sec;
992      struct bfd_link_info *       info ATTRIBUTE_UNUSED;
993      Elf_Internal_Rela *          rel;
994      struct elf_link_hash_entry * h;
995      Elf_Internal_Sym *           sym;
996 {
997   if (h != NULL)
998     {
999       switch (ELF32_R_TYPE (rel->r_info))
1000         {
1001         case R_XSTORMY16_GNU_VTINHERIT:
1002         case R_XSTORMY16_GNU_VTENTRY:
1003           break;
1004
1005         default:
1006           switch (h->root.type)
1007             {
1008             case bfd_link_hash_defined:
1009             case bfd_link_hash_defweak:
1010               return h->root.u.def.section;
1011
1012             case bfd_link_hash_common:
1013               return h->root.u.c.p->section;
1014
1015             default:
1016               break;
1017             }
1018         }
1019     }
1020   else
1021     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1022
1023   return NULL;
1024 }
1025
1026 /* Update the got entry reference counts for the section being removed.  */
1027
1028 static boolean
1029 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1030      bfd *                     abfd ATTRIBUTE_UNUSED;
1031      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
1032      asection *                sec ATTRIBUTE_UNUSED;
1033      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1034 {
1035   return true;
1036 }
1037 \f
1038 #define ELF_ARCH                bfd_arch_xstormy16
1039 #define ELF_MACHINE_CODE        EM_XSTORMY16
1040 #define ELF_MAXPAGESIZE         0x100
1041
1042 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1043 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1044
1045 #define elf_info_to_howto_rel                   NULL
1046 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1047 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1048 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1049 #define elf_backend_gc_sweep_hook               xstormy16_elf_gc_sweep_hook
1050 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1051 #define elf_backend_always_size_sections \
1052   xstormy16_elf_always_size_sections
1053 #define elf_backend_finish_dynamic_sections \
1054   xstormy16_elf_finish_dynamic_sections
1055
1056 #define elf_backend_can_gc_sections             1
1057 #define elf_backend_rela_normal                 1
1058
1059 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1060 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1061
1062 #include "elf32-target.h"