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