Coverage Report

Created: 2026-03-10 08:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/bfd/elf32-mt.c
Line
Count
Source
1
/* Morpho Technologies MT specific support for 32-bit ELF
2
   Copyright (C) 2001-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/mt.h"
26
27
/* Prototypes.  */
28
static reloc_howto_type * mt_reloc_type_lookup
29
  (bfd *, bfd_reloc_code_real_type);
30
31
static bool mt_info_to_howto_rela
32
  (bfd *, arelent *, Elf_Internal_Rela *);
33
34
static bfd_reloc_status_type mt_elf_relocate_hi16
35
  (bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma);
36
37
static bfd_reloc_status_type mt_final_link_relocate
38
  (reloc_howto_type *, bfd *, asection *, bfd_byte *,
39
   Elf_Internal_Rela *, bfd_vma);
40
41
static int mt_elf_relocate_section
42
  (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
43
   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
44
45
/* Relocation tables.  */
46
static reloc_howto_type mt_elf_howto_table [] =
47
{
48
  /* This reloc does nothing.  */
49
  HOWTO (R_MT_NONE,       /* type */
50
    0,        /* rightshift */
51
    0,        /* size */
52
    0,        /* bitsize */
53
    false,      /* pc_relative */
54
    0,        /* bitpos */
55
    complain_overflow_dont, /* complain_on_overflow */
56
    bfd_elf_generic_reloc,  /* special_function */
57
    "R_MT_NONE",    /* name */
58
    false,      /* partial_inplace */
59
    0 ,       /* src_mask */
60
    0,        /* dst_mask */
61
    false),     /* pcrel_offset */
62
63
  /* A 16 bit absolute relocation.  */
64
  HOWTO (R_MT_16,       /* type */
65
    0,        /* rightshift */
66
    4,        /* size */
67
    16,       /* bitsize */
68
    false,      /* pc_relative */
69
    0,        /* bitpos */
70
    complain_overflow_dont, /* complain_on_overflow */
71
    bfd_elf_generic_reloc,  /* special_function */
72
    "R_MT_16",    /* name */
73
    false,      /* partial_inplace */
74
    0 ,       /* src_mask */
75
    0xffff,     /* dst_mask */
76
    false),     /* pcrel_offset */
77
78
  /* A 32 bit absolute relocation.  */
79
  HOWTO (R_MT_32,       /* type */
80
    0,        /* rightshift */
81
    4,        /* size */
82
    32,       /* bitsize */
83
    false,      /* pc_relative */
84
    0,        /* bitpos */
85
    complain_overflow_dont, /* complain_on_overflow */
86
    bfd_elf_generic_reloc,  /* special_function */
87
    "R_MT_32",    /* name */
88
    false,      /* partial_inplace */
89
    0 ,       /* src_mask */
90
    0xffffffff,     /* dst_mask */
91
    false),     /* pcrel_offset */
92
93
  /* A 32 bit pc-relative relocation.  */
94
  HOWTO (R_MT_32_PCREL,       /* type */
95
    0,        /* rightshift */
96
    4,        /* size */
97
    32,       /* bitsize */
98
    true,       /* pc_relative */
99
    0,        /* bitpos */
100
    complain_overflow_dont, /* complain_on_overflow */
101
    bfd_elf_generic_reloc,  /* special_function */
102
    "R_MT_32_PCREL",    /* name */
103
    false,      /* partial_inplace */
104
    0 ,       /* src_mask */
105
    0xffffffff,     /* dst_mask */
106
    true),      /* pcrel_offset */
107
108
  /* A 16 bit pc-relative relocation.  */
109
  HOWTO (R_MT_PC16,       /* type */
110
    0,        /* 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_MT_PC16",    /* name */
118
    false,      /* partial_inplace */
119
    0,        /* src_mask */
120
    0xffff,     /* dst_mask */
121
    true),      /* pcrel_offset */
122
123
  /* high 16 bits of symbol value.  */
124
  HOWTO (R_MT_HI16,      /* type */
125
   0,     /* rightshift */
126
   4,     /* size */
127
   16,      /* bitsize */
128
   false,     /* pc_relative */
129
   0,     /* bitpos */
130
   complain_overflow_dont, /* complain_on_overflow */
131
   bfd_elf_generic_reloc, /* special_function */
132
   "R_MT_HI16",      /* name */
133
   false,      /* partial_inplace */
134
   0xffff0000,    /* src_mask */
135
   0xffff0000,    /* dst_mask */
136
   false),    /* pcrel_offset */
137
138
  /* Low 16 bits of symbol value.  */
139
  HOWTO (R_MT_LO16,      /* type */
140
   0,     /* rightshift */
141
   4,     /* size */
142
   16,      /* bitsize */
143
   false,     /* pc_relative */
144
   0,     /* bitpos */
145
   complain_overflow_dont, /* complain_on_overflow */
146
   bfd_elf_generic_reloc, /* special_function */
147
   "R_MT_LO16",      /* name */
148
   false,      /* partial_inplace */
149
   0xffff,    /* src_mask */
150
   0xffff,    /* dst_mask */
151
   false),    /* pcrel_offset */
152
};
153
154
/* Map BFD reloc types to MT ELF reloc types.  */
155
156
static reloc_howto_type *
157
mt_reloc_type_lookup
158
    (bfd *          abfd ATTRIBUTE_UNUSED,
159
     bfd_reloc_code_real_type code)
160
0
{
161
  /* Note that the mt_elf_howto_table is indxed by the R_
162
     constants.  Thus, the order that the howto records appear in the
163
     table *must* match the order of the relocation types defined in
164
     include/elf/mt.h.  */
165
166
0
  switch (code)
167
0
    {
168
0
    case BFD_RELOC_NONE:
169
0
      return &mt_elf_howto_table[ (int) R_MT_NONE];
170
0
    case BFD_RELOC_16:
171
0
      return &mt_elf_howto_table[ (int) R_MT_16];
172
0
    case BFD_RELOC_32:
173
0
      return &mt_elf_howto_table[ (int) R_MT_32];
174
0
    case BFD_RELOC_32_PCREL:
175
0
      return &mt_elf_howto_table[ (int) R_MT_32_PCREL];
176
0
    case BFD_RELOC_16_PCREL:
177
0
      return &mt_elf_howto_table[ (int) R_MT_PC16];
178
0
    case BFD_RELOC_HI16:
179
0
      return &mt_elf_howto_table[ (int) R_MT_HI16];
180
0
    case BFD_RELOC_LO16:
181
0
      return &mt_elf_howto_table[ (int) R_MT_LO16];
182
183
0
    default:
184
      /* Pacify gcc -Wall.  */
185
0
      return NULL;
186
0
    }
187
0
  return NULL;
188
0
}
189
190
static reloc_howto_type *
191
mt_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
192
          const char *r_name)
193
0
{
194
0
  unsigned int i;
195
196
0
  for (i = 0;
197
0
       i < sizeof (mt_elf_howto_table) / sizeof (mt_elf_howto_table[0]);
198
0
       i++)
199
0
    if (mt_elf_howto_table[i].name != NULL
200
0
  && strcasecmp (mt_elf_howto_table[i].name, r_name) == 0)
201
0
      return &mt_elf_howto_table[i];
202
203
0
  return NULL;
204
0
}
205
206
bfd_reloc_status_type
207
mt_elf_relocate_hi16
208
    (bfd *     input_bfd,
209
     Elf_Internal_Rela * relhi,
210
     bfd_byte *    contents,
211
     bfd_vma     value)
212
0
{
213
0
  bfd_vma insn;
214
215
0
  insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
216
217
0
  value += relhi->r_addend;
218
0
  value >>= 16;
219
0
  insn = ((insn & ~0xFFFF) | value);
220
221
0
  bfd_put_32 (input_bfd, insn, contents + relhi->r_offset);
222
0
  return bfd_reloc_ok;
223
0
}
224

225
/* XXX: The following code is the result of a cut&paste.  This unfortunate
226
   practice is very widespread in the various target back-end files.  */
227
228
/* Set the howto pointer for a MT ELF reloc.  */
229
230
static bool
231
mt_info_to_howto_rela (bfd *abfd,
232
           arelent *cache_ptr,
233
           Elf_Internal_Rela *dst)
234
0
{
235
0
  unsigned int r_type;
236
237
0
  r_type = ELF32_R_TYPE (dst->r_info);
238
0
  if (r_type >= (unsigned int) R_MT_max)
239
0
    {
240
      /* xgettext:c-format */
241
0
      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
242
0
        abfd, r_type);
243
0
      bfd_set_error (bfd_error_bad_value);
244
0
      return false;
245
0
    }
246
0
  cache_ptr->howto = & mt_elf_howto_table [r_type];
247
0
  return true;
248
0
}
249
250
/* Perform a single relocation.  By default we use the standard BFD
251
   routines.  */
252
253
static bfd_reloc_status_type
254
mt_final_link_relocate
255
    (reloc_howto_type *  howto,
256
     bfd *     input_bfd,
257
     asection *    input_section,
258
     bfd_byte *    contents,
259
     Elf_Internal_Rela * rel,
260
     bfd_vma     relocation)
261
0
{
262
0
  return _bfd_final_link_relocate (howto, input_bfd, input_section,
263
0
           contents, rel->r_offset,
264
0
           relocation, rel->r_addend);
265
0
}
266
267
/* Relocate a MT ELF section.
268
   There is some attempt to make this function usable for many architectures,
269
   both USE_REL and USE_RELA ['twould be nice if such a critter existed],
270
   if only to serve as a learning tool.
271
272
   The RELOCATE_SECTION function is called by the new ELF backend linker
273
   to handle the relocations for a section.
274
275
   The relocs are always passed as Rela structures; if the section
276
   actually uses Rel structures, the r_addend field will always be
277
   zero.
278
279
   This function is responsible for adjusting the section contents as
280
   necessary, and (if using Rela relocs and generating a relocatable
281
   output file) adjusting the reloc addend as necessary.
282
283
   This function does not have to worry about setting the reloc
284
   address or the reloc symbol index.
285
286
   LOCAL_SYMS is a pointer to the swapped in local symbols.
287
288
   LOCAL_SECTIONS is an array giving the section in the input file
289
   corresponding to the st_shndx field of each local symbol.
290
291
   The global hash table entry for the global symbols can be found
292
   via elf_sym_hashes (input_bfd).
293
294
   When generating relocatable output, this function must handle
295
   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
296
   going to be the section symbol corresponding to the output
297
   section, which means that the addend must be adjusted
298
   accordingly.  */
299
300
static int
301
mt_elf_relocate_section
302
    (bfd *         output_bfd ATTRIBUTE_UNUSED,
303
     struct bfd_link_info *  info,
304
     bfd *         input_bfd,
305
     asection *        input_section,
306
     bfd_byte *        contents,
307
     Elf_Internal_Rela *     relocs,
308
     Elf_Internal_Sym *      local_syms,
309
     asection **       local_sections)
310
0
{
311
0
  Elf_Internal_Shdr *   symtab_hdr;
312
0
  struct elf_link_hash_entry ** sym_hashes;
313
0
  Elf_Internal_Rela *   rel;
314
0
  Elf_Internal_Rela *   relend;
315
316
0
  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
317
0
  sym_hashes = elf_sym_hashes (input_bfd);
318
0
  relend     = relocs + input_section->reloc_count;
319
320
0
  for (rel = relocs; rel < relend; rel ++)
321
0
    {
322
0
      reloc_howto_type *     howto;
323
0
      unsigned long      r_symndx;
324
0
      Elf_Internal_Sym *     sym;
325
0
      asection *       sec;
326
0
      struct elf_link_hash_entry * h;
327
0
      bfd_vma        relocation;
328
0
      bfd_reloc_status_type    r;
329
0
      const char *       name = NULL;
330
0
      int        r_type;
331
332
0
      r_type = ELF32_R_TYPE (rel->r_info);
333
334
0
      r_symndx = ELF32_R_SYM (rel->r_info);
335
336
0
      howto  = mt_elf_howto_table + ELF32_R_TYPE (rel->r_info);
337
0
      h      = NULL;
338
0
      sym    = NULL;
339
0
      sec    = NULL;
340
341
0
      if (r_symndx < symtab_hdr->sh_info)
342
0
  {
343
0
    sym = local_syms + r_symndx;
344
0
    sec = local_sections [r_symndx];
345
0
    relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
346
347
0
    name = bfd_elf_string_from_elf_section
348
0
      (input_bfd, symtab_hdr->sh_link, sym->st_name);
349
0
    name = name == NULL ? bfd_section_name (sec) : name;
350
0
  }
351
0
      else
352
0
  {
353
0
    bool unresolved_reloc;
354
0
    bool warned, ignored;
355
356
0
    RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
357
0
           r_symndx, symtab_hdr, sym_hashes,
358
0
           h, sec, relocation,
359
0
           unresolved_reloc, warned, ignored);
360
361
0
    name = h->root.root.string;
362
0
  }
363
364
0
      if (sec != NULL && discarded_section (sec))
365
0
  RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
366
0
           rel, 1, relend, R_MT_NONE,
367
0
           howto, 0, contents);
368
369
0
      if (bfd_link_relocatable (info))
370
0
  continue;
371
372
      /* Finally, the sole MT-specific part.  */
373
0
      switch (r_type)
374
0
  {
375
0
  case R_MT_HI16:
376
0
    r = mt_elf_relocate_hi16 (input_bfd, rel, contents, relocation);
377
0
    break;
378
0
  default:
379
0
    r = mt_final_link_relocate (howto, input_bfd, input_section,
380
0
            contents, rel, relocation);
381
0
    break;
382
0
  }
383
384
385
0
      if (r != bfd_reloc_ok)
386
0
  {
387
0
    const char * msg = (const char *) NULL;
388
389
0
    switch (r)
390
0
      {
391
0
      case bfd_reloc_overflow:
392
0
        (*info->callbacks->reloc_overflow)
393
0
    (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
394
0
     input_bfd, input_section, rel->r_offset);
395
0
        break;
396
397
0
      case bfd_reloc_undefined:
398
0
        (*info->callbacks->undefined_symbol)
399
0
    (info, name, input_bfd, input_section, rel->r_offset, true);
400
0
        break;
401
402
0
      case bfd_reloc_outofrange:
403
0
        msg = _("internal error: out of range error");
404
0
        break;
405
406
0
      case bfd_reloc_dangerous:
407
0
        msg = _("internal error: dangerous relocation");
408
0
        break;
409
410
0
      default:
411
0
        msg = _("internal error: unknown error");
412
0
        break;
413
0
      }
414
415
0
    if (msg)
416
0
      (*info->callbacks->warning) (info, msg, name, input_bfd,
417
0
           input_section, rel->r_offset);
418
0
  }
419
0
    }
420
421
0
  return true;
422
0
}
423
424
/* Look through the relocs for a section during the first phase.
425
   Since we don't do .gots or .plts, we just need to consider the
426
   virtual table relocs for gc.  */
427
428
static bool
429
mt_elf_check_relocs (bfd *abfd,
430
         struct bfd_link_info *info,
431
         asection *sec,
432
         const Elf_Internal_Rela *relocs)
433
0
{
434
0
  Elf_Internal_Shdr *symtab_hdr;
435
0
  struct elf_link_hash_entry **sym_hashes;
436
0
  const Elf_Internal_Rela *rel;
437
0
  const Elf_Internal_Rela *rel_end;
438
439
0
  if (bfd_link_relocatable (info))
440
0
    return true;
441
442
0
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
443
0
  sym_hashes = elf_sym_hashes (abfd);
444
445
0
  rel_end = relocs + sec->reloc_count;
446
0
  for (rel = relocs; rel < rel_end; rel++)
447
0
    {
448
0
      struct elf_link_hash_entry *h;
449
0
      unsigned long r_symndx;
450
451
0
      r_symndx = ELF32_R_SYM (rel->r_info);
452
0
      if (r_symndx < symtab_hdr->sh_info)
453
0
  h = NULL;
454
0
      else
455
0
  {
456
0
    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
457
0
    while (h->root.type == bfd_link_hash_indirect
458
0
     || h->root.type == bfd_link_hash_warning)
459
0
      h = (struct elf_link_hash_entry *) h->root.u.i.link;
460
0
  }
461
0
    }
462
463
0
  return true;
464
0
}
465
466
/* Return the MACH for an e_flags value.  */
467
468
static int
469
elf32_mt_machine (bfd *abfd)
470
58
{
471
58
  switch (elf_elfheader (abfd)->e_flags & EF_MT_CPU_MASK)
472
58
    {
473
0
    case EF_MT_CPU_MRISC: return bfd_mach_ms1;
474
34
    case EF_MT_CPU_MRISC2: return bfd_mach_mrisc2;
475
6
    case EF_MT_CPU_MS2:   return bfd_mach_ms2;
476
58
    }
477
478
18
  return bfd_mach_ms1;
479
58
}
480
481
static bool
482
mt_elf_object_p (bfd *abfd)
483
58
{
484
58
  bfd_default_set_arch_mach (abfd, bfd_arch_mt, elf32_mt_machine (abfd));
485
486
58
  return true;
487
58
}
488
489
/* Function to set the ELF flag bits.  */
490
491
static bool
492
mt_elf_set_private_flags (bfd *abfd, flagword flags)
493
0
{
494
0
  elf_elfheader (abfd)->e_flags = flags;
495
0
  elf_flags_init (abfd) = true;
496
0
  return true;
497
0
}
498
499
/* Merge backend specific data from an object file to the output
500
   object file when linking.  */
501
502
static bool
503
mt_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
504
0
{
505
0
  bfd *obfd = info->output_bfd;
506
0
  flagword old_flags, new_flags;
507
0
  bool ok = true;
508
509
  /* Check if we have the same endianness.  */
510
0
  if (!_bfd_generic_verify_endian_match (ibfd, info))
511
0
    return false;
512
513
  /* If they're not both mt, then merging is meaningless, so just
514
     don't do it.  */
515
0
  if (strcmp (ibfd->arch_info->arch_name, "mt") != 0)
516
0
    return true;
517
0
  if (strcmp (obfd->arch_info->arch_name, "mt") != 0)
518
0
    return true;
519
520
0
  new_flags = elf_elfheader (ibfd)->e_flags;
521
0
  old_flags = elf_elfheader (obfd)->e_flags;
522
523
#ifdef DEBUG
524
  _bfd_error_handler ("%pB: old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s",
525
          ibfd, old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no");
526
#endif
527
528
0
  if (!elf_flags_init (obfd))
529
0
    {
530
0
      old_flags = new_flags;
531
0
      elf_flags_init (obfd) = true;
532
0
    }
533
0
  else if ((new_flags & EF_MT_CPU_MASK) != (old_flags & EF_MT_CPU_MASK))
534
0
    {
535
      /* CPU has changed.  This is invalid, because MRISC, MRISC2 and
536
   MS2 are not subsets of each other.   */
537
0
      ok = false;
538
0
    }
539
540
0
  if (ok)
541
0
    {
542
0
      obfd->arch_info = ibfd->arch_info;
543
0
      elf_elfheader (obfd)->e_flags = old_flags;
544
0
    }
545
546
0
  return ok;
547
0
}
548
549
static bool
550
mt_elf_print_private_bfd_data (bfd *abfd, void *ptr)
551
26
{
552
26
  FILE *file = (FILE *) ptr;
553
26
  flagword flags;
554
555
26
  BFD_ASSERT (abfd != NULL && ptr != NULL);
556
557
  /* Print normal ELF private data.  */
558
26
  _bfd_elf_print_private_bfd_data (abfd, ptr);
559
560
26
  flags = elf_elfheader (abfd)->e_flags;
561
26
  fprintf (file, _("private flags = 0x%lx:"), (unsigned long) flags);
562
563
26
  switch (flags & EF_MT_CPU_MASK)
564
26
    {
565
7
    default:
566
7
    case EF_MT_CPU_MRISC:   fprintf (file, " ms1-16-002");  break;
567
16
    case EF_MT_CPU_MRISC2:  fprintf (file, " ms1-16-003"); break;
568
3
    case EF_MT_CPU_MS2:     fprintf (file, " ms2"); break;
569
26
    }
570
571
26
  fputc ('\n', file);
572
573
  return true;
574
26
}
575
576

577
#define TARGET_BIG_SYM   mt_elf32_vec
578
#define TARGET_BIG_NAME  "elf32-mt"
579
580
#define ELF_ARCH   bfd_arch_mt
581
#define ELF_MACHINE_CODE EM_MT
582
#define ELF_MAXPAGESIZE  1 /* No pages on the MT.  */
583
584
#define elf_info_to_howto_rel     NULL
585
#define elf_info_to_howto     mt_info_to_howto_rela
586
587
#define elf_backend_relocate_section    mt_elf_relocate_section
588
589
#define bfd_elf32_bfd_reloc_type_lookup   mt_reloc_type_lookup
590
#define bfd_elf32_bfd_reloc_name_lookup   mt_reloc_name_lookup
591
592
#define elf_backend_check_relocs    mt_elf_check_relocs
593
#define elf_backend_object_p      mt_elf_object_p
594
#define elf_backend_rela_normal     1
595
596
#define elf_backend_can_gc_sections   1
597
598
#define bfd_elf32_bfd_set_private_flags   mt_elf_set_private_flags
599
#define bfd_elf32_bfd_merge_private_bfd_data  mt_elf_merge_private_bfd_data
600
#define bfd_elf32_bfd_print_private_bfd_data  mt_elf_print_private_bfd_data
601
602
#include "elf32-target.h"