* elf-bfd.h (struct elf_reloc_cookie): Remove locsym_shndx,
[platform/upstream/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 *, Elf32_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      Elf32_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    There is some attempt to make this function usable for many architectures,
713    both USE_REL and USE_RELA ['twould be nice if such a critter existed],
714    if only to serve as a learning tool.
715
716    The RELOCATE_SECTION function is called by the new ELF backend linker
717    to handle the relocations for a section.
718
719    The relocs are always passed as Rela structures; if the section
720    actually uses Rel structures, the r_addend field will always be
721    zero.
722
723    This function is responsible for adjusting the section contents as
724    necessary, and (if using Rela relocs and generating a relocateable
725    output file) adjusting the reloc addend as necessary.
726
727    This function does not have to worry about setting the reloc
728    address or the reloc symbol index.
729
730    LOCAL_SYMS is a pointer to the swapped in local symbols.
731
732    LOCAL_SECTIONS is an array giving the section in the input file
733    corresponding to the st_shndx field of each local symbol.
734
735    The global hash table entry for the global symbols can be found
736    via elf_sym_hashes (input_bfd).
737
738    When generating relocateable output, this function must handle
739    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
740    going to be the section symbol corresponding to the output
741    section, which means that the addend must be adjusted
742    accordingly.  */
743
744 static boolean
745 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
746                            contents, relocs, local_syms, local_sections)
747      bfd *                   output_bfd ATTRIBUTE_UNUSED;
748      struct bfd_link_info *  info;
749      bfd *                   input_bfd;
750      asection *              input_section;
751      bfd_byte *              contents;
752      Elf_Internal_Rela *     relocs;
753      Elf_Internal_Sym *      local_syms;
754      asection **             local_sections;
755 {
756   Elf_Internal_Shdr *           symtab_hdr;
757   struct elf_link_hash_entry ** sym_hashes;
758   Elf_Internal_Rela *           rel;
759   Elf_Internal_Rela *           relend;
760   bfd *dynobj;
761   asection *splt;
762
763   if (info->relocateable)
764     return true;
765
766   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
767   sym_hashes = elf_sym_hashes (input_bfd);
768   relend     = relocs + input_section->reloc_count;
769
770   dynobj = elf_hash_table (info)->dynobj;
771   splt = NULL;
772   if (dynobj != NULL)
773     splt = bfd_get_section_by_name (dynobj, ".plt");
774
775   for (rel = relocs; rel < relend; rel ++)
776     {
777       reloc_howto_type *           howto;
778       unsigned long                r_symndx;
779       Elf_Internal_Sym *           sym;
780       asection *                   sec;
781       struct elf_link_hash_entry * h;
782       bfd_vma                      relocation;
783       bfd_reloc_status_type        r;
784       const char *                 name = NULL;
785       int                          r_type;
786
787       r_type = ELF32_R_TYPE (rel->r_info);
788
789       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
790           || r_type == R_XSTORMY16_GNU_VTENTRY)
791         continue;
792
793       r_symndx = ELF32_R_SYM (rel->r_info);
794       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
795       h      = NULL;
796       sym    = NULL;
797       sec    = NULL;
798
799       if (r_symndx < symtab_hdr->sh_info)
800         {
801           sym = local_syms + r_symndx;
802           sec = local_sections [r_symndx];
803           relocation = (sec->output_section->vma
804                         + sec->output_offset
805                         + sym->st_value);
806
807           name = bfd_elf_string_from_elf_section
808             (input_bfd, symtab_hdr->sh_link, sym->st_name);
809           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
810         }
811       else
812         {
813           h = sym_hashes [r_symndx - symtab_hdr->sh_info];
814
815           while (h->root.type == bfd_link_hash_indirect
816                  || h->root.type == bfd_link_hash_warning)
817             h = (struct elf_link_hash_entry *) h->root.u.i.link;
818
819           name = h->root.root.string;
820
821           if (h->root.type == bfd_link_hash_defined
822               || h->root.type == bfd_link_hash_defweak)
823             {
824               sec = h->root.u.def.section;
825               relocation = (h->root.u.def.value
826                             + sec->output_section->vma
827                             + sec->output_offset);
828             }
829           else if (h->root.type == bfd_link_hash_undefweak)
830             {
831               relocation = 0;
832             }
833           else
834             {
835               if (! ((*info->callbacks->undefined_symbol)
836                      (info, h->root.root.string, input_bfd,
837                       input_section, rel->r_offset, true)))
838                 return false;
839               relocation = 0;
840             }
841         }
842
843       switch (ELF32_R_TYPE (rel->r_info))
844         {
845         case R_XSTORMY16_24:
846           {
847             bfd_vma reloc = relocation + rel->r_addend;
848             unsigned int x;
849
850             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
851             x &= 0x0000ff00;
852             x |= reloc & 0xff;
853             x |= (reloc << 8) & 0xffff0000;
854             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
855
856             if (reloc & ~0xffffff)
857               r = bfd_reloc_overflow;
858             else
859               r = bfd_reloc_ok;
860             break;
861           }
862
863         case R_XSTORMY16_FPTR16:
864           {
865             bfd_vma *plt_offset;
866
867             if (h != NULL)
868               plt_offset = &h->plt.offset;
869             else
870               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
871
872             if (relocation <= 0xffff)
873               {
874                 /* If the symbol is in range for a 16-bit address, we should
875                    have deallocated the plt entry in relax_section.  */
876                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
877               }
878             else
879               {
880                 /* If the symbol is out of range for a 16-bit address,
881                    we must have allocated a plt entry.  */
882                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
883
884                 /* If this is the first time we've processed this symbol,
885                    fill in the plt entry with the correct symbol address.  */
886                 if ((*plt_offset & 1) == 0)
887                   {
888                     unsigned int x;
889
890                     x = 0x00000200;  /* jmpf */
891                     x |= relocation & 0xff;
892                     x |= (relocation << 8) & 0xffff0000;
893                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
894                     *plt_offset |= 1;
895                   }
896
897                 relocation = (splt->output_section->vma
898                               + splt->output_offset
899                               + (*plt_offset & -2));
900               }
901             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
902                                           contents, rel->r_offset,
903                                           relocation, 0);
904             break;
905           }
906
907         default:
908           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
909                                         contents, rel->r_offset,
910                                         relocation, rel->r_addend);
911           break;
912         }
913
914       if (r != bfd_reloc_ok)
915         {
916           const char * msg = (const char *) NULL;
917
918           switch (r)
919             {
920             case bfd_reloc_overflow:
921               r = info->callbacks->reloc_overflow
922                 (info, name, howto->name, (bfd_vma) 0,
923                  input_bfd, input_section, rel->r_offset);
924               break;
925
926             case bfd_reloc_undefined:
927               r = info->callbacks->undefined_symbol
928                 (info, name, input_bfd, input_section, rel->r_offset,
929                  true);
930               break;
931
932             case bfd_reloc_outofrange:
933               msg = _("internal error: out of range error");
934               break;
935
936             case bfd_reloc_notsupported:
937               msg = _("internal error: unsupported relocation error");
938               break;
939
940             case bfd_reloc_dangerous:
941               msg = _("internal error: dangerous relocation");
942               break;
943
944             default:
945               msg = _("internal error: unknown error");
946               break;
947             }
948
949           if (msg)
950             r = info->callbacks->warning
951               (info, msg, name, input_bfd, input_section, rel->r_offset);
952
953           if (! r)
954             return false;
955         }
956     }
957
958   return true;
959 }
960
961 /* This must exist if dynobj is ever set.  */
962
963 static boolean
964 xstormy16_elf_finish_dynamic_sections (abfd, info)
965      bfd *abfd ATTRIBUTE_UNUSED;
966      struct bfd_link_info *info;
967 {
968   bfd *dynobj;
969   asection *splt;
970
971   /* As an extra sanity check, verify that all plt entries have
972      been filled in.  */
973
974   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
975       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
976     {
977       bfd_byte *contents = splt->contents;
978       unsigned int i, size = splt->_raw_size;
979       for (i = 0; i < size; i += 4)
980         {
981           unsigned int x = bfd_get_32 (dynobj, contents + i);
982           BFD_ASSERT (x != 0);
983         }
984     }
985
986   return true;
987 }
988 \f
989 /* Return the section that should be marked against GC for a given
990    relocation.  */
991
992 static asection *
993 xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
994      asection *                   sec;
995      struct bfd_link_info *       info ATTRIBUTE_UNUSED;
996      Elf_Internal_Rela *          rel;
997      struct elf_link_hash_entry * h;
998      Elf_Internal_Sym *           sym;
999 {
1000   if (h != NULL)
1001     {
1002       switch (ELF32_R_TYPE (rel->r_info))
1003         {
1004         case R_XSTORMY16_GNU_VTINHERIT:
1005         case R_XSTORMY16_GNU_VTENTRY:
1006           break;
1007
1008         default:
1009           switch (h->root.type)
1010             {
1011             case bfd_link_hash_defined:
1012             case bfd_link_hash_defweak:
1013               return h->root.u.def.section;
1014
1015             case bfd_link_hash_common:
1016               return h->root.u.c.p->section;
1017
1018             default:
1019               break;
1020             }
1021         }
1022     }
1023   else
1024     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1025
1026   return NULL;
1027 }
1028
1029 /* Update the got entry reference counts for the section being removed.  */
1030
1031 static boolean
1032 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1033      bfd *                     abfd ATTRIBUTE_UNUSED;
1034      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
1035      asection *                sec ATTRIBUTE_UNUSED;
1036      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1037 {
1038   return true;
1039 }
1040 \f
1041 #define ELF_ARCH                bfd_arch_xstormy16
1042 #define ELF_MACHINE_CODE        EM_XSTORMY16
1043 #define ELF_MAXPAGESIZE         0x100
1044
1045 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1046 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1047
1048 #define elf_info_to_howto_rel                   NULL
1049 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1050 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1051 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1052 #define elf_backend_gc_sweep_hook               xstormy16_elf_gc_sweep_hook
1053 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1054 #define elf_backend_always_size_sections \
1055   xstormy16_elf_always_size_sections
1056 #define elf_backend_finish_dynamic_sections \
1057   xstormy16_elf_finish_dynamic_sections
1058
1059 #define elf_backend_can_gc_sections             1
1060 #define elf_backend_rela_normal                 1
1061
1062 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1063 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1064
1065 #include "elf32-target.h"