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