/* LoongArch-specific support for ELF.
   Copyright (C) 2021-2023 Free Software Foundation, Inc.
   Contributed by Loongson Ltd.

   Based on RISC-V target.

   This file is part of BFD, the Binary File Descriptor library.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING3.  If not,
   see <http://www.gnu.org/licenses/>.  */

#include "sysdep.h"
#include "bfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/loongarch.h"
#include "elfxx-loongarch.h"

#define ALL_ONES (~ (bfd_vma) 0)

typedef struct loongarch_reloc_howto_type_struct
{
  /* The first must be reloc_howto_type!  */
  reloc_howto_type howto;
  bfd_reloc_code_real_type bfd_type;
  bool (*adjust_reloc_bits)(reloc_howto_type *, bfd_vma *);
  const char *larch_reloc_type_name;
} loongarch_reloc_howto_type;

#define LOONGARCH_DEFAULT_HOWTO(r_name)					    \
  { HOWTO (R_LARCH_##r_name, 0, 4, 32, false, 0, complain_overflow_signed,  \
	bfd_elf_generic_reloc, "R_LARCH_" #r_name, false, 0, ALL_ONES,	    \
	false), BFD_RELOC_LARCH_##r_name, NULL, NULL }

#define LOONGARCH_HOWTO(type, right, size, bits, pcrel, left, ovf, func,  \
	    name, inplace, src_mask, dst_mask, pcrel_off, btype, afunc,lname) \
  { HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,	  \
	  inplace, src_mask, dst_mask, pcrel_off), btype, afunc, lname }

#define LOONGARCH_EMPTY_HOWTO(C) \
  { EMPTY_HOWTO (C), BFD_RELOC_NONE, NULL, NULL }

static bool
reloc_bits (reloc_howto_type *howto, bfd_vma *val);
static bool
reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *fix_val);
static bool
reloc_bits_b21 (reloc_howto_type *howto, bfd_vma *fix_val);
static bool
reloc_bits_b26 (reloc_howto_type *howto, bfd_vma *val);

/* This does not include any relocation information, but should be
   good enough for GDB or objdump to read the file.  */
static loongarch_reloc_howto_type loongarch_howto_table[] =
{
  /* No relocation.  */
    LOONGARCH_HOWTO (R_LARCH_NONE,	  /* type (0).  */
	 0,				  /* rightshift */
	 0,				  /* size */
	 0,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_NONE",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 0,				  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_NONE,		  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  /* 32 bit relocation.  */
  LOONGARCH_HOWTO (R_LARCH_32,		  /* type (1).  */
	 0,				  /* rightshift */
	 4,				  /* size */
	 32,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_32",			  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_32,			  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  /* 64 bit relocation.  */
  LOONGARCH_HOWTO (R_LARCH_64,		  /* type (2).  */
	 0,				  /* rightshift */
	 8,				  /* size */
	 64,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_64",			  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_64,			  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_RELATIVE,	  /* type (3).  */
	 0,				  /* rightshift */
	 4,				  /* size */
	 32,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_RELATIVE",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_NONE,		  /* undefined?  */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_COPY,	  /* type (4).  */
	 0,				  /* rightshift */
	 0,				  /* this one is variable size */
	 0,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_bitfield,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_COPY",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 0,				  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_NONE,		  /* undefined?  */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_JUMP_SLOT,	  /* type (5).  */
	 0,				  /* rightshift */
	 8,				  /* size */
	 64,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_bitfield,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_JUMP_SLOT",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 0,				  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_NONE,		  /* undefined?  */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  /* Dynamic TLS relocations.  */
  LOONGARCH_HOWTO (R_LARCH_TLS_DTPMOD32,  /* type (6).  */
	 0,				  /* rightshift */
	 4,				  /* size */
	 32,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_TLS_DTPMOD32",	  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_DTPMOD32,	  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_DTPMOD64,  /* type (7).  */
	 0,				  /* rightshift */
	 8,				  /* size */
	 64,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_TLS_DTPMOD64",	  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_DTPMOD64,	  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_DTPREL32,  /* type (8). */
	 0,				  /* rightshift */
	 4,				  /* size */
	 32,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_TLS_DTPREL32",	  /* name */
	 true,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_DTPREL32,	  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_DTPREL64,  /* type (9).  */
	 0,				  /* rightshift */
	 8,				  /* size */
	 64,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_TLS_DTPREL64",	  /* name */
	 true,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_DTPREL64,	  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_TPREL32,	  /* type (10).  */
	 0,				  /* rightshift */
	 4,				  /* size */
	 32,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_TLS_TPREL32",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_TPREL32,	  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_TPREL64,	  /* type (11).  */
	 0,				  /* rightshift */
	 8,				  /* size */
	 64,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_TLS_TPREL64",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_TPREL64,	  /* bfd_reloc_code_real_type */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_IRELATIVE,	  /* type (12).  */
	 0,				  /* rightshift */
	 4,				  /* size */
	 32,				  /* bitsize */
	 false,				  /* pc_relative */
	 0,				  /* bitpos */
	 complain_overflow_dont,	  /* complain_on_overflow */
	 bfd_elf_generic_reloc,		  /* special_function */
	 "R_LARCH_IRELATIVE",		  /* name */
	 false,				  /* partial_inplace */
	 0,				  /* src_mask */
	 ALL_ONES,			  /* dst_mask */
	 false,				  /* pcrel_offset */
	 BFD_RELOC_NONE,		  /* undefined?  */
	 NULL,				  /* adjust_reloc_bits */
	 NULL),				  /* larch_reloc_type_name */

  LOONGARCH_EMPTY_HOWTO (13),
  LOONGARCH_EMPTY_HOWTO (14),
  LOONGARCH_EMPTY_HOWTO (15),
  LOONGARCH_EMPTY_HOWTO (16),
  LOONGARCH_EMPTY_HOWTO (17),
  LOONGARCH_EMPTY_HOWTO (18),
  LOONGARCH_EMPTY_HOWTO (19),

  LOONGARCH_HOWTO (R_LARCH_MARK_LA,		/* type (20).  */
	 0,					/* rightshift.  */
	 0,					/* size.  */
	 0,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_MARK_LA",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask.  */
	 0,					/* dst_mask.  */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_MARK_LA,		/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_MARK_PCREL,		/* type (21).  */
	 0,					/* rightshift.  */
	 0,					/* size.  */
	 0,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_MARK_PCREL",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask.  */
	 0,					/* dst_mask.  */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_MARK_PCREL,		/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_PUSH_PCREL,	/* type (22).  */
	 2,					/* rightshift.  */
	 4,					/* size.  */
	 32,					/* bitsize.  */
	 true /* FIXME: somewhat use this.  */,	/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SOP_PUSH_PCREL",		/* name.  */
	 false,					/* partial_inplace.  */
	 0x03ffffff,				/* src_mask.  */
	 0x03ffffff,				/* dst_mask.  */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_PUSH_PCREL,	/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  /* type 23-37.  */
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_ABSOLUTE),
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_DUP),
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_GPREL),
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_TLS_TPREL),
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_TLS_GOT),
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_TLS_GD),
  LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_PLT_PCREL),
  LOONGARCH_DEFAULT_HOWTO (SOP_ASSERT),
  LOONGARCH_DEFAULT_HOWTO (SOP_NOT),
  LOONGARCH_DEFAULT_HOWTO (SOP_SUB),
  LOONGARCH_DEFAULT_HOWTO (SOP_SL),
  LOONGARCH_DEFAULT_HOWTO (SOP_SR),
  LOONGARCH_DEFAULT_HOWTO (SOP_ADD),
  LOONGARCH_DEFAULT_HOWTO (SOP_AND),
  LOONGARCH_DEFAULT_HOWTO (SOP_IF_ELSE),

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_5,	  /* type (38).  */
	 0,					  /* rightshift.  */
	 4,					  /* size.  */
	 5,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 10,					  /* bitpos.  */
	 complain_overflow_signed,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_S_10_5",		  /* name.  */
	 false,					  /* partial_inplace.  */
	 0,					  /* src_mask */
	 0x7c00,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_10_5,	  /* bfd_reloc_code_real_type */
	 reloc_bits,				  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U_10_12,	  /* type (39).  */
	 0,					  /* rightshift.  */
	 4,					  /* size.  */
	 12,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 10,					  /* bitpos.  */
	 complain_overflow_unsigned,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_U_10_12",		  /* name.  */
	 false,					  /* partial_inplace.  */
	 0,					  /* src_mask */
	 0x3ffc00,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_U_10_12,	  /* bfd_reloc_code_real_type */
	 reloc_bits,				  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_12,	  /* type (40).  */
	 0,					  /* rightshift.  */
	 4,					  /* size.  */
	 12,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 10,					  /* bitpos.  */
	 complain_overflow_signed,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_S_10_12",		  /* name.  */
	 false,					  /* partial_inplace.  */
	 0,					  /* src_mask */
	 0x3ffc00,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_10_12,	  /* bfd_reloc_code_real_type */
	 reloc_bits,				  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_16,	  /* type (41).  */
	 0,					  /* rightshift.  */
	 4,					  /* size.  */
	 16,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 10,					  /* bitpos.  */
	 complain_overflow_signed,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_S_10_16",		  /* name.  */
	 false,					  /* partial_inplace.  */
	 0,					  /* src_mask */
	 0x3fffc00,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_10_16,	  /* bfd_reloc_code_real_type */
	 reloc_bits,				  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_16_S2, /* type (42).  */
	 2,					  /* rightshift.  */
	 4,					  /* size.  */
	 16,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 10,					  /* bitpos.  */
	 complain_overflow_signed,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_S_10_16_S2",	  /* name.  */
	 false,					  /* partial_inplace.  */
	 0,					  /* src_mask */
	 0x3fffc00,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2,	  /* bfd_reloc_code_real_type */
	 reloc_bits_b16,			  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_5_20,	  /* type (43).  */
	 0,					  /* rightshift.  */
	 4,					  /* size.  */
	 20,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 5,					  /* bitpos.  */
	 complain_overflow_signed,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_S_5_20",		  /* name.  */
	 false,					  /* partial_inplace.  */
	 0,					  /* src_mask */
	 0x1ffffe0,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_5_20,	  /* bfd_reloc_code_real_type */
	 reloc_bits,				  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
						  /* type (44).  */
	 2,					  /* rightshift.  */
	 4,					  /* size.  */
	 21,					  /* bitsize.  */
	 false,					  /* pc_relative.  */
	 0,					  /* bitpos.  */
	 complain_overflow_signed,		  /* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			  /* special_function.  */
	 "R_LARCH_SOP_POP_32_S_0_5_10_16_S2",	  /* name.  */
	 false,					  /* partial_inplace.  */
	 0xfc0003e0,				  /* src_mask */
	 0xfc0003e0,				  /* dst_mask */
	 false,					  /* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2,
						  /* bfd_reloc_code_real_type */
	 reloc_bits_b21,			  /* adjust_reloc_bits */
	 NULL),					  /* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_10_10_16_S2,	/* type (45).  */
	 2,					/* rightshift.  */
	 4,					/* size.  */
	 26,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SOP_POP_32_S_0_10_10_16_S2",	/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x03ffffff,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2,
						/* bfd_reloc_code_real_type */
	 reloc_bits_b26,			/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U,	/* type (46).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 32,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_unsigned,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SOP_POP_32_S_U",		/* name.  */
	 false,					/* partial_inplace.  */
	 0xffffffff00000000,			/* src_mask */
	 0x00000000ffffffff,			/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SOP_POP_32_U,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ADD8,		/* type (47).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 8,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ADD8",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ADD8,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ADD16,		/* type (48).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 16,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ADD16",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ADD16,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ADD24,		/* type (49).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 24,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ADD24",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ADD24,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ADD32,		/* type (50).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 32,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ADD32",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ADD32,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ADD64,		/* type (51).  */
	 0,					/* rightshift.  */
	 8,					/* size.  */
	 64,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ADD64",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ADD64,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SUB8,		/* type (52).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 8,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SUB8",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SUB8,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SUB16,		/* type (53).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 16,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SUB16",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SUB16,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SUB24,		/* type (54).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 24,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SUB24",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SUB24,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SUB32,		/* type (55).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 32,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SUB32",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SUB32,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_SUB64,		/* type (56).  */
	 0,					/* rightshift.  */
	 8,					/* size.  */
	 64,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_SUB64",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 ALL_ONES,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_SUB64,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GNU_VTINHERIT,	/* type (57).  */
	 0,					/* rightshift.  */
	 0,					/* size.  */
	 0,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GNU_VTINHERIT",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0,					/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_NONE,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GNU_VTENTRY,		/* type (58).  */
	 0,					/* rightshift.  */
	 0,					/* size.  */
	 0,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 NULL,					/* special_function.  */
	 "R_LARCH_GNU_VTENTRY",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0,					/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_NONE,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_EMPTY_HOWTO (59),
  LOONGARCH_EMPTY_HOWTO (60),
  LOONGARCH_EMPTY_HOWTO (61),
  LOONGARCH_EMPTY_HOWTO (62),
  LOONGARCH_EMPTY_HOWTO (63),

  /* New reloc types.  */
  LOONGARCH_HOWTO (R_LARCH_B16,			/* type (64).  */
	 2,					/* rightshift.  */
	 4,					/* size.  */
	 16,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_B16",				/* name.  */
	 false,					/* partial_inplace.  */
	 0x3fffc00,				/* src_mask */
	 0x3fffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_B16,			/* bfd_reloc_code_real_type */
	 reloc_bits_b16,			/* adjust_reloc_bits */
	 "b16"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_B21,			/* type (65).  */
	 2,					/* rightshift.  */
	 4,					/* size.  */
	 21,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_B21",				/* name.  */
	 false,					/* partial_inplace.  */
	 0xfc0003e0,				/* src_mask */
	 0xfc0003e0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_B21,			/* bfd_reloc_code_real_type */
	 reloc_bits_b21,			/* adjust_reloc_bits */
	 "b21"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_B26,			/* type (66).  */
	 2,					/* rightshift.  */
	 4,					/* size.  */
	 26,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_B26",				/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x03ffffff,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_B26,			/* bfd_reloc_code_real_type */
	 reloc_bits_b26,			/* adjust_reloc_bits */
	 "b26"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ABS_HI20,		/* type (67).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ABS_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ABS_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "abs_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ABS_LO12,		/* type (68).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_unsigned,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ABS_LO12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ABS_LO12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "abs_lo12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ABS64_LO20,		/* type (69).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ABS64_LO20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ABS64_LO20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "abs64_lo20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_ABS64_HI12,		/* type (70).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_ABS64_HI12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_ABS64_HI12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "abs64_hi12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_PCALA_HI20,		/* type (71).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_PCALA_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_PCALA_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "pc_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_PCALA_LO12,		/* type (72).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_PCALA_LO12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_PCALA_LO12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "pc_lo12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_PCALA64_LO20,	/* type (73).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_PCALA64_LO20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_PCALA64_LO20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "pc64_lo20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_PCALA64_HI12,	/* type (74).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_PCALA64_HI12",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_PCALA64_HI12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "pc64_hi12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT_PC_HI20,		/* type (75).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT_PC_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT_PC_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got_pc_hi20"),			/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT_PC_LO12,		/* type (76).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT_PC_LO12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT_PC_LO12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got_pc_lo12"),			/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT64_PC_LO20,	/* type (77).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT64_PC_LO20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT64_PC_LO20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got64_pc_lo20"),			/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT64_PC_HI12,	/* type (78).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT64_PC_HI12",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT64_PC_HI12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got64_pc_hi12"),			/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT_HI20,		/* type (79).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT_LO12,		/* type (80).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT_LO12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT_LO12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got_lo12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT64_LO20,		/* type (81).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT64_LO20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT64_LO20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got64_lo20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_GOT64_HI12,		/* type (82).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_GOT64_HI12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_GOT64_HI12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "got64_hi12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_LE_HI20,		/* type (83).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_LE_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_LE_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "le_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_LE_LO12,		/* type (84).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_LE_LO12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_LE_LO12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "le_lo12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_LE64_LO20,	/* type (85).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_LE64_LO20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_LE64_LO20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "le64_lo20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_LE64_HI12,	/* type (86).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_LE64_HI12",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_LE64_HI12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "le64_hi12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE_PC_HI20,	/* type (87).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE_PC_HI20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE_PC_HI20,	/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie_pc_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE_PC_LO12,	/* type (88).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_unsigned,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE_PC_LO12",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE_PC_LO12,	/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie_pc_lo12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_PC_LO20,	/* type (89).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE64_PC_LO20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE64_PC_LO20,	/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie64_pc_lo20"),			/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_PC_HI12,	/* type (90).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE64_PC_HI12",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE64_PC_HI12,	/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie64_pc_hi12"),			/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE_HI20,	/* type (91).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE_LO12,		/* type (92).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE_LO12",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE_LO12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie_lo12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_LO20,	/* type (93).  */
	 32,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE64_LO20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE64_LO20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie64_lo20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_HI12,	/* type (94).  */
	 52,					/* rightshift.  */
	 4,					/* size.  */
	 12,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 10,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_IE64_HI12",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x3ffc00,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_IE64_HI12,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ie64_hi12"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_LD_PC_HI20,	/* type (95).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_LD_PC_HI20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_LD_PC_HI20,	/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ld_pc_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_LD_HI20,		/* type (96).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_LD_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_LD_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "ld_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_GD_PC_HI20,	/* type (97).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_GD_PC_HI20",		/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_GD_PC_HI20,	/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "gd_pc_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_TLS_GD_HI20,		/* type (98).  */
	 12,					/* rightshift.  */
	 4,					/* size.  */
	 20,					/* bitsize.  */
	 false,					/* pc_relative.  */
	 5,					/* bitpos.  */
	 complain_overflow_signed,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_TLS_GD_HI20",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0x1ffffe0,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_TLS_GD_HI20,		/* bfd_reloc_code_real_type */
	 reloc_bits,				/* adjust_reloc_bits */
	 "gd_hi20"),				/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_32_PCREL,		/* type (99).  */
	 0,					/* rightshift.  */
	 4,					/* size.  */
	 32,					/* bitsize.  */
	 true,					/* pc_relative.  */
	 0,					/* bitpos.  */
	 complain_overflow_dont,		/* complain_on_overflow.  */
	 bfd_elf_generic_reloc,			/* special_function.  */
	 "R_LARCH_32_PCREL",			/* name.  */
	 false,					/* partial_inplace.  */
	 0,					/* src_mask */
	 0xffffffff,				/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_32_PCREL,		/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

  LOONGARCH_HOWTO (R_LARCH_RELAX,		/* type (100).  */
	 0,					/* rightshift */
	 1,					/* size */
	 0,					/* bitsize */
	 false,					/* pc_relative */
	 0,					/* bitpos */
	 complain_overflow_dont,		/* complain_on_overflow */
	 bfd_elf_generic_reloc,			/* special_function */
	 "R_LARCH_RELAX",			/* name */
	 false,					/* partial_inplace */
	 0,					/* src_mask */
	 0,					/* dst_mask */
	 false,					/* pcrel_offset */
	 BFD_RELOC_LARCH_RELAX,			/* bfd_reloc_code_real_type */
	 NULL,					/* adjust_reloc_bits */
	 NULL),					/* larch_reloc_type_name */

};

reloc_howto_type *
loongarch_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
{
  if(r_type < R_LARCH_count)
    {
      /* For search table fast.  */
      BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);

      if (loongarch_howto_table[r_type].howto.type == r_type)
	return (reloc_howto_type *)&loongarch_howto_table[r_type];

      for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
	if (loongarch_howto_table[i].howto.type == r_type)
	  return (reloc_howto_type *)&loongarch_howto_table[i];
    }

  (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
			 abfd, r_type);
  bfd_set_error (bfd_error_bad_value);
  return NULL;
}

reloc_howto_type *
loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
{
  BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);

  for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
    if (loongarch_howto_table[i].howto.name
	&& strcasecmp (loongarch_howto_table[i].howto.name, r_name) == 0)
      return (reloc_howto_type *)&loongarch_howto_table[i];

  (*_bfd_error_handler) (_("%pB: unsupported relocation type %s"),
			 abfd, r_name);
  bfd_set_error (bfd_error_bad_value);

  return NULL;
}

/* Cost so much.  */
reloc_howto_type *
loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
			     bfd_reloc_code_real_type code)
{
  BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);

  /* Fast search for new reloc types.  */
  if (BFD_RELOC_LARCH_B16 <= code && code < BFD_RELOC_LARCH_RELAX)
    {
      BFD_ASSERT (BFD_RELOC_LARCH_RELAX - BFD_RELOC_LARCH_B16
		  == R_LARCH_RELAX - R_LARCH_B16);
      loongarch_reloc_howto_type *ht = NULL;
      ht = &loongarch_howto_table[code - BFD_RELOC_LARCH_B16 + R_LARCH_B16];
      BFD_ASSERT (ht->bfd_type == code);
      return (reloc_howto_type *)ht;
    }

  for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
    if (loongarch_howto_table[i].bfd_type == code)
      return (reloc_howto_type *)&loongarch_howto_table[i];

  (*_bfd_error_handler) (_("%pB: unsupported bfd relocation type %#x"),
			 abfd, code);
  bfd_set_error (bfd_error_bad_value);

  return NULL;
}

bfd_reloc_code_real_type
loongarch_larch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
				   const char *l_r_name)
{
  for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
    {
      loongarch_reloc_howto_type *lht = &loongarch_howto_table[i];
      if ((NULL != lht->larch_reloc_type_name)
	  && (0 == strcmp (lht->larch_reloc_type_name, l_r_name)))
	return lht->bfd_type;
    }

  (*_bfd_error_handler) (_("%pB: unsupported relocation type name %s"),
			 abfd, l_r_name);
  bfd_set_error (bfd_error_bad_value);
  return BFD_RELOC_NONE;
}


/* Functions for reloc bits field.
   1.  Signed extend *fix_val.
   2.  Return false if overflow.  */

#define LARCH_RELOC_BFD_VMA_BIT_MASK(bitsize) \
  (~((((bfd_vma)0x1) << (bitsize)) - 1))

/* Adjust val to perform insn
   BFD_RELOC_LARCH_SOP_POP_32_S_10_5
   BFD_RELOC_LARCH_SOP_POP_32_S_10_12
   BFD_RELOC_LARCH_SOP_POP_32_U_10_12
   BFD_RELOC_LARCH_SOP_POP_32_S_10_16
   BFD_RELOC_LARCH_SOP_POP_32_S_5_20
   BFD_RELOC_LARCH_SOP_POP_32_U.  */
static bool
reloc_bits (reloc_howto_type *howto, bfd_vma *fix_val)
{
  bfd_signed_vma val = ((bfd_signed_vma)(*fix_val)) >> howto->rightshift;

  /* Perform insn bits field.  */
  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);
  val <<= howto->bitpos;

  *fix_val = (bfd_vma)val;

  return true;
}

/* Adjust val to perform insn
   R_LARCH_SOP_POP_32_S_10_16_S2
   R_LARCH_B16.  */
static bool
reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *fix_val)
{
  if (howto->complain_on_overflow != complain_overflow_signed)
    return false;

  bfd_signed_vma val = *fix_val;

  /* Judge whether 4 bytes align.  */
  if (val & ((0x1UL << howto->rightshift) - 1))
    return false;

  int bitsize = howto->bitsize + howto->rightshift;
  bfd_signed_vma sig_bit = (val >> (bitsize - 1)) & 0x1;

  /* If val < 0, sign bit is 1.  */
  if (sig_bit)
    {
      /* Signed bits is 1.  */
      if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
	  != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
	return false;
    }
  else
    {
      /* Signed bits is 0.  */
      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
	return false;
    }

  /* Perform insn bits field.  */
  val >>= howto->rightshift;
  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);
  val <<= howto->bitpos;

  *fix_val = val;

  return true;
}

/* Reloc type :
   R_LARCH_SOP_POP_32_S_0_5_10_16_S2
   R_LARCH_B21.  */
static bool
reloc_bits_b21 (reloc_howto_type *howto,
		bfd_vma *fix_val)
{
  if (howto->complain_on_overflow != complain_overflow_signed)
    return false;

  bfd_signed_vma val = *fix_val;

  if (val & ((0x1UL << howto->rightshift) - 1))
    return false;

  int bitsize = howto->bitsize + howto->rightshift;
  bfd_signed_vma sig_bit = (val >> (bitsize - 1)) & 0x1;

  /* If val < 0.  */
  if (sig_bit)
    {
      if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
	  != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
	return false;
    }
  else
    {
      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
	return false;
    }

  /* Perform insn bits field.  */
  val >>= howto->rightshift;
  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);

  /* Perform insn bits field.  15:0<<10, 20:16>>16.  */
  val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f);

  *fix_val = val;

  return true;
}

/* Reloc type:
   R_LARCH_SOP_POP_32_S_0_10_10_16_S2
   R_LARCH_B26.  */
static bool
reloc_bits_b26 (reloc_howto_type *howto,
		bfd_vma *fix_val)
{
  /* Return false if overflow.  */
  if (howto->complain_on_overflow != complain_overflow_signed)
    return false;

  bfd_signed_vma val = *fix_val;

  if (val & ((0x1UL << howto->rightshift) - 1))
    return false;

  int bitsize = howto->bitsize + howto->rightshift;
  bfd_signed_vma sig_bit = (val >> (bitsize - 1)) & 0x1;

  /* If val < 0.  */
  if (sig_bit)
    {
      if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
	  != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
	return false;
    }
  else
    {
      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
	return false;
    }

  /* Perform insn bits field.  */
  val >>= howto->rightshift;
  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);

  /* Perform insn bits field.  25:16>>16, 15:0<<10.  */
  val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff);

  *fix_val = val;

  return true;
}

bool
loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto,
				  bfd_vma *fix_val)
{
  BFD_ASSERT (((loongarch_reloc_howto_type *)howto)->adjust_reloc_bits);
  return ((loongarch_reloc_howto_type *)
	  howto)->adjust_reloc_bits(howto, fix_val);
}
