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