daily update
[external/binutils.git] / bfd / elf32-xstormy16.c
1 /* XSTORMY16-specific support for 32-bit ELF.
2    Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3
4 This file is part of BFD, the Binary File Descriptor library.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 > bfd_get_section_limit (abfd, input_section))
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_with_flags (dynobj, ".plt",
474                                                       (SEC_ALLOC
475                                                        | SEC_LOAD
476                                                        | SEC_HAS_CONTENTS
477                                                        | SEC_IN_MEMORY
478                                                        | SEC_LINKER_CREATED
479                                                        | SEC_READONLY
480                                                        | SEC_CODE));
481
482                   if (splt == NULL
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->size;
512               splt->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_elf_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_elf_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->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->size == 0)
622     return TRUE;
623
624   /* Map across all global symbols; see which ones happen to
625      fall in the low 64k.  */
626   relax_plt_data.splt = splt;
627   relax_plt_data.again = again;
628   elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
629                           &relax_plt_data);
630
631   /* Likewise for local symbols, though that's somewhat less convenient
632      as we have to walk the list of input bfds and swap in symbol data.  */
633   for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
634     {
635       bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
636       Elf_Internal_Shdr *symtab_hdr;
637       Elf_Internal_Sym *isymbuf = NULL;
638       unsigned int idx;
639
640       if (! local_plt_offsets)
641         continue;
642
643       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
644       if (symtab_hdr->sh_info != 0)
645         {
646           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
647           if (isymbuf == NULL)
648             isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
649                                             symtab_hdr->sh_info, 0,
650                                             NULL, NULL, NULL);
651           if (isymbuf == NULL)
652             return FALSE;
653         }
654
655       for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
656         {
657           Elf_Internal_Sym *isym;
658           asection *tsec;
659           bfd_vma address;
660
661           if (local_plt_offsets[idx] == (bfd_vma) -1)
662             continue;
663
664           isym = &isymbuf[idx];
665           if (isym->st_shndx == SHN_UNDEF)
666             continue;
667           else if (isym->st_shndx == SHN_ABS)
668             tsec = bfd_abs_section_ptr;
669           else if (isym->st_shndx == SHN_COMMON)
670             tsec = bfd_com_section_ptr;
671           else
672             tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
673
674           address = (tsec->output_section->vma
675                      + tsec->output_offset
676                      + isym->st_value);
677           if (address <= 0xffff)
678             {
679               local_plt_offsets[idx] = -1;
680               splt->size -= 4;
681               *again = TRUE;
682             }
683         }
684
685       if (isymbuf != NULL
686           && symtab_hdr->contents != (unsigned char *) isymbuf)
687         {
688           if (! info->keep_memory)
689             free (isymbuf);
690           else
691             {
692               /* Cache the symbols for elf_link_input_bfd.  */
693               symtab_hdr->contents = (unsigned char *) isymbuf;
694             }
695         }
696     }
697
698   /* If we changed anything, walk the symbols again to reallocate
699      .plt entry addresses.  */
700   if (*again && splt->size > 0)
701     {
702       bfd_vma entry = 0;
703
704       elf_link_hash_traverse (elf_hash_table (info),
705                               xstormy16_relax_plt_realloc, &entry);
706
707       for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
708         {
709           bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
710           unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
711           unsigned int idx;
712
713           if (! local_plt_offsets)
714             continue;
715
716           for (idx = 0; idx < nlocals; ++idx)
717             if (local_plt_offsets[idx] != (bfd_vma) -1)
718               {
719                 local_plt_offsets[idx] = entry;
720                 entry += 4;
721               }
722         }
723     }
724
725   return TRUE;
726 }
727
728 static bfd_boolean
729 xstormy16_elf_always_size_sections (output_bfd, info)
730      bfd *output_bfd ATTRIBUTE_UNUSED;
731      struct bfd_link_info *info;
732 {
733   bfd *dynobj;
734   asection *splt;
735
736   if (info->relocatable)
737     return TRUE;
738
739   dynobj = elf_hash_table (info)->dynobj;
740   if (dynobj == NULL)
741     return TRUE;
742
743   splt = bfd_get_section_by_name (dynobj, ".plt");
744   BFD_ASSERT (splt != NULL);
745
746   splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size);
747   if (splt->contents == NULL)
748     return FALSE;
749
750   return TRUE;
751 }
752 \f
753 /* Relocate an XSTORMY16 ELF section.
754
755    The RELOCATE_SECTION function is called by the new ELF backend linker
756    to handle the relocations for a section.
757
758    The relocs are always passed as Rela structures; if the section
759    actually uses Rel structures, the r_addend field will always be
760    zero.
761
762    This function is responsible for adjusting the section contents as
763    necessary, and (if using Rela relocs and generating a relocatable
764    output file) adjusting the reloc addend as necessary.
765
766    This function does not have to worry about setting the reloc
767    address or the reloc symbol index.
768
769    LOCAL_SYMS is a pointer to the swapped in local symbols.
770
771    LOCAL_SECTIONS is an array giving the section in the input file
772    corresponding to the st_shndx field of each local symbol.
773
774    The global hash table entry for the global symbols can be found
775    via elf_sym_hashes (input_bfd).
776
777    When generating relocatable output, this function must handle
778    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
779    going to be the section symbol corresponding to the output
780    section, which means that the addend must be adjusted
781    accordingly.  */
782
783 static bfd_boolean
784 xstormy16_elf_relocate_section (output_bfd, info, input_bfd, input_section,
785                            contents, relocs, local_syms, local_sections)
786      bfd *                   output_bfd ATTRIBUTE_UNUSED;
787      struct bfd_link_info *  info;
788      bfd *                   input_bfd;
789      asection *              input_section;
790      bfd_byte *              contents;
791      Elf_Internal_Rela *     relocs;
792      Elf_Internal_Sym *      local_syms;
793      asection **             local_sections;
794 {
795   Elf_Internal_Shdr *           symtab_hdr;
796   struct elf_link_hash_entry ** sym_hashes;
797   Elf_Internal_Rela *           rel;
798   Elf_Internal_Rela *           relend;
799   bfd *dynobj;
800   asection *splt;
801
802   if (info->relocatable)
803     return TRUE;
804
805   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
806   sym_hashes = elf_sym_hashes (input_bfd);
807   relend     = relocs + input_section->reloc_count;
808
809   dynobj = elf_hash_table (info)->dynobj;
810   splt = NULL;
811   if (dynobj != NULL)
812     splt = bfd_get_section_by_name (dynobj, ".plt");
813
814   for (rel = relocs; rel < relend; rel ++)
815     {
816       reloc_howto_type *           howto;
817       unsigned long                r_symndx;
818       Elf_Internal_Sym *           sym;
819       asection *                   sec;
820       struct elf_link_hash_entry * h;
821       bfd_vma                      relocation;
822       bfd_reloc_status_type        r;
823       const char *                 name = NULL;
824       int                          r_type;
825
826       r_type = ELF32_R_TYPE (rel->r_info);
827
828       if (   r_type == R_XSTORMY16_GNU_VTINHERIT
829           || r_type == R_XSTORMY16_GNU_VTENTRY)
830         continue;
831
832       r_symndx = ELF32_R_SYM (rel->r_info);
833       howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
834       h      = NULL;
835       sym    = NULL;
836       sec    = NULL;
837
838       if (r_symndx < symtab_hdr->sh_info)
839         {
840           sym = local_syms + r_symndx;
841           sec = local_sections [r_symndx];
842           relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
843         }
844       else
845         {
846           bfd_boolean unresolved_reloc, warned;
847
848           RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
849                                    r_symndx, symtab_hdr, sym_hashes,
850                                    h, sec, relocation,
851                                    unresolved_reloc, warned);
852         }
853
854       if (h != NULL)
855         name = h->root.root.string;
856       else
857         {
858           name = (bfd_elf_string_from_elf_section
859                   (input_bfd, symtab_hdr->sh_link, sym->st_name));
860           if (name == NULL || *name == '\0')
861             name = bfd_section_name (input_bfd, sec);
862         }
863
864       switch (ELF32_R_TYPE (rel->r_info))
865         {
866         case R_XSTORMY16_24:
867           {
868             bfd_vma reloc = relocation + rel->r_addend;
869             unsigned int x;
870
871             x = bfd_get_32 (input_bfd, contents + rel->r_offset);
872             x &= 0x0000ff00;
873             x |= reloc & 0xff;
874             x |= (reloc << 8) & 0xffff0000;
875             bfd_put_32 (input_bfd, x, contents + rel->r_offset);
876
877             if (reloc & ~0xffffff)
878               r = bfd_reloc_overflow;
879             else
880               r = bfd_reloc_ok;
881             break;
882           }
883
884         case R_XSTORMY16_FPTR16:
885           {
886             bfd_vma *plt_offset;
887
888             if (h != NULL)
889               plt_offset = &h->plt.offset;
890             else
891               plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
892
893             if (relocation <= 0xffff)
894               {
895                 /* If the symbol is in range for a 16-bit address, we should
896                    have deallocated the plt entry in relax_section.  */
897                 BFD_ASSERT (*plt_offset == (bfd_vma) -1);
898               }
899             else
900               {
901                 /* If the symbol is out of range for a 16-bit address,
902                    we must have allocated a plt entry.  */
903                 BFD_ASSERT (*plt_offset != (bfd_vma) -1);
904
905                 /* If this is the first time we've processed this symbol,
906                    fill in the plt entry with the correct symbol address.  */
907                 if ((*plt_offset & 1) == 0)
908                   {
909                     unsigned int x;
910
911                     x = 0x00000200;  /* jmpf */
912                     x |= relocation & 0xff;
913                     x |= (relocation << 8) & 0xffff0000;
914                     bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
915                     *plt_offset |= 1;
916                   }
917
918                 relocation = (splt->output_section->vma
919                               + splt->output_offset
920                               + (*plt_offset & -2));
921               }
922             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
923                                           contents, rel->r_offset,
924                                           relocation, 0);
925             break;
926           }
927
928         default:
929           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
930                                         contents, rel->r_offset,
931                                         relocation, rel->r_addend);
932           break;
933         }
934
935       if (r != bfd_reloc_ok)
936         {
937           const char * msg = (const char *) NULL;
938
939           switch (r)
940             {
941             case bfd_reloc_overflow:
942               r = info->callbacks->reloc_overflow
943                 (info, (h ? &h->root : NULL), name, howto->name,
944                  (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
945               break;
946
947             case bfd_reloc_undefined:
948               r = info->callbacks->undefined_symbol
949                 (info, name, input_bfd, input_section, rel->r_offset,
950                  TRUE);
951               break;
952
953             case bfd_reloc_outofrange:
954               msg = _("internal error: out of range error");
955               break;
956
957             case bfd_reloc_notsupported:
958               msg = _("internal error: unsupported relocation error");
959               break;
960
961             case bfd_reloc_dangerous:
962               msg = _("internal error: dangerous relocation");
963               break;
964
965             default:
966               msg = _("internal error: unknown error");
967               break;
968             }
969
970           if (msg)
971             r = info->callbacks->warning
972               (info, msg, name, input_bfd, input_section, rel->r_offset);
973
974           if (! r)
975             return FALSE;
976         }
977     }
978
979   return TRUE;
980 }
981
982 /* This must exist if dynobj is ever set.  */
983
984 static bfd_boolean
985 xstormy16_elf_finish_dynamic_sections (abfd, info)
986      bfd *abfd ATTRIBUTE_UNUSED;
987      struct bfd_link_info *info;
988 {
989   bfd *dynobj;
990   asection *splt;
991
992   /* As an extra sanity check, verify that all plt entries have
993      been filled in.  */
994
995   if ((dynobj = elf_hash_table (info)->dynobj) != NULL
996       && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
997     {
998       bfd_byte *contents = splt->contents;
999       unsigned int i, size = splt->size;
1000       for (i = 0; i < size; i += 4)
1001         {
1002           unsigned int x = bfd_get_32 (dynobj, contents + i);
1003           BFD_ASSERT (x != 0);
1004         }
1005     }
1006
1007   return TRUE;
1008 }
1009 \f
1010 /* Return the section that should be marked against GC for a given
1011    relocation.  */
1012
1013 static asection *
1014 xstormy16_elf_gc_mark_hook (sec, info, rel, h, sym)
1015      asection *                   sec;
1016      struct bfd_link_info *       info ATTRIBUTE_UNUSED;
1017      Elf_Internal_Rela *          rel;
1018      struct elf_link_hash_entry * h;
1019      Elf_Internal_Sym *           sym;
1020 {
1021   if (h != NULL)
1022     {
1023       switch (ELF32_R_TYPE (rel->r_info))
1024         {
1025         case R_XSTORMY16_GNU_VTINHERIT:
1026         case R_XSTORMY16_GNU_VTENTRY:
1027           break;
1028
1029         default:
1030           switch (h->root.type)
1031             {
1032             case bfd_link_hash_defined:
1033             case bfd_link_hash_defweak:
1034               return h->root.u.def.section;
1035
1036             case bfd_link_hash_common:
1037               return h->root.u.c.p->section;
1038
1039             default:
1040               break;
1041             }
1042         }
1043     }
1044   else
1045     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1046
1047   return NULL;
1048 }
1049
1050 /* Update the got entry reference counts for the section being removed.  */
1051
1052 static bfd_boolean
1053 xstormy16_elf_gc_sweep_hook (abfd, info, sec, relocs)
1054      bfd *                     abfd ATTRIBUTE_UNUSED;
1055      struct bfd_link_info *    info ATTRIBUTE_UNUSED;
1056      asection *                sec ATTRIBUTE_UNUSED;
1057      const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED;
1058 {
1059   return TRUE;
1060 }
1061 \f
1062 #define ELF_ARCH                bfd_arch_xstormy16
1063 #define ELF_MACHINE_CODE        EM_XSTORMY16
1064 #define ELF_MAXPAGESIZE         0x100
1065
1066 #define TARGET_LITTLE_SYM       bfd_elf32_xstormy16_vec
1067 #define TARGET_LITTLE_NAME      "elf32-xstormy16"
1068
1069 #define elf_info_to_howto_rel                   NULL
1070 #define elf_info_to_howto                       xstormy16_info_to_howto_rela
1071 #define elf_backend_relocate_section            xstormy16_elf_relocate_section
1072 #define elf_backend_gc_mark_hook                xstormy16_elf_gc_mark_hook
1073 #define elf_backend_gc_sweep_hook               xstormy16_elf_gc_sweep_hook
1074 #define elf_backend_check_relocs                xstormy16_elf_check_relocs
1075 #define elf_backend_always_size_sections \
1076   xstormy16_elf_always_size_sections
1077 #define elf_backend_finish_dynamic_sections \
1078   xstormy16_elf_finish_dynamic_sections
1079
1080 #define elf_backend_can_gc_sections             1
1081 #define elf_backend_rela_normal                 1
1082
1083 #define bfd_elf32_bfd_reloc_type_lookup         xstormy16_reloc_type_lookup
1084 #define bfd_elf32_bfd_relax_section             xstormy16_elf_relax_section
1085
1086 #include "elf32-target.h"