Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/bfd/elf32-xstormy16.c
Line
Count
Source (jump to first uncovered line)
1
/* Xstormy16-specific support for 32-bit ELF.
2
   Copyright (C) 2000-2025 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
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
0
{
39
0
  bfd_vma relocation, x;
40
41
0
  if (output_bfd != NULL)
42
0
    {
43
0
      reloc_entry->address += input_section->output_offset;
44
0
      return bfd_reloc_ok;
45
0
    }
46
47
0
  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
48
0
    return bfd_reloc_outofrange;
49
50
0
  if (bfd_is_com_section (symbol->section))
51
0
    relocation = 0;
52
0
  else
53
0
    relocation = symbol->value;
54
55
0
  relocation += symbol->section->output_section->vma;
56
0
  relocation += symbol->section->output_offset;
57
0
  relocation += reloc_entry->addend;
58
59
0
  x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
60
0
  x &= 0x0000ff00;
61
0
  x |= relocation & 0xff;
62
0
  x |= (relocation << 8) & 0xffff0000;
63
0
  bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
64
65
0
  if (relocation & ~ (bfd_vma) 0xffffff)
66
0
    return bfd_reloc_overflow;
67
68
0
  return bfd_reloc_ok;
69
0
}
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 *
332
xstormy16_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
333
           bfd_reloc_code_real_type code)
334
0
{
335
0
  unsigned int i;
336
337
0
  for (i = ARRAY_SIZE (xstormy16_reloc_map); i--;)
338
0
    {
339
0
      const reloc_map * entry;
340
341
0
      entry = xstormy16_reloc_map + i;
342
343
0
      if (entry->bfd_reloc_val == code)
344
0
  return entry->table + (entry->xstormy16_reloc_val
345
0
             - entry->table[0].type);
346
0
    }
347
348
0
  return NULL;
349
0
}
350
351
static reloc_howto_type *
352
xstormy16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
353
           const char *r_name)
354
0
{
355
0
  unsigned int i;
356
357
0
  for (i = 0;
358
0
       i < (sizeof (xstormy16_elf_howto_table)
359
0
      / sizeof (xstormy16_elf_howto_table[0]));
360
0
       i++)
361
0
    if (xstormy16_elf_howto_table[i].name != NULL
362
0
  && strcasecmp (xstormy16_elf_howto_table[i].name, r_name) == 0)
363
0
      return &xstormy16_elf_howto_table[i];
364
365
0
  for (i = 0;
366
0
       i < (sizeof (xstormy16_elf_howto_table2)
367
0
      / sizeof (xstormy16_elf_howto_table2[0]));
368
0
       i++)
369
0
    if (xstormy16_elf_howto_table2[i].name != NULL
370
0
  && strcasecmp (xstormy16_elf_howto_table2[i].name, r_name) == 0)
371
0
      return &xstormy16_elf_howto_table2[i];
372
373
0
  return NULL;
374
0
}
375
376
/* Set the howto pointer for an XSTORMY16 ELF reloc.  */
377
378
static bool
379
xstormy16_info_to_howto_rela (bfd * abfd,
380
            arelent * cache_ptr,
381
            Elf_Internal_Rela * dst)
382
0
{
383
0
  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
384
385
0
  if (r_type <= (unsigned int) R_XSTORMY16_12)
386
0
    cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
387
0
  else if (r_type - R_XSTORMY16_GNU_VTINHERIT
388
0
     <= ((unsigned int) R_XSTORMY16_GNU_VTENTRY
389
0
         - (unsigned int) R_XSTORMY16_GNU_VTINHERIT))
390
0
    cache_ptr->howto
391
0
      = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
392
0
  else
393
0
    {
394
      /* xgettext:c-format */
395
0
      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
396
0
        abfd, r_type);
397
0
      bfd_set_error (bfd_error_bad_value);
398
0
      return false;
399
0
    }
400
0
  return true;
401
0
}
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
410
xstormy16_elf_check_relocs (bfd *abfd,
411
          struct bfd_link_info *info,
412
          asection *sec,
413
          const Elf_Internal_Rela *relocs)
414
0
{
415
0
  const Elf_Internal_Rela *rel, *relend;
416
0
  struct elf_link_hash_entry **sym_hashes;
417
0
  Elf_Internal_Shdr *symtab_hdr;
418
0
  bfd_vma *local_plt_offsets;
419
0
  asection *splt;
420
0
  bfd *dynobj;
421
422
0
  if (bfd_link_relocatable (info))
423
0
    return true;
424
425
0
  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
426
0
  sym_hashes = elf_sym_hashes (abfd);
427
0
  local_plt_offsets = elf_local_got_offsets (abfd);
428
0
  dynobj = elf_hash_table(info)->dynobj;
429
430
0
  relend = relocs + sec->reloc_count;
431
0
  for (rel = relocs; rel < relend; ++rel)
432
0
    {
433
0
      unsigned long r_symndx;
434
0
      struct elf_link_hash_entry *h;
435
0
      bfd_vma *offset;
436
437
0
      r_symndx = ELF32_R_SYM (rel->r_info);
438
0
      if (r_symndx < symtab_hdr->sh_info)
439
0
  h = NULL;
440
0
      else
441
0
  {
442
0
    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
443
0
    while (h->root.type == bfd_link_hash_indirect
444
0
     || h->root.type == bfd_link_hash_warning)
445
0
      h = (struct elf_link_hash_entry *) h->root.u.i.link;
446
0
  }
447
448
0
      switch (ELF32_R_TYPE (rel->r_info))
449
0
  {
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
0
  case R_XSTORMY16_FPTR16:
454
0
    if (rel->r_addend != 0)
455
0
      {
456
0
        (*info->callbacks->warning)
457
0
    (info, _("non-zero addend in @fptr reloc"), 0,
458
0
     abfd, 0, 0);
459
0
      }
460
461
0
    if (dynobj == NULL)
462
0
      elf_hash_table (info)->dynobj = dynobj = abfd;
463
0
    splt = elf_hash_table (info)->splt;
464
0
    if (splt == NULL)
465
0
      {
466
0
        flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
467
0
        | SEC_IN_MEMORY | SEC_LINKER_CREATED
468
0
        | SEC_READONLY | SEC_CODE);
469
470
0
        splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
471
0
               flags);
472
0
        elf_hash_table (info)->splt = splt;
473
0
        if (splt == NULL
474
0
      || !bfd_set_section_alignment (splt, 1))
475
0
    return false;
476
0
      }
477
478
0
    if (h != NULL)
479
0
      offset = &h->plt.offset;
480
0
    else
481
0
      {
482
0
        if (local_plt_offsets == NULL)
483
0
    {
484
0
      size_t size;
485
0
      unsigned int i;
486
487
0
      size = symtab_hdr->sh_info * sizeof (bfd_vma);
488
0
      local_plt_offsets = bfd_alloc (abfd, size);
489
0
      if (local_plt_offsets == NULL)
490
0
        return false;
491
0
      elf_local_got_offsets (abfd) = local_plt_offsets;
492
493
0
      for (i = 0; i < symtab_hdr->sh_info; i++)
494
0
        local_plt_offsets[i] = (bfd_vma) -1;
495
0
    }
496
0
        offset = &local_plt_offsets[r_symndx];
497
0
      }
498
499
0
    if (*offset == (bfd_vma) -1)
500
0
      {
501
0
        *offset = splt->size;
502
0
        splt->size += 4;
503
0
      }
504
0
    break;
505
506
    /* This relocation describes the C++ object vtable hierarchy.
507
       Reconstruct it for later use during GC.  */
508
0
  case R_XSTORMY16_GNU_VTINHERIT:
509
0
    if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
510
0
      return false;
511
0
    break;
512
513
    /* This relocation describes which C++ vtable entries are actually
514
       used.  Record for later use during GC.  */
515
0
  case R_XSTORMY16_GNU_VTENTRY:
516
0
    if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
517
0
      return false;
518
0
    break;
519
0
  }
520
0
    }
521
522
0
  return true;
523
0
}
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
535
xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
536
0
{
537
0
  struct relax_plt_data *data = (struct relax_plt_data *) xdata;
538
539
0
  if (h->plt.offset != (bfd_vma) -1)
540
0
    {
541
0
      bfd_vma address;
542
543
0
      if (h->root.type == bfd_link_hash_undefined
544
0
    || h->root.type == bfd_link_hash_undefweak)
545
0
  address = 0;
546
0
      else
547
0
  address = (h->root.u.def.section->output_section->vma
548
0
       + h->root.u.def.section->output_offset
549
0
       + h->root.u.def.value);
550
551
0
      if (address <= 0xffff)
552
0
  {
553
0
    h->plt.offset = -1;
554
0
    data->splt->size -= 4;
555
0
    *data->again = true;
556
0
  }
557
0
    }
558
559
0
  return true;
560
0
}
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
566
xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
567
0
{
568
0
  bfd_vma *entry = (bfd_vma *) xdata;
569
570
0
  if (h->plt.offset != (bfd_vma) -1)
571
0
    {
572
0
      h->plt.offset = *entry;
573
0
      *entry += 4;
574
0
    }
575
576
0
  return true;
577
0
}
578
579
static bool
580
xstormy16_elf_relax_section (bfd *dynobj,
581
           asection *splt,
582
           struct bfd_link_info *info,
583
           bool *again)
584
0
{
585
0
  struct relax_plt_data relax_plt_data;
586
0
  bfd *ibfd;
587
588
  /* Assume nothing changes.  */
589
0
  *again = false;
590
591
0
  if (bfd_link_relocatable (info)
592
0
      || !is_elf_hash_table (info->hash))
593
0
    return true;
594
595
  /* We only relax the .plt section at the moment.  */
596
0
  if (dynobj != elf_hash_table (info)->dynobj
597
0
      || strcmp (splt->name, ".plt") != 0)
598
0
    return true;
599
600
  /* Quick check for an empty plt.  */
601
0
  if (splt->size == 0)
602
0
    return true;
603
604
  /* Map across all global symbols; see which ones happen to
605
     fall in the low 64k.  */
606
0
  relax_plt_data.splt = splt;
607
0
  relax_plt_data.again = again;
608
0
  elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
609
0
        &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
0
  for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
614
0
    {
615
0
      bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
616
0
      Elf_Internal_Shdr *symtab_hdr;
617
0
      Elf_Internal_Sym *isymbuf = NULL;
618
0
      unsigned int idx;
619
620
0
      if (! local_plt_offsets)
621
0
  continue;
622
623
0
      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
624
0
      if (symtab_hdr->sh_info != 0)
625
0
  {
626
0
    isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
627
0
    if (isymbuf == NULL)
628
0
      isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
629
0
              symtab_hdr->sh_info, 0,
630
0
              NULL, NULL, NULL);
631
0
    if (isymbuf == NULL)
632
0
      return false;
633
0
  }
634
635
0
      for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
636
0
  {
637
0
    Elf_Internal_Sym *isym;
638
0
    asection *tsec;
639
0
    bfd_vma address;
640
641
0
    if (local_plt_offsets[idx] == (bfd_vma) -1)
642
0
      continue;
643
644
0
    isym = &isymbuf[idx];
645
0
    if (isym->st_shndx == SHN_UNDEF)
646
0
      continue;
647
0
    else if (isym->st_shndx == SHN_ABS)
648
0
      tsec = bfd_abs_section_ptr;
649
0
    else if (isym->st_shndx == SHN_COMMON)
650
0
      tsec = bfd_com_section_ptr;
651
0
    else
652
0
      tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx);
653
654
0
    address = (tsec->output_section->vma
655
0
         + tsec->output_offset
656
0
         + isym->st_value);
657
0
    if (address <= 0xffff)
658
0
      {
659
0
        local_plt_offsets[idx] = -1;
660
0
        splt->size -= 4;
661
0
        *again = true;
662
0
      }
663
0
  }
664
665
0
      if (isymbuf != NULL
666
0
    && symtab_hdr->contents != (unsigned char *) isymbuf)
667
0
  {
668
0
    if (! info->keep_memory)
669
0
      free (isymbuf);
670
0
    else
671
0
      {
672
        /* Cache the symbols for elf_link_input_bfd.  */
673
0
        symtab_hdr->contents = (unsigned char *) isymbuf;
674
0
      }
675
0
  }
676
0
    }
677
678
  /* If we changed anything, walk the symbols again to reallocate
679
     .plt entry addresses.  */
680
0
  if (*again && splt->size > 0)
681
0
    {
682
0
      bfd_vma entry = 0;
683
684
0
      elf_link_hash_traverse (elf_hash_table (info),
685
0
            xstormy16_relax_plt_realloc, &entry);
686
687
0
      for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
688
0
  {
689
0
    bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
690
0
    unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
691
0
    unsigned int idx;
692
693
0
    if (! local_plt_offsets)
694
0
      continue;
695
696
0
    for (idx = 0; idx < nlocals; ++idx)
697
0
      if (local_plt_offsets[idx] != (bfd_vma) -1)
698
0
        {
699
0
    local_plt_offsets[idx] = entry;
700
0
    entry += 4;
701
0
        }
702
0
  }
703
0
    }
704
705
0
  return true;
706
0
}
707
708
static bool
709
xstormy16_elf_early_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
710
           struct bfd_link_info *info)
711
0
{
712
0
  bfd *dynobj;
713
0
  asection *splt;
714
715
0
  if (bfd_link_relocatable (info))
716
0
    return true;
717
718
0
  dynobj = elf_hash_table (info)->dynobj;
719
0
  if (dynobj == NULL)
720
0
    return true;
721
722
0
  splt = elf_hash_table (info)->splt;
723
0
  BFD_ASSERT (splt != NULL);
724
725
0
  splt->contents = bfd_zalloc (dynobj, splt->size);
726
0
  if (splt->contents == NULL)
727
0
    return false;
728
0
  splt->alloced = 1;
729
730
0
  return true;
731
0
}
732

733
/* Relocate an XSTORMY16 ELF section.
734
735
   The RELOCATE_SECTION function is called by the new ELF backend linker
736
   to handle the relocations for a section.
737
738
   The relocs are always passed as Rela structures; if the section
739
   actually uses Rel structures, the r_addend field will always be
740
   zero.
741
742
   This function is responsible for adjusting the section contents as
743
   necessary, and (if using Rela relocs and generating a relocatable
744
   output file) adjusting the reloc addend as necessary.
745
746
   This function does not have to worry about setting the reloc
747
   address or the reloc symbol index.
748
749
   LOCAL_SYMS is a pointer to the swapped in local symbols.
750
751
   LOCAL_SECTIONS is an array giving the section in the input file
752
   corresponding to the st_shndx field of each local symbol.
753
754
   The global hash table entry for the global symbols can be found
755
   via elf_sym_hashes (input_bfd).
756
757
   When generating relocatable output, this function must handle
758
   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
759
   going to be the section symbol corresponding to the output
760
   section, which means that the addend must be adjusted
761
   accordingly.  */
762
763
static int
764
xstormy16_elf_relocate_section (bfd *     output_bfd ATTRIBUTE_UNUSED,
765
        struct bfd_link_info *  info,
766
        bfd *     input_bfd,
767
        asection *    input_section,
768
        bfd_byte *    contents,
769
        Elf_Internal_Rela * relocs,
770
        Elf_Internal_Sym *  local_syms,
771
        asection **   local_sections)
772
0
{
773
0
  Elf_Internal_Shdr *   symtab_hdr;
774
0
  struct elf_link_hash_entry ** sym_hashes;
775
0
  Elf_Internal_Rela *   rel;
776
0
  Elf_Internal_Rela *   relend;
777
0
  asection *splt;
778
779
0
  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
780
0
  sym_hashes = elf_sym_hashes (input_bfd);
781
0
  relend     = relocs + input_section->reloc_count;
782
783
0
  splt = elf_hash_table (info)->splt;
784
785
0
  for (rel = relocs; rel < relend; rel ++)
786
0
    {
787
0
      reloc_howto_type *     howto;
788
0
      unsigned long      r_symndx;
789
0
      Elf_Internal_Sym *     sym;
790
0
      asection *       sec;
791
0
      struct elf_link_hash_entry * h;
792
0
      bfd_vma        relocation;
793
0
      bfd_reloc_status_type    r;
794
0
      const char *       name = NULL;
795
0
      int        r_type;
796
797
0
      r_type = ELF32_R_TYPE (rel->r_info);
798
799
0
      if (   r_type == R_XSTORMY16_GNU_VTINHERIT
800
0
    || r_type == R_XSTORMY16_GNU_VTENTRY)
801
0
  continue;
802
803
0
      r_symndx = ELF32_R_SYM (rel->r_info);
804
0
      howto  = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
805
0
      h      = NULL;
806
0
      sym    = NULL;
807
0
      sec    = NULL;
808
809
0
      if (r_symndx < symtab_hdr->sh_info)
810
0
  {
811
0
    sym = local_syms + r_symndx;
812
0
    sec = local_sections [r_symndx];
813
0
    relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
814
0
  }
815
0
      else
816
0
  {
817
0
    bool unresolved_reloc, warned, ignored;
818
819
0
    RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
820
0
           r_symndx, symtab_hdr, sym_hashes,
821
0
           h, sec, relocation,
822
0
           unresolved_reloc, warned, ignored);
823
0
  }
824
825
0
      if (sec != NULL && discarded_section (sec))
826
0
  RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
827
0
           rel, 1, relend, howto, 0, contents);
828
829
0
      if (bfd_link_relocatable (info))
830
0
  continue;
831
832
0
      if (h != NULL)
833
0
  name = h->root.root.string;
834
0
      else
835
0
  {
836
0
    name = (bfd_elf_string_from_elf_section
837
0
      (input_bfd, symtab_hdr->sh_link, sym->st_name));
838
0
    if (name == NULL || *name == '\0')
839
0
      name = bfd_section_name (sec);
840
0
  }
841
842
0
      switch (ELF32_R_TYPE (rel->r_info))
843
0
  {
844
0
  case R_XSTORMY16_24:
845
0
    {
846
0
      bfd_vma reloc = relocation + rel->r_addend;
847
0
      unsigned int x;
848
849
0
      x = bfd_get_32 (input_bfd, contents + rel->r_offset);
850
0
      x &= 0x0000ff00;
851
0
      x |= reloc & 0xff;
852
0
      x |= (reloc << 8) & 0xffff0000;
853
0
      bfd_put_32 (input_bfd, x, contents + rel->r_offset);
854
855
0
      if (reloc & ~0xffffff)
856
0
        r = bfd_reloc_overflow;
857
0
      else
858
0
        r = bfd_reloc_ok;
859
0
      break;
860
0
    }
861
862
0
  case R_XSTORMY16_FPTR16:
863
0
    {
864
0
      bfd_vma *plt_offset;
865
866
0
      if (h != NULL)
867
0
        plt_offset = &h->plt.offset;
868
0
      else
869
0
        plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
870
871
0
      if (relocation <= 0xffff)
872
0
        {
873
    /* If the symbol is in range for a 16-bit address, we should
874
       have deallocated the plt entry in relax_section.  */
875
0
    BFD_ASSERT (*plt_offset == (bfd_vma) -1);
876
0
        }
877
0
      else
878
0
        {
879
    /* If the symbol is out of range for a 16-bit address,
880
       we must have allocated a plt entry.  */
881
0
    BFD_ASSERT (*plt_offset != (bfd_vma) -1);
882
883
    /* If this is the first time we've processed this symbol,
884
       fill in the plt entry with the correct symbol address.  */
885
0
    if ((*plt_offset & 1) == 0)
886
0
      {
887
0
        unsigned int x;
888
889
0
        x = 0x00000200;  /* jmpf */
890
0
        x |= relocation & 0xff;
891
0
        x |= (relocation << 8) & 0xffff0000;
892
0
        bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
893
0
        *plt_offset |= 1;
894
0
      }
895
896
0
    relocation = (splt->output_section->vma
897
0
            + splt->output_offset
898
0
            + (*plt_offset & -2));
899
0
        }
900
0
      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
901
0
            contents, rel->r_offset,
902
0
            relocation, 0);
903
0
      break;
904
0
    }
905
906
0
  default:
907
0
    r = _bfd_final_link_relocate (howto, input_bfd, input_section,
908
0
          contents, rel->r_offset,
909
0
          relocation, rel->r_addend);
910
0
    break;
911
0
  }
912
913
0
      if (r != bfd_reloc_ok)
914
0
  {
915
0
    const char * msg = NULL;
916
917
0
    switch (r)
918
0
      {
919
0
      case bfd_reloc_overflow:
920
0
        (*info->callbacks->reloc_overflow)
921
0
    (info, (h ? &h->root : NULL), name, howto->name,
922
0
     (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
923
0
        break;
924
925
0
      case bfd_reloc_undefined:
926
0
        (*info->callbacks->undefined_symbol)
927
0
    (info, name, input_bfd, input_section, rel->r_offset, true);
928
0
        break;
929
930
0
      case bfd_reloc_outofrange:
931
0
        msg = _("internal error: out of range error");
932
0
        break;
933
934
0
      case bfd_reloc_notsupported:
935
0
        msg = _("internal error: unsupported relocation error");
936
0
        break;
937
938
0
      case bfd_reloc_dangerous:
939
0
        msg = _("internal error: dangerous relocation");
940
0
        break;
941
942
0
      default:
943
0
        msg = _("internal error: unknown error");
944
0
        break;
945
0
      }
946
947
0
    if (msg)
948
0
      (*info->callbacks->warning) (info, msg, name, input_bfd,
949
0
           input_section, rel->r_offset);
950
0
  }
951
0
    }
952
953
0
  return true;
954
0
}
955
956
/* This must exist if dynobj is ever set.  */
957
958
static bool
959
xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED,
960
               struct bfd_link_info *info)
961
0
{
962
0
  bfd *dynobj = elf_hash_table (info)->dynobj;
963
0
  asection *splt = elf_hash_table (info)->splt;
964
965
  /* As an extra sanity check, verify that all plt entries have
966
     been filled in.  */
967
968
0
  if (dynobj != NULL && splt != NULL)
969
0
    {
970
0
      bfd_byte *contents = splt->contents;
971
0
      unsigned int i, size = splt->size;
972
973
0
      for (i = 0; i < size; i += 4)
974
0
  {
975
0
    unsigned int x = bfd_get_32 (dynobj, contents + i);
976
977
0
    BFD_ASSERT (x != 0);
978
0
  }
979
0
    }
980
981
0
  return true;
982
0
}
983

984
/* Return the section that should be marked against GC for a given
985
   relocation.  */
986
987
static asection *
988
xstormy16_elf_gc_mark_hook (asection *sec,
989
          struct bfd_link_info *info,
990
          Elf_Internal_Rela *rel,
991
          struct elf_link_hash_entry *h,
992
          Elf_Internal_Sym *sym)
993
0
{
994
0
  if (h != NULL)
995
0
    switch (ELF32_R_TYPE (rel->r_info))
996
0
      {
997
0
      case R_XSTORMY16_GNU_VTINHERIT:
998
0
      case R_XSTORMY16_GNU_VTENTRY:
999
0
  return NULL;
1000
0
      }
1001
1002
0
  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
1003
0
}
1004

1005
#define ELF_ARCH    bfd_arch_xstormy16
1006
#define ELF_MACHINE_CODE  EM_XSTORMY16
1007
#define ELF_MAXPAGESIZE   0x100
1008
1009
#define TARGET_LITTLE_SYM       xstormy16_elf32_vec
1010
#define TARGET_LITTLE_NAME  "elf32-xstormy16"
1011
1012
#define elf_info_to_howto_rel     NULL
1013
#define elf_info_to_howto     xstormy16_info_to_howto_rela
1014
#define elf_backend_relocate_section    xstormy16_elf_relocate_section
1015
#define elf_backend_gc_mark_hook    xstormy16_elf_gc_mark_hook
1016
#define elf_backend_check_relocs    xstormy16_elf_check_relocs
1017
#define elf_backend_early_size_sections \
1018
  xstormy16_elf_early_size_sections
1019
#define elf_backend_omit_section_dynsym \
1020
  _bfd_elf_omit_section_dynsym_all
1021
#define elf_backend_finish_dynamic_sections \
1022
  xstormy16_elf_finish_dynamic_sections
1023
1024
#define elf_backend_can_gc_sections   1
1025
#define elf_backend_rela_normal     1
1026
1027
#define bfd_elf32_bfd_reloc_type_lookup   xstormy16_reloc_type_lookup
1028
#define bfd_elf32_bfd_reloc_name_lookup \
1029
  xstormy16_reloc_name_lookup
1030
#define bfd_elf32_bfd_relax_section   xstormy16_elf_relax_section
1031
1032
#include "elf32-target.h"