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