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