OSDN Git Service

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