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