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