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