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