Coverage Report

Created: 2026-07-25 10:20

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