* reloc.c: Add BFD_RELOC_XSTORMY16_12.
[external/binutils.git] / bfd / elf32-xstormy16.c
1 /* XSTORMY16-specific support for 32-bit ELF.
2    Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "libbfd.h"
23 #include "elf-bfd.h"
24 #include "elf/xstormy16.h"
25 #include "libiberty.h"
26
27 /* Forward declarations.  */
28 static reloc_howto_type * xstormy16_reloc_type_lookup
29   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
30 static void xstormy16_info_to_howto_rela
31   PARAMS ((bfd *, arelent *, 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          0xffffffff,            /* dst_mask */
105          FALSE),                /* pcrel_offset */
106
107   /* An 8 bit absolute relocation.  */
108   HOWTO (R_XSTORMY16_8, /* type */
109          0,                     /* rightshift */
110          0,                     /* size (0 = byte, 1 = short, 2 = long) */
111          8,                     /* bitsize */
112          FALSE,                 /* pc_relative */
113          0,                     /* bitpos */
114          complain_overflow_bitfield, /* complain_on_overflow */
115          bfd_elf_generic_reloc, /* special_function */
116          "R_XSTORMY16_8",       /* name */
117          FALSE,                 /* partial_inplace */
118          0,                     /* src_mask */
119          0xffffffff,            /* dst_mask */
120          FALSE),                /* pcrel_offset */
121
122   /* A 32 bit pc-relative relocation.  */
123   HOWTO (R_XSTORMY16_PC32,      /* type */
124          0,                     /* rightshift */
125          2,                     /* size (0 = byte, 1 = short, 2 = long) */
126          32,                    /* bitsize */
127          TRUE,                  /* pc_relative */
128          0,                     /* bitpos */
129          complain_overflow_dont, /* complain_on_overflow */
130          bfd_elf_generic_reloc, /* special_function */
131          "R_XSTORMY16_PC32",    /* name */
132          FALSE,                 /* partial_inplace */
133          0,                     /* src_mask */
134          0xffffffff,            /* dst_mask */
135          TRUE),                 /* pcrel_offset */
136
137   /* A 16 bit pc-relative relocation.  */
138   HOWTO (R_XSTORMY16_PC16,      /* type */
139          0,                     /* rightshift */
140          1,                     /* size (0 = byte, 1 = short, 2 = long) */
141          16,                    /* bitsize */
142          TRUE,                  /* pc_relative */
143          0,                     /* bitpos */
144          complain_overflow_signed, /* complain_on_overflow */
145          bfd_elf_generic_reloc, /* special_function */
146          "R_XSTORMY16_PC16",    /* name */
147          FALSE,                 /* partial_inplace */
148          0,                     /* src_mask */
149          0xffffffff,            /* dst_mask */
150          TRUE),                 /* pcrel_offset */
151
152   /* An 8 bit pc-relative relocation.  */
153   HOWTO (R_XSTORMY16_PC8,       /* type */
154          0,                     /* rightshift */
155          0,                     /* size (0 = byte, 1 = short, 2 = long) */
156          8,                     /* bitsize */
157          TRUE,                  /* pc_relative */
158          0,                     /* bitpos */
159          complain_overflow_signed, /* complain_on_overflow */
160          bfd_elf_generic_reloc, /* special_function */
161          "R_XSTORMY16_PC8",     /* name */
162          FALSE,                 /* partial_inplace */
163          0,                     /* src_mask */
164          0xffffffff,            /* dst_mask */
165          TRUE),                 /* pcrel_offset */
166
167   /* A 12-bit pc-relative relocation suitable for the branch instructions.  */
168   HOWTO (R_XSTORMY16_REL_12,    /* type */
169          1,                     /* rightshift */
170          1,                     /* size (0 = byte, 1 = short, 2 = long) */
171          11,                    /* bitsize */
172          TRUE,                  /* pc_relative */
173          1,                     /* bitpos */
174          complain_overflow_signed, /* complain_on_overflow */
175          bfd_elf_generic_reloc, /* special_function */
176          "R_XSTORMY16_REL_12",  /* name */
177          TRUE,                  /* partial_inplace */
178          0,                     /* src_mask */
179          0x0fff,                /* dst_mask */
180          TRUE),                 /* pcrel_offset */
181
182   /* A 24-bit absolute relocation suitable for the jump instructions.  */
183   HOWTO (R_XSTORMY16_24,        /* type */
184          0,                     /* rightshift */
185          2,                     /* size (0 = byte, 1 = short, 2 = long) */
186          24,                    /* bitsize */
187          FALSE,                 /* pc_relative */
188          0,                     /* bitpos */
189          complain_overflow_unsigned, /* complain_on_overflow */
190          xstormy16_elf_24_reloc,        /* special_function */
191          "R_XSTORMY16_24",      /* name */
192          TRUE,                  /* partial_inplace */
193          0,                     /* src_mask */
194          0xffff00ff,            /* dst_mask */
195          TRUE),                 /* pcrel_offset */
196
197   /* A 16 bit absolute relocation to a function pointer.  */
198   HOWTO (R_XSTORMY16_FPTR16,    /* type */
199          0,                     /* rightshift */
200          1,                     /* size (0 = byte, 1 = short, 2 = long) */
201          16,                    /* bitsize */
202          FALSE,                 /* pc_relative */
203          0,                     /* bitpos */
204          complain_overflow_bitfield, /* complain_on_overflow */
205          bfd_elf_generic_reloc, /* special_function */
206          "R_XSTORMY16_FPTR16",  /* name */
207          FALSE,                 /* partial_inplace */
208          0,                     /* src_mask */
209          0xffffffff,            /* dst_mask */
210          FALSE),                /* pcrel_offset */
211
212   /* 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->relocateable)
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->relocateable)
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->relocateable)
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 relocateable
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 relocateable 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->relocateable)
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 = (sec->output_section->vma
849                         + sec->output_offset
850                         + sym->st_value);
851
852           name = bfd_elf_string_from_elf_section
853             (input_bfd, symtab_hdr->sh_link, sym->st_name);
854           name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
855         }
856       else
857         {
858           h = sym_hashes [r_symndx - symtab_hdr->sh_info];
859
860           while (h->root.type == bfd_link_hash_indirect
861                  || h->root.type == bfd_link_hash_warning)
862             h = (struct elf_link_hash_entry *) h->root.u.i.link;
863
864           name = h->root.root.string;
865
866           if (h->root.type == bfd_link_hash_defined
867               || h->root.type == bfd_link_hash_defweak)
868             {
869               sec = h->root.u.def.section;
870               relocation = (h->root.u.def.value
871                             + sec->output_section->vma
872                             + sec->output_offset);
873             }
874           else if (h->root.type == bfd_link_hash_undefweak)
875             {
876               relocation = 0;
877             }
878           else
879             {
880               if (! ((*info->callbacks->undefined_symbol)
881                      (info, h->root.root.string, input_bfd,
882                       input_section, rel->r_offset, TRUE)))
883                 return FALSE;
884               relocation = 0;
885             }
886         }
887
888       switch (ELF32_R_TYPE (rel->r_info))
889         {
890         case R_XSTORMY16_24:
891           {
892             bfd_vma reloc = relocation + rel->r_addend;
893             unsigned int x;
894
895             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
896             x &= 0x0000ff00;
897             x |= reloc & 0xff;
898             x |= (reloc << 8) & 0xffff0000;
899             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
900
901             if (reloc & ~0xffffff)
902               r = bfd_reloc_overflow;
903             else
904               r = bfd_reloc_ok;
905             break;
906           }
907
908         case R_XSTORMY16_FPTR16:
909           {
910             bfd_vma *plt_offset;
911
912             if (h != NULL)
913               plt_offset = &h->plt.offset;
914             else
915               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
916
917             if (relocation <= 0xffff)
918               {
919                 /* If the symbol is in range for a 16-bit address, we should
920                    have deallocated the plt entry in relax_section.  */
921                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
922               }
923             else
924               {
925                 /* If the symbol is out of range for a 16-bit address,
926                    we must have allocated a plt entry.  */
927                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
928
929                 /* If this is the first time we've processed this symbol,
930                    fill in the plt entry with the correct symbol address.  */
931                 if ((*plt_offset & 1) == 0)
932                   {
933                     unsigned int x;
934
935                     x = 0x00000200;  /* jmpf */
936                     x |= relocation & 0xff;
937                     x |= (relocation << 8) & 0xffff0000;
938                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
939                     *plt_offset |= 1;
940                   }
941
942                 relocation = (splt->output_section->vma
943                               + splt->output_offset
944                               + (*plt_offset & -2));
945               }
946             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
947                                           contents, rel->r_offset,
948                                           relocation, 0);
949             break;
950           }
951
952         default:
953           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
954                                         contents, rel->r_offset,
955                                         relocation, rel->r_addend);
956           break;
957         }
958
959       if (r != bfd_reloc_ok)
960         {
961           const char * msg = (const char *) NULL;
962
963           switch (r)
964             {
965             case bfd_reloc_overflow:
966               r = info->callbacks->reloc_overflow
967                 (info, name, howto->name, (bfd_vma) 0,
968                  input_bfd, input_section, rel->r_offset);
969               break;
970
971             case bfd_reloc_undefined:
972               r = info->callbacks->undefined_symbol
973                 (info, name, input_bfd, input_section, rel->r_offset,
974                  TRUE);
975               break;
976
977             case bfd_reloc_outofrange:
978               msg = _("internal error: out of range error");
979               break;
980
981             case bfd_reloc_notsupported:
982               msg = _("internal error: unsupported relocation error");
983               break;
984
985             case bfd_reloc_dangerous:
986               msg = _("internal error: dangerous relocation");
987               break;
988
989             default:
990               msg = _("internal error: unknown error");
991               break;
992             }
993
994           if (msg)
995             r = info->callbacks->warning
996               (info, msg, name, input_bfd, input_section, rel->r_offset);
997
998           if (! r)
999             return FALSE;
1000         }
1001     }
1002
1003   return TRUE;
1004 }
1005
1006 /* This must exist if dynobj is ever set.  */
1007
1008 static bfd_boolean
1009 xstormy16_elf_finish_dynamic_sections (abfd, info)
1010      bfd *abfd ATTRIBUTE_UNUSED;
1011      struct bfd_link_info *info;
1012 {
1013   bfd *dynobj;
1014   asection *splt;
1015
1016   /* As an extra sanity check, verify that all plt entries have
1017      been filled in.  */
1018
1019   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
1020       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
1021     {
1022       bfd_byte *contents = splt->contents;
1023       unsigned int i, size = splt->_raw_size;
1024       for (i = 0; i < size; i += 4)
1025         {
1026           unsigned int x = bfd_get_32 (dynobj, contents + i);
1027           BFD_ASSERT (x != 0);
1028         }
1029     }
1030
1031   return TRUE;
1032 }
1033 \f
1034 /* Return the section that should be marked against GC for a given
1035    relocation.  */
1036
1037 static asection *
1038 xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
1039      asection *                   sec;
1040      struct bfd_link_info *       info ATTRIBUTE_UNUSED;
1041      Elf_Internal_Rela *          rel;
1042      struct elf_link_hash_entry * h;
1043      Elf_Internal_Sym *           sym;
1044 {
1045   if (h != NULL)
1046     {
1047       switch (ELF32_R_TYPE (rel->r_info))
1048         {
1049         case R_XSTORMY16_GNU_VTINHERIT:
1050         case R_XSTORMY16_GNU_VTENTRY:
1051           break;
1052
1053         default:
1054           switch (h->root.type)
1055             {
1056             case bfd_link_hash_defined:
1057             case bfd_link_hash_defweak:
1058               return h->root.u.def.section;
1059
1060             case bfd_link_hash_common:
1061               return h->root.u.c.p->section;
1062
1063             default:
1064               break;
1065             }
1066         }
1067     }
1068   else
1069     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1070
1071   return NULL;
1072 }
1073
1074 /* Update the got entry reference counts for the section being removed.  */
1075
1076 static bfd_boolean
1077 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1078      bfd *                     abfd ATTRIBUTE_UNUSED;
1079      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
1080      asection *                sec ATTRIBUTE_UNUSED;
1081      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1082 {
1083   return TRUE;
1084 }
1085 \f
1086 #define ELF_ARCH                bfd_arch_xstormy16
1087 #define ELF_MACHINE_CODE        EM_XSTORMY16
1088 #define ELF_MAXPAGESIZE         0x100
1089
1090 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1091 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1092
1093 #define elf_info_to_howto_rel                   NULL
1094 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1095 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1096 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1097 #define elf_backend_gc_sweep_hook               xstormy16_elf_gc_sweep_hook
1098 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1099 #define elf_backend_always_size_sections \
1100   xstormy16_elf_always_size_sections
1101 #define elf_backend_finish_dynamic_sections \
1102   xstormy16_elf_finish_dynamic_sections
1103
1104 #define elf_backend_can_gc_sections             1
1105 #define elf_backend_rela_normal                 1
1106
1107 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1108 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1109
1110 #include "elf32-target.h"