(root)/
binutils-2.41/
bfd/
elf32-visium.c
       1  /* Visium-specific support for 32-bit ELF.
       2  
       3     Copyright (C) 2003-2023 Free Software Foundation, Inc.
       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,
      20     Boston, MA 02110-1301, USA.  */
      21  
      22  #include "sysdep.h"
      23  #include "bfd.h"
      24  #include "sysdep.h"
      25  #include "libbfd.h"
      26  #include "elf-bfd.h"
      27  #include "elf/visium.h"
      28  #include "libiberty.h"
      29  
      30  static bfd_reloc_status_type visium_elf_howto_parity_reloc
      31    (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
      32  
      33  static reloc_howto_type visium_elf_howto_table[] = {
      34    /* This reloc does nothing.  */
      35    HOWTO (R_VISIUM_NONE,		/* type */
      36  	 0,			/* rightshift */
      37  	 0,			/* size */
      38  	 0,			/* bitsize */
      39  	 false,			/* pc_relative */
      40  	 0,			/* bitpos */
      41  	 complain_overflow_dont,	/* complain_on_overflow */
      42  	 bfd_elf_generic_reloc,	/* special_function */
      43  	 "R_VISIUM_NONE",	/* name */
      44  	 false,			/* partial_inplace */
      45  	 0,			/* src_mask */
      46  	 0,			/* dst_mask */
      47  	 false),		/* pcrel_offset */
      48  
      49    /* A 8 bit absolute relocation.  */
      50    HOWTO (R_VISIUM_8,		/* type */
      51  	 0,			/* rightshift */
      52  	 1,			/* size */
      53  	 8,			/* bitsize */
      54  	 false,			/* pc_relative */
      55  	 0,			/* bitpos */
      56  	 complain_overflow_bitfield,	/* complain_on_overflow */
      57  	 bfd_elf_generic_reloc,	/* special_function */
      58  	 "R_VISIUM_8",		/* name */
      59  	 false,			/* partial_inplace */
      60  	 0x00,			/* src_mask */
      61  	 0xff,			/* dst_mask */
      62  	 false),		/* pcrel_offset */
      63  
      64    /* A 16 bit absolute relocation.  */
      65    HOWTO (R_VISIUM_16,		/* type */
      66  	 0,			/* rightshift */
      67  	 2,			/* size */
      68  	 16,			/* bitsize */
      69  	 false,			/* pc_relative */
      70  	 0,			/* bitpos */
      71  	 complain_overflow_bitfield,	/* complain_on_overflow */
      72  	 bfd_elf_generic_reloc,	/* special_function */
      73  	 "R_VISIUM_16",		/* name */
      74  	 false,			/* partial_inplace */
      75  	 0x0000,		/* src_mask */
      76  	 0xffff,		/* dst_mask */
      77  	 false),		/* pcrel_offset */
      78  
      79    /* A 32 bit absolute relocation.  */
      80    HOWTO (R_VISIUM_32,		/* type */
      81  	 0,			/* rightshift */
      82  	 4,			/* size */
      83  	 32,			/* bitsize */
      84  	 false,			/* pc_relative */
      85  	 0,			/* bitpos */
      86  	 complain_overflow_bitfield,	/* complain_on_overflow */
      87  	 bfd_elf_generic_reloc,	/* special_function */
      88  	 "R_VISIUM_32",		/* name */
      89  	 false,			/* partial_inplace */
      90  	 0x00000000,		/* src_mask */
      91  	 0xffffffff,		/* dst_mask */
      92  	 false),		/* pcrel_offset */
      93  
      94  
      95    /* A 8 bit PC relative relocation.  */
      96    HOWTO (R_VISIUM_8_PCREL,		/* type */
      97  	 0,			/* rightshift */
      98  	 1,			/* size */
      99  	 8,			/* bitsize */
     100  	 true,			/* pc_relative */
     101  	 0,			/* bitpos */
     102  	 complain_overflow_bitfield,	/* complain_on_overflow */
     103  	 bfd_elf_generic_reloc,	/* special_function */
     104  	 "R_VISIUM_8_PCREL",	/* name */
     105  	 false,			/* partial_inplace */
     106  	 0x00,			/* src_mask */
     107  	 0xff,			/* dst_mask */
     108  	 true),			/* pcrel_offset */
     109  
     110    /* A 16 bit PC relative relocation.  */
     111    HOWTO (R_VISIUM_16_PCREL,	/* type */
     112  	 0,			/* rightshift */
     113  	 2,			/* size */
     114  	 16,			/* bitsize */
     115  	 true,			/* pc_relative */
     116  	 0,			/* bitpos */
     117  	 complain_overflow_bitfield,	/* complain_on_overflow */
     118  	 bfd_elf_generic_reloc,	/* special_function */
     119  	 "R_VISIUM_16_PCREL",	/* name */
     120  	 false,			/* partial inplace */
     121  	 0x0000,		/* src_mask */
     122  	 0xffff,		/* dst_mask */
     123  	 true),			/* pcrel_offset */
     124  
     125    /* A 32-bit PC relative relocation.  */
     126    HOWTO (R_VISIUM_32_PCREL,	/* type */
     127  	 0,			/* rightshift */
     128  	 4,			/* size */
     129  	 32,			/* bitsize */
     130  	 true,			/* pc_relative */
     131  	 0,			/* bitpos */
     132  	 complain_overflow_bitfield,	/* complain_on_overflow */
     133  	 bfd_elf_generic_reloc,	/* special_function */
     134  	 "R_VISIUM_32_PCREL",	/* name */
     135  	 false,			/* partial_inplace */
     136  	 0,			/* src_mask */
     137  	 0xffffffff,		/* dst_mask */
     138  	 true),			/* pcrel_offset */
     139  
     140    /* A 16-bit PC word relative offset, relative to start of instruction
     141       and always in the second half of the instruction.  */
     142    HOWTO (R_VISIUM_PC16,		/* type */
     143  	 2,			/* rightshift */
     144  	 4,			/* size */
     145  	 16,			/* bitsize */
     146  	 true,			/* pc_relative */
     147  	 0,			/* bitpos */
     148  	 complain_overflow_signed,	/* complain_on_overflow */
     149  	 visium_elf_howto_parity_reloc,	/* special_function */
     150  	 "R_VISIUM_PC16",	/* name */
     151  	 false,			/* partial_inplace */
     152  	 0x00000000,		/* src_mask */
     153  	 0x0000ffff,		/* dst_mask */
     154  	 true),			/* pcrel_offset */
     155  
     156    /* The high 16 bits of symbol value.  */
     157    HOWTO (R_VISIUM_HI16,		/* type */
     158  	 16,			/* rightshift */
     159  	 4,			/* size */
     160  	 16,			/* bitsize */
     161  	 false,			/* pc_relative */
     162  	 0,			/* bitpos */
     163  	 complain_overflow_dont,	/* complain_on_overflow */
     164  	 visium_elf_howto_parity_reloc,	/* special_function */
     165  	 "R_VISIUM_HI16",	/* name */
     166  	 false,			/* partial_inplace */
     167  	 0x00000000,		/* src_mask */
     168  	 0x0000ffff,		/* dst_mask */
     169  	 false),		/* pcrel_offset */
     170  
     171    /* The low 16 bits of symbol value.  */
     172    HOWTO (R_VISIUM_LO16,		/* type */
     173  	 0,			/* rightshift */
     174  	 4,			/* size */
     175  	 16,			/* bitsize */
     176  	 false,			/* pc_relative */
     177  	 0,			/* bitpos */
     178  	 complain_overflow_dont,	/* complain_on_overflow */
     179  	 visium_elf_howto_parity_reloc,	/* special_function */
     180  	 "R_VISIUM_LO16",	/* name */
     181  	 false,			/* partial_inplace */
     182  	 0x00000000,		/* src_mask */
     183  	 0x0000ffff,		/* dst_mask */
     184  	 false),		/* pcrel_offset */
     185  
     186    /* A 16 bit immediate value.  */
     187    HOWTO (R_VISIUM_IM16,		/* type */
     188  	 0,			/* rightshift */
     189  	 4,			/* size */
     190  	 16,			/* bitsize */
     191  	 false,			/* pc_relative */
     192  	 0,			/* bitpos */
     193  	 complain_overflow_unsigned,	/* complain_on_overflow */
     194  	 visium_elf_howto_parity_reloc,	/* special_function */
     195  	 "R_VISIUM_IM16",	/* name */
     196  	 false,			/* partial_inplace */
     197  	 0x0000000,		/* src_mask */
     198  	 0x000ffff,		/* dst_mask */
     199  	 false),		/* pcrel_offset */
     200  
     201    /* The high 16 bits of symbol value, pc relative.  */
     202    HOWTO (R_VISIUM_HI16_PCREL,	/* type */
     203  	 16,			/* rightshift */
     204  	 4,			/* size */
     205  	 16,			/* bitsize */
     206  	 true,			/* pc_relative */
     207  	 0,			/* bitpos */
     208  	 complain_overflow_dont,	/* complain_on_overflow */
     209  	 visium_elf_howto_parity_reloc,	/* special_function */
     210  	 "R_VISIUM_HI16_PCREL",	/* name */
     211  	 false,			/* partial_inplace */
     212  	 0x00000000,		/* src_mask */
     213  	 0x0000ffff,		/* dst_mask */
     214  	 true),			/* pcrel_offset */
     215  
     216    /* The low 16 bits of symbol value, pc relative.  */
     217    HOWTO (R_VISIUM_LO16_PCREL,	/* type */
     218  	 0,			/* rightshift */
     219  	 4,			/* size */
     220  	 16,			/* bitsize */
     221  	 true,			/* pc_relative */
     222  	 0,			/* bitpos */
     223  	 complain_overflow_dont,	/* complain_on_overflow */
     224  	 visium_elf_howto_parity_reloc,	/* special_function */
     225  	 "R_VISIUM_LO16_PCREL",	/* name */
     226  	 false,			/* partial_inplace */
     227  	 0x00000000,		/* src_mask */
     228  	 0x0000ffff,		/* dst_mask */
     229  	 true),			/* pcrel_offset */
     230  
     231    /* A 16 bit immediate value, pc relative.  */
     232    HOWTO (R_VISIUM_IM16_PCREL,	/* type */
     233  	 0,			/* rightshift */
     234  	 4,			/* size */
     235  	 16,			/* bitsize */
     236  	 true,			/* pc_relative */
     237  	 0,			/* bitpos */
     238  	 complain_overflow_unsigned,	/* complain_on_overflow */
     239  	 visium_elf_howto_parity_reloc,	/* special_function */
     240  	 "R_VISIUM_IM16_PCREL",	/* name */
     241  	 false,			/* partial_inplace */
     242  	 0x0000000,		/* src_mask */
     243  	 0x000ffff,		/* dst_mask */
     244  	 true),			/* pcrel_offset */
     245  
     246  };
     247  
     248  /* GNU extension to record C++ vtable hierarchy.  */
     249  static reloc_howto_type visium_elf_vtinherit_howto =
     250    HOWTO (R_VISIUM_GNU_VTINHERIT,      /* type */
     251  	 0,			   /* rightshift */
     252  	 4,			   /* size */
     253  	 0,			   /* bitsize */
     254  	 false,			   /* pc_relative */
     255  	 0,			   /* bitpos */
     256  	 complain_overflow_dont,   /* complain_on_overflow */
     257  	 NULL,			   /* special_function */
     258  	 "R_VISIUM_GNU_VTINHERIT", /* name */
     259  	 false,			   /* partial_inplace */
     260  	 0,			   /* src_mask */
     261  	 0,			   /* dst_mask */
     262  	 false);		   /* pcrel_offset */
     263  
     264  /* GNU extension to record C++ vtable member usage.  */
     265  static reloc_howto_type visium_elf_vtentry_howto =
     266    HOWTO (R_VISIUM_GNU_VTENTRY,	   /* type */
     267  	 0,			   /* rightshift */
     268  	 4,			   /* size */
     269  	 0,			   /* bitsize */
     270  	 false,			   /* pc_relative */
     271  	 0,			   /* bitpos */
     272  	 complain_overflow_dont,   /* complain_on_overflow */
     273  	 NULL,			   /* special_function */
     274  	 "R_VISIUM_GNU_VTENTRY",   /* name */
     275  	 false,			   /* partial_inplace */
     276  	 0,			   /* src_mask */
     277  	 0,			   /* dst_mask */
     278  	 false);		   /* pcrel_offset */
     279  
     280  /* Return the parity bit for INSN shifted to its final position.  */
     281  
     282  static bfd_vma
     283  visium_parity_bit (bfd_vma insn)
     284  {
     285    bfd_vma p = 0;
     286    int i;
     287  
     288    for (i = 0; i < 31; i++)
     289      {
     290        p ^= (insn & 1);
     291        insn >>= 1;
     292      }
     293  
     294    return p << 31;
     295  }
     296  
     297  /* This "special function" will only be used when the input and
     298     output files have different formats ie. when generating S-records
     299     directly using "--oformat srec". Otherwise we use
     300     _bfd_final_link_relocate which uses a howto structure, but does
     301     not use the special_function field.
     302  
     303     It sets instruction parity to even.  This cannot be done by a howto.  */
     304  
     305  static bfd_reloc_status_type
     306  visium_elf_howto_parity_reloc (bfd * input_bfd, arelent *reloc_entry,
     307  			       asymbol *symbol, void *data,
     308  			       asection *input_section, bfd *output_bfd,
     309  			       char **error_message ATTRIBUTE_UNUSED)
     310  {
     311    bfd_reloc_status_type ret;
     312    bfd_vma relocation;
     313    bfd_byte *inplace_address;
     314    bfd_vma insn;
     315  
     316    /* This part is from bfd_elf_generic_reloc.
     317       If we're relocating, and this an external symbol, we don't want
     318       to change anything.  */
     319    if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0)
     320      {
     321        reloc_entry->address += input_section->output_offset;
     322        return bfd_reloc_ok;
     323      }
     324  
     325    /* Now do the reloc in the usual way.  */
     326  
     327    /* Sanity check the address (offset in section).  */
     328    if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section))
     329      return bfd_reloc_outofrange;
     330  
     331    ret = bfd_reloc_ok;
     332    if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL)
     333      ret = bfd_reloc_undefined;
     334  
     335    if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL)
     336      relocation = 0;
     337    else
     338      relocation = symbol->value;
     339  
     340    /* Only do this for a final link.  */
     341    if (output_bfd == (bfd *) NULL)
     342      {
     343        relocation += symbol->section->output_section->vma;
     344        relocation += symbol->section->output_offset;
     345      }
     346  
     347    relocation += reloc_entry->addend;
     348    inplace_address = (bfd_byte *) data + reloc_entry->address;
     349    insn = bfd_get_32 (input_bfd, inplace_address);
     350  
     351    if (reloc_entry->howto->pc_relative)
     352      {
     353        relocation -= input_section->output_section->vma;
     354        relocation -= input_section->output_offset;
     355        relocation -= reloc_entry->address;
     356      }
     357  
     358    switch (reloc_entry->howto->type)
     359      {
     360      case R_VISIUM_PC16:
     361        if (ret == bfd_reloc_ok
     362  	  && ((bfd_signed_vma) relocation < -0x20000
     363  	      || (bfd_signed_vma) relocation > 0x1ffff))
     364  	ret = bfd_reloc_overflow;
     365        relocation = (relocation >> 2) & 0xffff;
     366        break;
     367      case R_VISIUM_HI16:
     368      case R_VISIUM_HI16_PCREL:
     369        relocation = (relocation >> 16) & 0xffff;
     370        break;
     371      case R_VISIUM_LO16:
     372      case R_VISIUM_LO16_PCREL:
     373        relocation &= 0xffff;
     374        break;
     375      case R_VISIUM_IM16:
     376      case R_VISIUM_IM16_PCREL:
     377        if (ret == bfd_reloc_ok && (relocation & 0xffff0000) != 0)
     378  	ret = bfd_reloc_overflow;
     379        relocation &= 0xffff;
     380        break;
     381      }
     382    insn = (insn & 0x7fff0000) | relocation;
     383    insn |= visium_parity_bit (insn);
     384    bfd_put_32 (input_bfd, insn, inplace_address);
     385  
     386    if (output_bfd != (bfd *) NULL)
     387      reloc_entry->address += input_section->output_offset;
     388  
     389    return ret;
     390  }
     391  
     392  static reloc_howto_type *
     393  visium_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     394  			  bfd_reloc_code_real_type code)
     395  {
     396    /* Note that the visium_elf_howto_table is indexed by the R_
     397       constants. Thus, the order that the howto records appear in the
     398       table *must* match the order of the relocation types defined in
     399       include/elf/visium.h.  */
     400    switch (code)
     401      {
     402      case BFD_RELOC_NONE:
     403        return &visium_elf_howto_table[(int) R_VISIUM_NONE];
     404      case BFD_RELOC_8:
     405        return &visium_elf_howto_table[(int) R_VISIUM_8];
     406      case BFD_RELOC_16:
     407        return &visium_elf_howto_table[(int) R_VISIUM_16];
     408      case BFD_RELOC_32:
     409        return &visium_elf_howto_table[(int) R_VISIUM_32];
     410      case BFD_RELOC_8_PCREL:
     411        return &visium_elf_howto_table[(int) R_VISIUM_8_PCREL];
     412      case BFD_RELOC_16_PCREL:
     413        return &visium_elf_howto_table[(int) R_VISIUM_16_PCREL];
     414      case BFD_RELOC_32_PCREL:
     415        return &visium_elf_howto_table[(int) R_VISIUM_32_PCREL];
     416      case BFD_RELOC_VISIUM_REL16:
     417        return &visium_elf_howto_table[(int) R_VISIUM_PC16];
     418      case BFD_RELOC_VISIUM_HI16:
     419        return &visium_elf_howto_table[(int) R_VISIUM_HI16];
     420      case BFD_RELOC_VISIUM_LO16:
     421        return &visium_elf_howto_table[(int) R_VISIUM_LO16];
     422      case BFD_RELOC_VISIUM_IM16:
     423        return &visium_elf_howto_table[(int) R_VISIUM_IM16];
     424      case BFD_RELOC_VISIUM_HI16_PCREL:
     425        return &visium_elf_howto_table[(int) R_VISIUM_HI16_PCREL];
     426      case BFD_RELOC_VISIUM_LO16_PCREL:
     427        return &visium_elf_howto_table[(int) R_VISIUM_LO16_PCREL];
     428      case BFD_RELOC_VISIUM_IM16_PCREL:
     429        return &visium_elf_howto_table[(int) R_VISIUM_IM16_PCREL];
     430      case BFD_RELOC_VTABLE_INHERIT:
     431        return &visium_elf_vtinherit_howto;
     432      case BFD_RELOC_VTABLE_ENTRY:
     433        return &visium_elf_vtentry_howto;
     434      default:
     435        return NULL;
     436      }
     437  }
     438  
     439  static reloc_howto_type *
     440  visium_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
     441  {
     442    unsigned int i;
     443  
     444    for (i = 0;
     445         i < (sizeof (visium_elf_howto_table)
     446  	    / sizeof (visium_elf_howto_table[0])); i++)
     447      if (visium_elf_howto_table[i].name != NULL
     448  	&& strcasecmp (visium_elf_howto_table[i].name, r_name) == 0)
     449        return &visium_elf_howto_table[i];
     450  
     451    if (strcasecmp (visium_elf_vtinherit_howto.name, r_name) == 0)
     452      return &visium_elf_vtinherit_howto;
     453    if (strcasecmp (visium_elf_vtentry_howto.name, r_name) == 0)
     454      return &visium_elf_vtentry_howto;
     455  
     456    return NULL;
     457  }
     458  
     459  /* Set the howto pointer for a VISIUM ELF reloc.  */
     460  
     461  static bool
     462  visium_info_to_howto_rela (bfd *abfd, arelent *cache_ptr,
     463  			   Elf_Internal_Rela *dst)
     464  {
     465    unsigned int r_type = ELF32_R_TYPE (dst->r_info);
     466  
     467    switch (r_type)
     468      {
     469      case R_VISIUM_GNU_VTINHERIT:
     470        cache_ptr->howto = &visium_elf_vtinherit_howto;
     471        break;
     472  
     473      case R_VISIUM_GNU_VTENTRY:
     474        cache_ptr->howto = &visium_elf_vtentry_howto;
     475        break;
     476  
     477      default:
     478        if (r_type >= ARRAY_SIZE (visium_elf_howto_table))
     479  	{
     480  	  /* xgettext:c-format */
     481  	  _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
     482  			      abfd, r_type);
     483  	  bfd_set_error (bfd_error_bad_value);
     484  	  return false;
     485  	}
     486        cache_ptr->howto = &visium_elf_howto_table[r_type];
     487        break;
     488      }
     489    return true;
     490  }
     491  
     492  /* Look through the relocs for a section during the first phase.
     493     Since we don't do .gots or .plts, we just need to consider the
     494     virtual table relocs for gc.  */
     495  
     496  static bool
     497  visium_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
     498  			 asection *sec, const Elf_Internal_Rela *relocs)
     499  {
     500    Elf_Internal_Shdr *symtab_hdr;
     501    struct elf_link_hash_entry **sym_hashes;
     502    const Elf_Internal_Rela *rel;
     503    const Elf_Internal_Rela *rel_end;
     504  
     505    if (bfd_link_relocatable (info))
     506      return true;
     507  
     508    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
     509    sym_hashes = elf_sym_hashes (abfd);
     510  
     511    rel_end = relocs + sec->reloc_count;
     512    for (rel = relocs; rel < rel_end; rel++)
     513      {
     514        struct elf_link_hash_entry *h;
     515        unsigned long r_symndx;
     516  
     517        r_symndx = ELF32_R_SYM (rel->r_info);
     518        if (r_symndx < symtab_hdr->sh_info)
     519  	h = NULL;
     520        else
     521  	{
     522  	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
     523  	  while (h->root.type == bfd_link_hash_indirect
     524  		 || h->root.type == bfd_link_hash_warning)
     525  	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
     526  	}
     527  
     528        switch (ELF32_R_TYPE (rel->r_info))
     529  	{
     530  	  /* This relocation describes the C++ object vtable hierarchy.
     531  	     Reconstruct it for later use during GC.  */
     532  	case R_VISIUM_GNU_VTINHERIT:
     533  	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
     534  	    return false;
     535  	  break;
     536  
     537  	  /* This relocation describes which C++ vtable entries are actually
     538  	     used.  Record for later use during GC.  */
     539  	case R_VISIUM_GNU_VTENTRY:
     540  	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
     541  	    return false;
     542  	  break;
     543  	}
     544      }
     545  
     546    return true;
     547  }
     548  
     549  /* Relocate a VISIUM ELF section.  */
     550  
     551  static int
     552  visium_elf_relocate_section (bfd *output_bfd,
     553  			     struct bfd_link_info *info, bfd *input_bfd,
     554  			     asection *input_section, bfd_byte *contents,
     555  			     Elf_Internal_Rela *relocs,
     556  			     Elf_Internal_Sym *local_syms,
     557  			     asection **local_sections)
     558  {
     559    Elf_Internal_Shdr *symtab_hdr;
     560    struct elf_link_hash_entry **sym_hashes;
     561    Elf_Internal_Rela *rel;
     562    Elf_Internal_Rela *relend;
     563  
     564    symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
     565    sym_hashes = elf_sym_hashes (input_bfd);
     566    relend = relocs + input_section->reloc_count;
     567  
     568    for (rel = relocs; rel < relend; rel++)
     569      {
     570        reloc_howto_type *howto;
     571        unsigned long r_symndx;
     572        Elf_Internal_Sym *sym;
     573        asection *sec;
     574        struct elf_link_hash_entry *h;
     575        bfd_vma relocation;
     576        bfd_reloc_status_type r;
     577        const char *name = NULL;
     578        int r_type;
     579        bfd_vma insn;
     580  
     581        r_type = ELF32_R_TYPE (rel->r_info);
     582  
     583        if (r_type == R_VISIUM_GNU_VTINHERIT || r_type == R_VISIUM_GNU_VTENTRY)
     584  	continue;
     585  
     586        r_symndx = ELF32_R_SYM (rel->r_info);
     587  
     588        howto = visium_elf_howto_table + ELF32_R_TYPE (rel->r_info);
     589        h = NULL;
     590        sym = NULL;
     591        sec = NULL;
     592  
     593        if (r_symndx < symtab_hdr->sh_info)
     594  	{
     595  	  /* This is a local symbol.  */
     596  	  sym = local_syms + r_symndx;
     597  	  sec = local_sections[r_symndx];
     598  	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
     599  
     600  	  name = bfd_elf_string_from_elf_section
     601  	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
     602  	  name = name == NULL ? bfd_section_name (sec) : name;
     603  	}
     604        else
     605  	{
     606  	  bool unresolved_reloc;
     607  	  bool warned, ignored;
     608  
     609  	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
     610  				   r_symndx, symtab_hdr, sym_hashes,
     611  				   h, sec, relocation,
     612  				   unresolved_reloc, warned, ignored);
     613  
     614  	  name = h->root.root.string;
     615  	}
     616  
     617        if (sec != NULL && discarded_section (sec))
     618  	{
     619  	  /* For relocs against symbols from removed linkonce sections,
     620  	     or sections discarded by a linker script, we just want the
     621  	     section contents zeroed.  Avoid any special processing.  */
     622  	  _bfd_clear_contents (howto, input_bfd, input_section,
     623  			       contents, rel->r_offset);
     624  
     625  	  rel->r_info = 0;
     626  	  rel->r_addend = 0;
     627  	  continue;
     628  	}
     629  
     630        if (bfd_link_relocatable (info))
     631  	continue;
     632  
     633        switch (r_type)
     634  	{
     635  	case R_VISIUM_PC16:
     636  	case R_VISIUM_HI16:
     637  	case R_VISIUM_LO16:
     638  	case R_VISIUM_IM16:
     639  	case R_VISIUM_HI16_PCREL:
     640  	case R_VISIUM_LO16_PCREL:
     641  	case R_VISIUM_IM16_PCREL:
     642  	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
     643  					contents, rel->r_offset,
     644  					relocation, rel->r_addend);
     645  
     646  	  /* For instruction relocations, the parity needs correcting.  */
     647  	  if (r == bfd_reloc_ok)
     648  	    {
     649  	      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
     650  	      insn = (insn & 0x7fffffff) | visium_parity_bit (insn);
     651  	      bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
     652  	    }
     653  	  break;
     654  
     655  	default:
     656  	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
     657  					contents, rel->r_offset,
     658  					relocation, rel->r_addend);
     659  	  break;
     660  	}
     661  
     662        if (r != bfd_reloc_ok)
     663  	{
     664  	  const char *msg = (const char *) NULL;
     665  
     666  	  switch (r)
     667  	    {
     668  	    case bfd_reloc_overflow:
     669  	      (*info->callbacks->reloc_overflow)
     670  		(info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
     671  		 input_bfd, input_section, rel->r_offset);
     672  	      break;
     673  
     674  	    case bfd_reloc_undefined:
     675  	      (*info->callbacks->undefined_symbol)
     676  		(info, name, input_bfd, input_section, rel->r_offset, true);
     677  	      break;
     678  
     679  	    case bfd_reloc_outofrange:
     680  	      msg = _("internal error: out of range error");
     681  	      break;
     682  
     683  	    case bfd_reloc_notsupported:
     684  	      msg = _("internal error: unsupported relocation error");
     685  	      break;
     686  
     687  	    case bfd_reloc_dangerous:
     688  	      msg = _("internal error: dangerous relocation");
     689  	      break;
     690  
     691  	    default:
     692  	      msg = _("internal error: unknown error");
     693  	      break;
     694  	    }
     695  
     696  	  if (msg)
     697  	    (*info->callbacks->warning) (info, msg, name, input_bfd,
     698  					 input_section, rel->r_offset);
     699  	}
     700      }
     701  
     702    return true;
     703  }
     704  
     705  /* This function is called during section gc to discover the section a
     706     to which a particular relocation refers.  Return the section that
     707     should be marked against GC for a given relocation.  */
     708  
     709  static asection *
     710  visium_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info,
     711  			 Elf_Internal_Rela *rel, struct elf_link_hash_entry *h,
     712  			 Elf_Internal_Sym *sym)
     713  {
     714    if (h != NULL)
     715      switch (ELF32_R_TYPE (rel->r_info))
     716        {
     717        case R_VISIUM_GNU_VTINHERIT:
     718        case R_VISIUM_GNU_VTENTRY:
     719  	return NULL;
     720        }
     721  
     722    return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
     723  }
     724  
     725  static bool
     726  visium_elf_init_file_header (bfd *abfd, struct bfd_link_info *info)
     727  {
     728    Elf_Internal_Ehdr *i_ehdrp;
     729  
     730    if (!_bfd_elf_init_file_header (abfd, info))
     731      return false;
     732  
     733    i_ehdrp = elf_elfheader (abfd);
     734    i_ehdrp->e_ident[EI_ABIVERSION] = 1;
     735    return true;
     736  }
     737  
     738  /* Function to set the ELF flag bits.  */
     739  
     740  static bool
     741  visium_elf_set_private_flags (bfd *abfd, flagword flags)
     742  {
     743    elf_elfheader (abfd)->e_flags = flags;
     744    elf_flags_init (abfd) = true;
     745    return true;
     746  }
     747  
     748  /* Copy backend specific data from one object module to another.  */
     749  
     750  static bool
     751  visium_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
     752  {
     753    if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
     754        || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     755      return true;
     756  
     757    BFD_ASSERT (!elf_flags_init (obfd)
     758  	      || elf_elfheader (obfd)->e_flags ==
     759  	      elf_elfheader (ibfd)->e_flags);
     760  
     761    elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
     762    elf_flags_init (obfd) = true;
     763  
     764    /* Copy object attributes.  */
     765    _bfd_elf_copy_obj_attributes (ibfd, obfd);
     766  
     767    return true;
     768  }
     769  
     770  /* Merge backend specific data from an object
     771     file to the output object file when linking.  */
     772  
     773  static bool
     774  visium_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
     775  {
     776    bfd *obfd = info->output_bfd;
     777    flagword old_flags;
     778    flagword new_flags;
     779    flagword mismatch;
     780    const char *opt_arch = NULL;
     781    const char *new_opt_with = NULL;
     782    const char *old_opt_with = NULL;
     783    const char *with = "with";
     784    const char *without = "without";
     785    const char *mcm = "mcm";
     786    const char *mcm24 = "mcm24";
     787    const char *gr6 = "gr6";
     788  
     789    new_flags = elf_elfheader (ibfd)->e_flags;
     790    old_flags = elf_elfheader (obfd)->e_flags;
     791  
     792    if (!elf_flags_init (obfd))
     793      {
     794        /* First call, no flags set.  */
     795        elf_flags_init (obfd) = true;
     796        elf_elfheader (obfd)->e_flags = new_flags;
     797      }
     798    else
     799      {
     800        mismatch = (new_flags ^ old_flags)
     801  	& (EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_MCM24 | EF_VISIUM_ARCH_GR6);
     802        if (mismatch & EF_VISIUM_ARCH_GR6)
     803  	{
     804  	  opt_arch = gr6;
     805  	  new_opt_with = new_flags & EF_VISIUM_ARCH_GR6 ? with : without;
     806  	  old_opt_with = old_flags & EF_VISIUM_ARCH_GR6 ? with : without;
     807  	}
     808        else if (mismatch & EF_VISIUM_ARCH_MCM)
     809  	{
     810  	  opt_arch = mcm;
     811  	  new_opt_with = new_flags & EF_VISIUM_ARCH_MCM ? with : without;
     812  	  old_opt_with = old_flags & EF_VISIUM_ARCH_MCM ? with : without;
     813  	}
     814        else if (mismatch & EF_VISIUM_ARCH_MCM24)
     815  	{
     816  	  opt_arch = mcm24;
     817  	  new_opt_with = new_flags & EF_VISIUM_ARCH_MCM24 ? with : without;
     818  	  old_opt_with = old_flags & EF_VISIUM_ARCH_MCM24 ? with : without;
     819  	}
     820  
     821        if (mismatch)
     822  	_bfd_error_handler
     823  	  /* xgettext:c-format */
     824  	  (_("%pB: compiled %s -mtune=%s and linked with modules"
     825  	     " compiled %s -mtune=%s"),
     826  	   ibfd, new_opt_with, opt_arch, old_opt_with, opt_arch);
     827      }
     828  
     829    return true;
     830  }
     831  
     832  static bool
     833  visium_elf_print_private_bfd_data (bfd *abfd, void *ptr)
     834  {
     835    FILE *file = (FILE *) ptr;
     836    flagword flags;
     837  
     838    BFD_ASSERT (abfd != NULL && ptr != NULL);
     839  
     840    /* Print normal ELF private data.  */
     841    _bfd_elf_print_private_bfd_data (abfd, ptr);
     842  
     843    flags = elf_elfheader (abfd)->e_flags;
     844    fprintf (file, _("private flags = 0x%lx:"), (long) flags);
     845  
     846    if (flags & EF_VISIUM_ARCH_GR6)
     847      fprintf (file, " -mtune=gr6");
     848    else if (flags & EF_VISIUM_ARCH_MCM)
     849      fprintf (file, " -mtune=mcm");
     850    else if (flags & EF_VISIUM_ARCH_MCM24)
     851      fprintf (file, " -mtune=mcm24");
     852  
     853    fputc ('\n', file);
     854    return true;
     855  }
     856  
     857  #define ELF_ARCH		bfd_arch_visium
     858  #define ELF_MACHINE_CODE	EM_VISIUM
     859  #define ELF_OSABI		ELFOSABI_STANDALONE
     860  #define ELF_MAXPAGESIZE		1
     861  
     862  #define TARGET_BIG_SYM		visium_elf32_vec
     863  #define TARGET_BIG_NAME		"elf32-visium"
     864  
     865  #define elf_info_to_howto_rel			NULL
     866  #define elf_info_to_howto			visium_info_to_howto_rela
     867  #define elf_backend_relocate_section		visium_elf_relocate_section
     868  #define elf_backend_gc_mark_hook		visium_elf_gc_mark_hook
     869  #define elf_backend_check_relocs		visium_elf_check_relocs
     870  #define elf_backend_rela_normal			1
     871  
     872  #define elf_backend_can_gc_sections		1
     873  
     874  #define bfd_elf32_bfd_reloc_type_lookup		visium_reloc_type_lookup
     875  #define bfd_elf32_bfd_reloc_name_lookup		visium_reloc_name_lookup
     876  
     877  #define bfd_elf32_bfd_set_private_flags		visium_elf_set_private_flags
     878  #define bfd_elf32_bfd_copy_private_bfd_data	visium_elf_copy_private_bfd_data
     879  #define bfd_elf32_bfd_merge_private_bfd_data	visium_elf_merge_private_bfd_data
     880  #define bfd_elf32_bfd_print_private_bfd_data	visium_elf_print_private_bfd_data
     881  #define elf_backend_init_file_header		visium_elf_init_file_header
     882  
     883  #include "elf32-target.h"