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