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