Support for more than 64k ELF sections.
[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       Elf_Internal_Shdr *shndx_hdr;
581       Elf32_External_Sym *extsyms;
582       Elf_External_Sym_Shndx *shndx_buf;
583       unsigned int idx;
584
585       if (! local_plt_offsets)
586         continue;
587
588       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
589       shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr;
590
591       if (symtab_hdr->contents != NULL)
592         extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
593       else
594         {
595           bfd_size_type amt;
596
597           amt = symtab_hdr->sh_info;
598           amt *= sizeof (Elf32_External_Sym);
599           extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
600           if (extsyms == NULL)
601             return false;
602           if (bfd_seek (ibfd, symtab_hdr->sh_offset, SEEK_SET) != 0
603               || bfd_bread ((PTR) extsyms, amt, ibfd) != amt)
604             {
605             error_ret_free_extsyms:
606               free (extsyms);
607               return false;
608             }
609         }
610
611       shndx_buf = NULL;
612       if (shndx_hdr->sh_size != 0)
613         {
614           bfd_size_type amt;
615
616           amt = symtab_hdr->sh_info;
617           amt *= sizeof (Elf_External_Sym_Shndx);
618           shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
619           if (shndx_buf == NULL)
620             goto error_ret_free_extsyms;
621           if (bfd_seek (ibfd, shndx_hdr->sh_offset, SEEK_SET) != 0
622               || bfd_bread ((PTR) shndx_buf, amt, ibfd) != amt)
623             {
624               free (shndx_buf);
625               goto error_ret_free_extsyms;
626             }
627           shndx_hdr->contents = (bfd_byte *) shndx_buf;
628         }
629
630       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
631         {
632           Elf_External_Sym_Shndx *shndx;
633           Elf_Internal_Sym isym;
634           asection *tsec;
635           bfd_vma address;
636
637           if (local_plt_offsets[idx] == (bfd_vma) -1)
638             continue;
639
640           shndx = shndx_buf;
641           if (shndx != NULL)
642             shndx += idx;
643           bfd_elf32_swap_symbol_in (ibfd, extsyms + idx, shndx, &isym);
644           if (isym.st_shndx == SHN_UNDEF)
645             continue;
646           else if (isym.st_shndx == SHN_ABS)
647             tsec = bfd_abs_section_ptr;
648           else if (isym.st_shndx == SHN_COMMON)
649             tsec = bfd_com_section_ptr;
650           else
651             tsec = bfd_section_from_elf_index (ibfd, isym.st_shndx);
652
653           address = (tsec->output_section->vma
654                      + tsec->output_offset
655                      + isym.st_value);
656           if (address <= 0xffff)
657             {
658               local_plt_offsets[idx] = -1;
659               splt->_cooked_size -= 4;
660               *again = true;
661             }
662         }
663
664       if (shndx_buf != NULL)
665         free (shndx_buf);
666
667       if ((Elf32_External_Sym *) symtab_hdr->contents != extsyms)
668         free (extsyms);
669     }
670
671   /* If we changed anything, walk the symbols again to reallocate
672      .plt entry addresses.  */
673   if (*again && splt->_cooked_size > 0)
674     {
675       bfd_vma entry = 0;
676
677       elf_link_hash_traverse (elf_hash_table (info),
678                               xstormy16_relax_plt_realloc, &entry);
679
680       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
681         {
682           bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
683           unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
684           unsigned int idx;
685
686           if (! local_plt_offsets)
687             continue;
688
689           for (idx = 0; idx < nlocals; ++idx)
690             if (local_plt_offsets[idx] != (bfd_vma) -1)
691               {
692                 local_plt_offsets[idx] = entry;
693                 entry += 4;
694               }
695         }
696     }
697
698   splt->_raw_size = splt->_cooked_size;
699   return true;
700 }
701
702 static boolean
703 xstormy16_elf_always_size_sections (output_bfd, info)
704      bfd *output_bfd ATTRIBUTE_UNUSED;
705      struct bfd_link_info *info;
706 {
707   bfd *dynobj;
708   asection *splt;
709
710   if (info->relocateable)
711     return true;
712
713   dynobj = elf_hash_table (info)->dynobj;
714   if (dynobj == NULL)
715     return true;
716
717   splt = bfd_get_section_by_name (dynobj, ".plt");
718   BFD_ASSERT (splt != NULL);
719
720   splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->_raw_size);
721   if (splt->contents == NULL)
722     return false;
723
724   return true;
725 }
726 \f
727 /* Relocate an XSTORMY16 ELF section.
728    There is some attempt to make this function usable for many architectures,
729    both USE_REL and USE_RELA ['twould be nice if such a critter existed],
730    if only to serve as a learning tool.
731
732    The RELOCATE_SECTION function is called by the new ELF backend linker
733    to handle the relocations for a section.
734
735    The relocs are always passed as Rela structures; if the section
736    actually uses Rel structures, the r_addend field will always be
737    zero.
738
739    This function is responsible for adjusting the section contents as
740    necessary, and (if using Rela relocs and generating a relocateable
741    output file) adjusting the reloc addend as necessary.
742
743    This function does not have to worry about setting the reloc
744    address or the reloc symbol index.
745
746    LOCAL_SYMS is a pointer to the swapped in local symbols.
747
748    LOCAL_SECTIONS is an array giving the section in the input file
749    corresponding to the st_shndx field of each local symbol.
750
751    The global hash table entry for the global symbols can be found
752    via elf_sym_hashes (input_bfd).
753
754    When generating relocateable output, this function must handle
755    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
756    going to be the section symbol corresponding to the output
757    section, which means that the addend must be adjusted
758    accordingly.  */
759
760 static boolean
761 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
762                            contents, relocs, local_syms, local_sections)
763      bfd *                   output_bfd ATTRIBUTE_UNUSED;
764      struct bfd_link_info *  info;
765      bfd *                   input_bfd;
766      asection *              input_section;
767      bfd_byte *              contents;
768      Elf_Internal_Rela *     relocs;
769      Elf_Internal_Sym *      local_syms;
770      asection **             local_sections;
771 {
772   Elf_Internal_Shdr *           symtab_hdr;
773   struct elf_link_hash_entry ** sym_hashes;
774   Elf_Internal_Rela *           rel;
775   Elf_Internal_Rela *           relend;
776   bfd *dynobj;
777   asection *splt;
778
779   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
780   sym_hashes = elf_sym_hashes (input_bfd);
781   relend     = relocs + input_section->reloc_count;
782
783   dynobj = elf_hash_table (info)->dynobj;
784   splt = NULL;
785   if (dynobj != NULL)
786     splt = bfd_get_section_by_name (dynobj, ".plt");
787
788   for (rel = relocs; rel < relend; rel ++)
789     {
790       reloc_howto_type *           howto;
791       unsigned long                r_symndx;
792       Elf_Internal_Sym *           sym;
793       asection *                   sec;
794       struct elf_link_hash_entry * h;
795       bfd_vma                      relocation;
796       bfd_reloc_status_type        r;
797       const char *                 name = NULL;
798       int                          r_type;
799       
800       r_type = ELF32_R_TYPE (rel->r_info);
801       
802       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
803           || r_type == R_XSTORMY16_GNU_VTENTRY)
804         continue;
805       
806       r_symndx = ELF32_R_SYM (rel->r_info);
807
808       if (info->relocateable)
809         {
810           /* This is a relocateable link.  We don't have to change
811              anything, unless the reloc is against a section symbol,
812              in which case we have to adjust according to where the
813              section symbol winds up in the output section.  */
814           if (r_symndx < symtab_hdr->sh_info)
815             {
816               sym = local_syms + r_symndx;
817               
818               if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
819                 {
820                   sec = local_sections [r_symndx];
821                   rel->r_addend += sec->output_offset + sym->st_value;
822                 }
823             }
824
825           continue;
826         }
827
828       /* This is a final link.  */
829       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
830       h      = NULL;
831       sym    = NULL;
832       sec    = NULL;
833       
834       if (r_symndx < symtab_hdr->sh_info)
835         {
836           sym = local_syms + r_symndx;
837           sec = local_sections [r_symndx];
838           relocation = (sec->output_section->vma
839                         + sec->output_offset
840                         + sym->st_value);
841           
842           name = bfd_elf_string_from_elf_section
843             (input_bfd, symtab_hdr->sh_link, sym->st_name);
844           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
845         }
846       else
847         {
848           h = sym_hashes [r_symndx - symtab_hdr->sh_info];
849           
850           while (h->root.type == bfd_link_hash_indirect
851                  || h->root.type == bfd_link_hash_warning)
852             h = (struct elf_link_hash_entry *) h->root.u.i.link;
853
854           name = h->root.root.string;
855           
856           if (h->root.type == bfd_link_hash_defined
857               || h->root.type == bfd_link_hash_defweak)
858             {
859               sec = h->root.u.def.section;
860               relocation = (h->root.u.def.value
861                             + sec->output_section->vma
862                             + sec->output_offset);
863             }
864           else if (h->root.type == bfd_link_hash_undefweak)
865             {
866               relocation = 0;
867             }
868           else
869             {
870               if (! ((*info->callbacks->undefined_symbol)
871                      (info, h->root.root.string, input_bfd,
872                       input_section, rel->r_offset, true)))
873                 return false;
874               relocation = 0;
875             }
876         }
877       
878       switch (ELF32_R_TYPE (rel->r_info))
879         {
880         case R_XSTORMY16_24:
881           {
882             bfd_vma reloc = relocation + rel->r_addend;
883             unsigned int x;
884           
885             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
886             x &= 0x0000ff00;
887             x |= reloc & 0xff;
888             x |= (reloc << 8) & 0xffff0000;
889             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
890
891             if (reloc & ~0xffffff)
892               r = bfd_reloc_overflow;
893             else
894               r = bfd_reloc_ok;
895             break;
896           }
897
898         case R_XSTORMY16_FPTR16:
899           {
900             bfd_vma *plt_offset;
901
902             if (h != NULL)
903               plt_offset = &h->plt.offset;
904             else
905               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
906
907             if (relocation <= 0xffff)
908               {
909                 /* If the symbol is in range for a 16-bit address, we should
910                    have deallocated the plt entry in relax_section.  */
911                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
912               }
913             else
914               {
915                 /* If the symbol is out of range for a 16-bit address,
916                    we must have allocated a plt entry.  */
917                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
918
919                 /* If this is the first time we've processed this symbol,
920                    fill in the plt entry with the correct symbol address.  */
921                 if ((*plt_offset & 1) == 0)
922                   {
923                     unsigned int x;
924
925                     x = 0x00000200;  /* jmpf */
926                     x |= relocation & 0xff;
927                     x |= (relocation << 8) & 0xffff0000;
928                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
929                     *plt_offset |= 1;
930                   }
931
932                 relocation = (splt->output_section->vma
933                               + splt->output_offset
934                               + (*plt_offset & -2));
935               }
936             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
937                                           contents, rel->r_offset,
938                                           relocation, 0);
939             break;
940           }
941
942         default:
943           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
944                                         contents, rel->r_offset,
945                                         relocation, rel->r_addend);
946           break;
947         }
948
949       if (r != bfd_reloc_ok)
950         {
951           const char * msg = (const char *) NULL;
952
953           switch (r)
954             {
955             case bfd_reloc_overflow:
956               r = info->callbacks->reloc_overflow
957                 (info, name, howto->name, (bfd_vma) 0,
958                  input_bfd, input_section, rel->r_offset);
959               break;
960               
961             case bfd_reloc_undefined:
962               r = info->callbacks->undefined_symbol
963                 (info, name, input_bfd, input_section, rel->r_offset,
964                  true);
965               break;
966               
967             case bfd_reloc_outofrange:
968               msg = _("internal error: out of range error");
969               break;
970
971             case bfd_reloc_notsupported:
972               msg = _("internal error: unsupported relocation error");
973               break;
974
975             case bfd_reloc_dangerous:
976               msg = _("internal error: dangerous relocation");
977               break;
978
979             default:
980               msg = _("internal error: unknown error");
981               break;
982             }
983
984           if (msg)
985             r = info->callbacks->warning
986               (info, msg, name, input_bfd, input_section, rel->r_offset);
987
988           if (! r)
989             return false;
990         }
991     }
992
993   return true;
994 }
995
996 /* This must exist if dynobj is ever set.  */
997
998 static boolean
999 xstormy16_elf_finish_dynamic_sections (abfd, info)
1000      bfd *abfd ATTRIBUTE_UNUSED;
1001      struct bfd_link_info *info;
1002 {
1003   bfd *dynobj;
1004   asection *splt;
1005
1006   /* As an extra sanity check, verify that all plt entries have
1007      been filled in.  */
1008
1009   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
1010       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
1011     {
1012       bfd_byte *contents = splt->contents;
1013       unsigned int i, size = splt->_raw_size;
1014       for (i = 0; i < size; i += 4)
1015         {
1016           unsigned int x = bfd_get_32 (dynobj, contents + i);
1017           BFD_ASSERT (x != 0);
1018         }
1019     }
1020
1021   return true;
1022 }
1023 \f
1024 /* Return the section that should be marked against GC for a given
1025    relocation.  */
1026
1027 static asection *
1028 xstormy16_elf_gc_mark_hook (abfd, info, rel, h, sym)
1029      bfd *                        abfd;
1030      struct bfd_link_info *       info ATTRIBUTE_UNUSED;
1031      Elf_Internal_Rela *          rel;
1032      struct elf_link_hash_entry * h;
1033      Elf_Internal_Sym *           sym;
1034 {
1035   if (h != NULL)
1036     {
1037       switch (ELF32_R_TYPE (rel->r_info))
1038         {
1039         case R_XSTORMY16_GNU_VTINHERIT:
1040         case R_XSTORMY16_GNU_VTENTRY:
1041           break;
1042
1043         default:
1044           switch (h->root.type)
1045             {
1046             case bfd_link_hash_defined:
1047             case bfd_link_hash_defweak:
1048               return h->root.u.def.section;
1049
1050             case bfd_link_hash_common:
1051               return h->root.u.c.p->section;
1052
1053             default:
1054               break;
1055             }
1056         }
1057     }
1058   else
1059     {
1060       return bfd_section_from_elf_index (abfd, sym->st_shndx);
1061     }
1062
1063   return NULL;
1064 }
1065
1066 /* Update the got entry reference counts for the section being removed.  */
1067
1068 static boolean
1069 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1070      bfd *                     abfd ATTRIBUTE_UNUSED;
1071      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
1072      asection *                sec ATTRIBUTE_UNUSED;
1073      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1074 {
1075   return true;
1076 }
1077 \f
1078 #define ELF_ARCH                bfd_arch_xstormy16
1079 #define ELF_MACHINE_CODE        EM_XSTORMY16
1080 #define ELF_MAXPAGESIZE         0x100
1081
1082 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1083 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1084
1085 #define elf_info_to_howto_rel                   NULL
1086 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1087 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1088 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1089 #define elf_backend_gc_sweep_hook               xstormy16_elf_gc_sweep_hook
1090 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1091 #define elf_backend_always_size_sections \
1092   xstormy16_elf_always_size_sections
1093 #define elf_backend_finish_dynamic_sections \
1094   xstormy16_elf_finish_dynamic_sections
1095
1096 #define elf_backend_can_gc_sections             1
1097
1098 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1099 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1100
1101 #include "elf32-target.h"