Coverage Report

Created: 2023-08-28 06:26

/src/binutils-gdb/bfd/elf32-d10v.c
Line
Count
Source (jump to first uncovered line)
1
/* D10V-specific support for 32-bit ELF
2
   Copyright (C) 1996-2023 Free Software Foundation, Inc.
3
   Contributed by Martin Hunt (hunt@cygnus.com).
4
5
   This file is part of BFD, the Binary File Descriptor library.
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program; if not, write to the Free Software
19
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
22
#include "sysdep.h"
23
#include "bfd.h"
24
#include "libbfd.h"
25
#include "elf-bfd.h"
26
#include "elf/d10v.h"
27
28
/* Use REL instead of RELA to save space.  */
29
#define USE_REL 1
30
31
static reloc_howto_type elf_d10v_howto_table[] =
32
{
33
  /* This reloc does nothing.  */
34
  HOWTO (R_D10V_NONE,   /* Type.  */
35
   0,     /* Rightshift.  */
36
   0,     /* Size.  */
37
   0,     /* Bitsize.  */
38
   false,     /* PC_relative.  */
39
   0,     /* Bitpos.  */
40
   complain_overflow_dont,/* Complain_on_overflow.  */
41
   bfd_elf_generic_reloc, /* Special_function.  */
42
   "R_D10V_NONE",   /* Name.  */
43
   false,     /* Partial_inplace.  */
44
   0,     /* Src_mask.  */
45
   0,     /* Dst_mask.  */
46
   false),    /* PCrel_offset.  */
47
48
  /* An PC Relative 10-bit relocation, shifted by 2, right container.  */
49
  HOWTO (R_D10V_10_PCREL_R, /* Type.  */
50
   2,     /* Rightshift.  */
51
   4,     /* Size.  */
52
   8,     /* Bitsize.  */
53
   true,      /* PC_relative.  */
54
   0,     /* Bitpos.  */
55
   complain_overflow_signed, /* Complain_on_overflow.  */
56
   bfd_elf_generic_reloc, /* Special_function.  */
57
   "R_D10V_10_PCREL_R", /* Name.  */
58
   false,     /* Partial_inplace.  */
59
   0xff,      /* Src_mask.  */
60
   0xff,      /* Dst_mask.  */
61
   true),     /* PCrel_offset.  */
62
63
  /* An PC Relative 10-bit relocation, shifted by 2, left container.  */
64
  HOWTO (R_D10V_10_PCREL_L, /* Type.  */
65
   2,     /* Rightshift.  */
66
   4,     /* Size.  */
67
   8,     /* Bitsize.  */
68
   true,      /* PC_relative.  */
69
   15,      /* Bitpos.  */
70
   complain_overflow_signed, /* Complain_on_overflow.  */
71
   bfd_elf_generic_reloc, /* Special_function.  */
72
   "R_D10V_10_PCREL_L", /* Name.  */
73
   false,     /* Partial_inplace.  */
74
   0x07f8000,   /* Src_mask.  */
75
   0x07f8000,   /* Dst_mask.  */
76
   true),     /* PCrel_offset.  */
77
78
  /* A 16 bit absolute relocation.  */
79
  HOWTO (R_D10V_16,   /* Type.  */
80
   0,     /* Rightshift.  */
81
   2,     /* Size.  */
82
   16,      /* Bitsize.  */
83
   false,     /* PC_relative.  */
84
   0,     /* Bitpos.  */
85
   complain_overflow_dont,/* Complain_on_overflow.  */
86
   bfd_elf_generic_reloc, /* Special_function.  */
87
   "R_D10V_16",   /* Name.  */
88
   false,     /* Partial_inplace.  */
89
   0xffff,    /* Src_mask.  */
90
   0xffff,    /* Dst_mask.  */
91
   false),    /* PCrel_offset.  */
92
93
  /* An 18 bit absolute relocation, right shifted 2.  */
94
  HOWTO (R_D10V_18,   /* Type.  */
95
   2,     /* Rightshift.  */
96
   2,     /* Size.  */
97
   16,      /* Bitsize.  */
98
   false,     /* PC_relative.  */
99
   0,     /* Bitpos.  */
100
   complain_overflow_dont, /* Complain_on_overflow.  */
101
   bfd_elf_generic_reloc, /* Special_function.  */
102
   "R_D10V_18",   /* Name.  */
103
   false,     /* Partial_inplace.  */
104
   0xffff,    /* Src_mask.  */
105
   0xffff,    /* Dst_mask.  */
106
   false),    /* PCrel_offset.  */
107
108
  /* A relative 18 bit relocation, right shifted by 2.  */
109
  HOWTO (R_D10V_18_PCREL, /* Type.  */
110
   2,     /* Rightshift.  */
111
   4,     /* Size.  */
112
   16,      /* Bitsize.  */
113
   true,      /* PC_relative.  */
114
   0,     /* Bitpos.  */
115
   complain_overflow_signed, /* Complain_on_overflow.  */
116
   bfd_elf_generic_reloc, /* Special_function.  */
117
   "R_D10V_18_PCREL", /* Name.  */
118
   false,     /* Partial_inplace.  */
119
   0xffff,    /* Src_mask.  */
120
   0xffff,    /* Dst_mask.  */
121
   true),     /* PCrel_offset.  */
122
123
  /* A 32 bit absolute relocation.  */
124
  HOWTO (R_D10V_32,   /* Type.  */
125
   0,     /* Rightshift.  */
126
   4,     /* Size.  */
127
   32,      /* Bitsize.  */
128
   false,     /* PC_relative.  */
129
   0,     /* Bitpos.  */
130
   complain_overflow_dont,/* Complain_on_overflow.  */
131
   bfd_elf_generic_reloc, /* Special_function.  */
132
   "R_D10V_32",   /* Name.  */
133
   false,     /* Partial_inplace.  */
134
   0xffffffff,    /* Src_mask.  */
135
   0xffffffff,    /* Dst_mask.  */
136
   false),    /* PCrel_offset.  */
137
138
  /* GNU extension to record C++ vtable hierarchy.  */
139
  HOWTO (R_D10V_GNU_VTINHERIT,  /* Type.  */
140
   0,     /* Rightshift.  */
141
   4,     /* Size.  */
142
   0,     /* Bitsize.  */
143
   false,     /* PC_relative.  */
144
   0,     /* Bitpos.  */
145
   complain_overflow_dont,/* Complain_on_overflow.  */
146
   NULL,      /* Special_function.  */
147
   "R_D10V_GNU_VTINHERIT",/* Name.  */
148
   false,     /* Partial_inplace.  */
149
   0,     /* Src_mask.  */
150
   0,     /* Dst_mask.  */
151
   false),    /* PCrel_offset.  */
152
153
  /* GNU extension to record C++ vtable member usage.  */
154
  HOWTO (R_D10V_GNU_VTENTRY,  /* Type.  */
155
   0,     /* Rightshift.  */
156
   4,     /* Size.  */
157
   0,     /* Bitsize.  */
158
   false,     /* PC_relative.  */
159
   0,     /* Bitpos.  */
160
   complain_overflow_dont,/* Complain_on_overflow.  */
161
   _bfd_elf_rel_vtable_reloc_fn,  /* Special_function.  */
162
   "R_D10V_GNU_VTENTRY",  /* Name.  */
163
   false,     /* Partial_inplace.  */
164
   0,     /* Src_mask.  */
165
   0,     /* Dst_mask.  */
166
   false),    /* PCrel_offset.  */
167
};
168
169
/* Map BFD reloc types to D10V ELF reloc types.  */
170
171
struct d10v_reloc_map
172
{
173
  bfd_reloc_code_real_type bfd_reloc_val;
174
  unsigned char elf_reloc_val;
175
};
176
177
static const struct d10v_reloc_map d10v_reloc_map[] =
178
{
179
  { BFD_RELOC_NONE, R_D10V_NONE, },
180
  { BFD_RELOC_D10V_10_PCREL_R, R_D10V_10_PCREL_R },
181
  { BFD_RELOC_D10V_10_PCREL_L, R_D10V_10_PCREL_L },
182
  { BFD_RELOC_16, R_D10V_16 },
183
  { BFD_RELOC_D10V_18, R_D10V_18 },
184
  { BFD_RELOC_D10V_18_PCREL, R_D10V_18_PCREL },
185
  { BFD_RELOC_32, R_D10V_32 },
186
  { BFD_RELOC_VTABLE_INHERIT, R_D10V_GNU_VTINHERIT },
187
  { BFD_RELOC_VTABLE_ENTRY, R_D10V_GNU_VTENTRY },
188
};
189
190
static reloc_howto_type *
191
bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
192
         bfd_reloc_code_real_type code)
193
0
{
194
0
  unsigned int i;
195
196
0
  for (i = 0;
197
0
       i < sizeof (d10v_reloc_map) / sizeof (struct d10v_reloc_map);
198
0
       i++)
199
0
    if (d10v_reloc_map[i].bfd_reloc_val == code)
200
0
      return &elf_d10v_howto_table[d10v_reloc_map[i].elf_reloc_val];
201
202
0
  return NULL;
203
0
}
204
205
static reloc_howto_type *
206
bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
207
         const char *r_name)
208
0
{
209
0
  unsigned int i;
210
211
0
  for (i = 0;
212
0
       i < sizeof (elf_d10v_howto_table) / sizeof (elf_d10v_howto_table[0]);
213
0
       i++)
214
0
    if (elf_d10v_howto_table[i].name != NULL
215
0
  && strcasecmp (elf_d10v_howto_table[i].name, r_name) == 0)
216
0
      return &elf_d10v_howto_table[i];
217
218
0
  return NULL;
219
0
}
220
221
/* Set the howto pointer for an D10V ELF reloc.  */
222
223
static bool
224
d10v_info_to_howto_rel (bfd *abfd,
225
      arelent *cache_ptr,
226
      Elf_Internal_Rela *dst)
227
0
{
228
0
  unsigned int r_type;
229
230
0
  r_type = ELF32_R_TYPE (dst->r_info);
231
0
  if (r_type >= (unsigned int) R_D10V_max)
232
0
    {
233
      /* xgettext:c-format */
234
0
      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
235
0
        abfd, r_type);
236
0
      bfd_set_error (bfd_error_bad_value);
237
0
      return false;
238
0
    }
239
0
  cache_ptr->howto = &elf_d10v_howto_table[r_type];
240
0
  return true;
241
0
}
242
243
static asection *
244
elf32_d10v_gc_mark_hook (asection *sec,
245
       struct bfd_link_info *info,
246
       Elf_Internal_Rela *rel,
247
       struct elf_link_hash_entry *h,
248
       Elf_Internal_Sym *sym)
249
0
{
250
0
  if (h != NULL)
251
0
    switch (ELF32_R_TYPE (rel->r_info))
252
0
      {
253
0
      case R_D10V_GNU_VTINHERIT:
254
0
      case R_D10V_GNU_VTENTRY:
255
0
  return NULL;
256
0
      }
257
258
0
  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
259
0
}
260
261
/* Look through the relocs for a section during the first phase.
262
   Since we don't do .gots or .plts, we just need to consider the
263
   virtual table relocs for gc.  */
264
265
static bool
266
elf32_d10v_check_relocs (bfd *abfd,
267
       struct bfd_link_info *info,
268
       asection *sec,
269
       const Elf_Internal_Rela *relocs)
270
0
{
271
0
  Elf_Internal_Shdr *symtab_hdr;
272
0
  struct elf_link_hash_entry **sym_hashes;
273
0
  const Elf_Internal_Rela *rel;
274
0
  const Elf_Internal_Rela *rel_end;
275
276
0
  if (bfd_link_relocatable (info))
277
0
    return true;
278
279
0
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
280
0
  sym_hashes = elf_sym_hashes (abfd);
281
282
0
  rel_end = relocs + sec->reloc_count;
283
0
  for (rel = relocs; rel < rel_end; rel++)
284
0
    {
285
0
      struct elf_link_hash_entry *h;
286
0
      unsigned long r_symndx;
287
288
0
      r_symndx = ELF32_R_SYM (rel->r_info);
289
0
      if (r_symndx < symtab_hdr->sh_info)
290
0
  h = NULL;
291
0
      else
292
0
  {
293
0
    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
294
0
    while (h->root.type == bfd_link_hash_indirect
295
0
     || h->root.type == bfd_link_hash_warning)
296
0
      h = (struct elf_link_hash_entry *) h->root.u.i.link;
297
0
  }
298
299
0
      switch (ELF32_R_TYPE (rel->r_info))
300
0
  {
301
  /* This relocation describes the C++ object vtable hierarchy.
302
     Reconstruct it for later use during GC.  */
303
0
  case R_D10V_GNU_VTINHERIT:
304
0
    if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
305
0
      return false;
306
0
    break;
307
308
  /* This relocation describes which C++ vtable entries are actually
309
     used.  Record for later use during GC.  */
310
0
  case R_D10V_GNU_VTENTRY:
311
0
    if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
312
0
      return false;
313
0
    break;
314
0
  }
315
0
    }
316
317
0
  return true;
318
0
}
319
320
static bfd_vma
321
extract_rel_addend (bfd *abfd,
322
        bfd_byte *where,
323
        reloc_howto_type *howto)
324
0
{
325
0
  bfd_vma insn, val;
326
327
0
  switch (bfd_get_reloc_size (howto))
328
0
    {
329
0
    case 1:
330
0
      insn = bfd_get_8 (abfd, where);
331
0
      break;
332
0
    case 2:
333
0
      insn = bfd_get_16 (abfd, where);
334
0
      break;
335
0
    case 4:
336
0
      insn = bfd_get_32 (abfd, where);
337
0
      break;
338
0
    default:
339
0
      abort ();
340
0
    }
341
342
0
  val = (insn & howto->dst_mask) >> howto->bitpos << howto->rightshift;
343
  /* We should really be testing for signed addends here, but we don't
344
     have that info directly in the howto.  */
345
0
  if (howto->pc_relative)
346
0
    {
347
0
      bfd_vma sign;
348
0
      sign = howto->dst_mask & (~howto->dst_mask >> 1 | ~(-(bfd_vma) 1 >> 1));
349
0
      sign = sign >> howto->bitpos << howto->rightshift;
350
0
      val = (val ^ sign) - sign;
351
0
    }
352
0
  return val;
353
0
}
354
355
static void
356
insert_rel_addend (bfd *abfd,
357
       bfd_byte *where,
358
       reloc_howto_type *howto,
359
       bfd_vma addend)
360
0
{
361
0
  bfd_vma insn;
362
363
0
  addend = (addend >> howto->rightshift << howto->bitpos) & howto->dst_mask;
364
0
  insn = ~howto->dst_mask;
365
0
  switch (bfd_get_reloc_size (howto))
366
0
    {
367
0
    case 1:
368
0
      insn &= bfd_get_8 (abfd, where);
369
0
      insn |= addend;
370
0
      bfd_put_8 (abfd, insn, where);
371
0
      break;
372
0
    case 2:
373
0
      insn &= bfd_get_16 (abfd, where);
374
0
      insn |= addend;
375
0
      bfd_put_16 (abfd, insn, where);
376
0
      break;
377
0
    case 4:
378
0
      insn &= bfd_get_32 (abfd, where);
379
0
      insn |= addend;
380
0
      bfd_put_32 (abfd, insn, where);
381
0
      break;
382
0
    default:
383
0
      abort ();
384
0
    }
385
0
}
386
387
/* Relocate a D10V ELF section.  */
388
389
static int
390
elf32_d10v_relocate_section (bfd *output_bfd,
391
           struct bfd_link_info *info,
392
           bfd *input_bfd,
393
           asection *input_section,
394
           bfd_byte *contents,
395
           Elf_Internal_Rela *relocs,
396
           Elf_Internal_Sym *local_syms,
397
           asection **local_sections)
398
0
{
399
0
  Elf_Internal_Shdr *symtab_hdr;
400
0
  struct elf_link_hash_entry **sym_hashes;
401
0
  Elf_Internal_Rela *rel, *relend;
402
0
  const char *name;
403
404
0
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
405
0
  sym_hashes = elf_sym_hashes (input_bfd);
406
407
0
  rel = relocs;
408
0
  relend = relocs + input_section->reloc_count;
409
0
  for (; rel < relend; rel++)
410
0
    {
411
0
      int r_type;
412
0
      reloc_howto_type *howto;
413
0
      unsigned long r_symndx;
414
0
      Elf_Internal_Sym *sym;
415
0
      asection *sec;
416
0
      struct elf_link_hash_entry *h;
417
0
      bfd_vma relocation;
418
0
      bfd_reloc_status_type r;
419
420
0
      r_symndx = ELF32_R_SYM (rel->r_info);
421
0
      r_type = ELF32_R_TYPE (rel->r_info);
422
423
0
      if (r_type == R_D10V_GNU_VTENTRY
424
0
    || r_type == R_D10V_GNU_VTINHERIT)
425
0
  continue;
426
427
0
      howto = elf_d10v_howto_table + r_type;
428
0
      h = NULL;
429
0
      sym = NULL;
430
0
      sec = NULL;
431
0
      if (r_symndx < symtab_hdr->sh_info)
432
0
  {
433
0
    sym = local_syms + r_symndx;
434
0
    sec = local_sections[r_symndx];
435
0
    relocation = (sec->output_section->vma
436
0
      + sec->output_offset
437
0
      + sym->st_value);
438
0
    if (ELF_ST_TYPE (sym->st_info) == STT_SECTION
439
0
        && ((sec->flags & SEC_MERGE) != 0
440
0
      || (bfd_link_relocatable (info)
441
0
          && sec->output_offset != 0)))
442
0
      {
443
0
        bfd_vma addend;
444
0
        bfd_byte *where = contents + rel->r_offset;
445
446
0
        addend = extract_rel_addend (input_bfd, where, howto);
447
448
0
        if (bfd_link_relocatable (info))
449
0
    addend += sec->output_offset;
450
0
        else
451
0
    {
452
0
      asection *msec = sec;
453
0
      addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec,
454
0
               addend);
455
0
      addend -= relocation;
456
0
      addend += msec->output_section->vma + msec->output_offset;
457
0
    }
458
0
        insert_rel_addend (input_bfd, where, howto, addend);
459
0
      }
460
0
  }
461
0
      else
462
0
  {
463
0
    bool unresolved_reloc, warned, ignored;
464
465
0
    RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
466
0
           r_symndx, symtab_hdr, sym_hashes,
467
0
           h, sec, relocation,
468
0
           unresolved_reloc, warned, ignored);
469
0
  }
470
471
0
      if (sec != NULL && discarded_section (sec))
472
0
  RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
473
0
           rel, 1, relend, howto, 0, contents);
474
475
0
      if (bfd_link_relocatable (info))
476
0
  continue;
477
478
0
      if (h != NULL)
479
0
  name = h->root.root.string;
480
0
      else
481
0
  {
482
0
    name = (bfd_elf_string_from_elf_section
483
0
      (input_bfd, symtab_hdr->sh_link, sym->st_name));
484
0
    if (name == NULL || *name == '\0')
485
0
      name = bfd_section_name (sec);
486
0
  }
487
488
0
      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
489
0
            contents, rel->r_offset,
490
0
            relocation, (bfd_vma) 0);
491
492
0
      if (r != bfd_reloc_ok)
493
0
  {
494
0
    const char * msg = (const char *) 0;
495
496
0
    switch (r)
497
0
      {
498
0
      case bfd_reloc_overflow:
499
0
        (*info->callbacks->reloc_overflow)
500
0
    (info, (h ? &h->root : NULL), name, howto->name,
501
0
     (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
502
0
        break;
503
504
0
      case bfd_reloc_undefined:
505
0
        (*info->callbacks->undefined_symbol)
506
0
    (info, name, input_bfd, input_section, rel->r_offset, true);
507
0
        break;
508
509
0
      case bfd_reloc_outofrange:
510
0
        msg = _("internal error: out of range error");
511
0
        goto common_error;
512
513
0
      case bfd_reloc_notsupported:
514
0
        msg = _("internal error: unsupported relocation error");
515
0
        goto common_error;
516
517
0
      case bfd_reloc_dangerous:
518
0
        msg = _("internal error: dangerous error");
519
0
        goto common_error;
520
521
0
      default:
522
0
        msg = _("internal error: unknown error");
523
        /* fall through */
524
525
0
      common_error:
526
0
        (*info->callbacks->warning) (info, msg, name, input_bfd,
527
0
             input_section, rel->r_offset);
528
0
        break;
529
0
      }
530
0
  }
531
0
    }
532
533
0
  return true;
534
0
}
535
#define ELF_ARCH    bfd_arch_d10v
536
#define ELF_MACHINE_CODE  EM_D10V
537
#define ELF_MACHINE_ALT1  EM_CYGNUS_D10V
538
#define ELF_MAXPAGESIZE   0x1000
539
540
#define TARGET_BIG_SYM    d10v_elf32_vec
541
#define TARGET_BIG_NAME   "elf32-d10v"
542
543
#define elf_info_to_howto        NULL
544
#define elf_info_to_howto_rel        d10v_info_to_howto_rel
545
#define elf_backend_object_p         0
546
#define elf_backend_gc_mark_hook       elf32_d10v_gc_mark_hook
547
#define elf_backend_check_relocs       elf32_d10v_check_relocs
548
#define elf_backend_relocate_section       elf32_d10v_relocate_section
549
#define elf_backend_can_gc_sections      1
550
551
#include "elf32-target.h"