1012 lines
31 KiB
C
1012 lines
31 KiB
C
/* RISC-V-specific support for ELF.
|
|
Copyright (C) 2011-2018 Free Software Foundation, Inc.
|
|
|
|
Contributed by Andrew Waterman (andrew@sifive.com).
|
|
Based on TILE-Gx and MIPS targets.
|
|
|
|
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/riscv.h"
|
|
#include "opcode/riscv.h"
|
|
#include "libiberty.h"
|
|
#include "elfxx-riscv.h"
|
|
#include <stdint.h>
|
|
|
|
#define MINUS_ONE ((bfd_vma)0 - 1)
|
|
|
|
/* Special handler for ADD/SUB relocations that allows them to be filled out
|
|
both in the pre-linked and post-linked file. This is necessary to make
|
|
pre-linked debug info work, as due to linker relaxations we need to emit
|
|
relocations for the debug info. */
|
|
static bfd_reloc_status_type riscv_elf_add_sub_reloc
|
|
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
|
|
|
|
/* The relocation table used for SHT_RELA sections. */
|
|
|
|
static reloc_howto_type howto_table[] =
|
|
{
|
|
/* No relocation. */
|
|
HOWTO (R_RISCV_NONE, /* type */
|
|
0, /* rightshift */
|
|
3, /* size */
|
|
0, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_NONE", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 32 bit relocation. */
|
|
HOWTO (R_RISCV_32, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_32", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 64 bit relocation. */
|
|
HOWTO (R_RISCV_64, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_64", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Relocation against a local symbol in a shared object. */
|
|
HOWTO (R_RISCV_RELATIVE, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_RELATIVE", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_COPY, /* type */
|
|
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_RISCV_COPY", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_JUMP_SLOT, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_bitfield, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_JUMP_SLOT", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Dynamic TLS relocations. */
|
|
HOWTO (R_RISCV_TLS_DTPMOD32, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_DTPMOD32", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_TLS_DTPMOD64, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_DTPMOD64", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_TLS_DTPREL32, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_DTPREL32", /* name */
|
|
TRUE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_TLS_DTPREL64, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_DTPREL64", /* name */
|
|
TRUE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_TLS_TPREL32, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_TPREL32", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
HOWTO (R_RISCV_TLS_TPREL64, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_TPREL64", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Reserved for future relocs that the dynamic linker must understand. */
|
|
EMPTY_HOWTO (12),
|
|
EMPTY_HOWTO (13),
|
|
EMPTY_HOWTO (14),
|
|
EMPTY_HOWTO (15),
|
|
|
|
/* 12-bit PC-relative branch offset. */
|
|
HOWTO (R_RISCV_BRANCH, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_BRANCH", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_SBTYPE_IMM (-1U), /* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* 20-bit PC-relative jump offset. */
|
|
HOWTO (R_RISCV_JAL, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_JAL", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UJTYPE_IMM (-1U), /* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* 32-bit PC-relative function call (AUIPC/JALR). */
|
|
HOWTO (R_RISCV_CALL, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
64, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_CALL", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
|
|
/* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* Like R_RISCV_CALL, but not locally binding. */
|
|
HOWTO (R_RISCV_CALL_PLT, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
64, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_CALL_PLT", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
|
|
/* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* High 20 bits of 32-bit PC-relative GOT access. */
|
|
HOWTO (R_RISCV_GOT_HI20, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_GOT_HI20", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 20 bits of 32-bit PC-relative TLS IE GOT access. */
|
|
HOWTO (R_RISCV_TLS_GOT_HI20, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_GOT_HI20", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 20 bits of 32-bit PC-relative TLS GD GOT reference. */
|
|
HOWTO (R_RISCV_TLS_GD_HI20, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TLS_GD_HI20", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 20 bits of 32-bit PC-relative reference. */
|
|
HOWTO (R_RISCV_PCREL_HI20, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_PCREL_HI20", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U), /* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* Low 12 bits of a 32-bit PC-relative load or add. */
|
|
HOWTO (R_RISCV_PCREL_LO12_I, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_PCREL_LO12_I", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Low 12 bits of a 32-bit PC-relative store. */
|
|
HOWTO (R_RISCV_PCREL_LO12_S, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_PCREL_LO12_S", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_STYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 20 bits of 32-bit absolute address. */
|
|
HOWTO (R_RISCV_HI20, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_HI20", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 12 bits of 32-bit load or add. */
|
|
HOWTO (R_RISCV_LO12_I, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_LO12_I", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 12 bits of 32-bit store. */
|
|
HOWTO (R_RISCV_LO12_S, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_LO12_S", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_STYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* High 20 bits of TLS LE thread pointer offset. */
|
|
HOWTO (R_RISCV_TPREL_HI20, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TPREL_HI20", /* name */
|
|
TRUE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_UTYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Low 12 bits of TLS LE thread pointer offset for loads and adds. */
|
|
HOWTO (R_RISCV_TPREL_LO12_I, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TPREL_LO12_I", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Low 12 bits of TLS LE thread pointer offset for stores. */
|
|
HOWTO (R_RISCV_TPREL_LO12_S, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TPREL_LO12_S", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_STYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* TLS LE thread pointer usage. May be relaxed. */
|
|
HOWTO (R_RISCV_TPREL_ADD, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TPREL_ADD", /* name */
|
|
TRUE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 8-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_ADD8, /* type */
|
|
0, /* rightshift */
|
|
0, /* size */
|
|
8, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_ADD8", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 16-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_ADD16, /* type */
|
|
0, /* rightshift */
|
|
1, /* size */
|
|
16, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_ADD16", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 32-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_ADD32, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_ADD32", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 64-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_ADD64, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_ADD64", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 8-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_SUB8, /* type */
|
|
0, /* rightshift */
|
|
0, /* size */
|
|
8, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_SUB8", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 16-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_SUB16, /* type */
|
|
0, /* rightshift */
|
|
1, /* size */
|
|
16, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_SUB16", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 32-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_SUB32, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_SUB32", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 64-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_SUB64, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
64, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_SUB64", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* GNU extension to record C++ vtable hierarchy */
|
|
HOWTO (R_RISCV_GNU_VTINHERIT, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
0, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
NULL, /* special_function */
|
|
"R_RISCV_GNU_VTINHERIT", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* GNU extension to record C++ vtable member usage */
|
|
HOWTO (R_RISCV_GNU_VTENTRY, /* type */
|
|
0, /* rightshift */
|
|
4, /* size */
|
|
0, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
_bfd_elf_rel_vtable_reloc_fn, /* special_function */
|
|
"R_RISCV_GNU_VTENTRY", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* Indicates an alignment statement. The addend field encodes how many
|
|
bytes of NOPs follow the statement. The desired alignment is the
|
|
addend rounded up to the next power of two. */
|
|
HOWTO (R_RISCV_ALIGN, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
0, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_ALIGN", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* 8-bit PC-relative branch offset. */
|
|
HOWTO (R_RISCV_RVC_BRANCH, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_RVC_BRANCH", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_RVC_B_IMM (-1U), /* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* 11-bit PC-relative jump offset. */
|
|
HOWTO (R_RISCV_RVC_JUMP, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_RVC_JUMP", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_RVC_J_IMM (-1U), /* dst_mask */
|
|
TRUE), /* pcrel_offset */
|
|
|
|
/* High 6 bits of 18-bit absolute address. */
|
|
HOWTO (R_RISCV_RVC_LUI, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_RVC_LUI", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_RVC_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* GP-relative load. */
|
|
HOWTO (R_RISCV_GPREL_I, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_GPREL_I", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* GP-relative store. */
|
|
HOWTO (R_RISCV_GPREL_S, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_GPREL_S", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_STYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* TP-relative TLS LE load. */
|
|
HOWTO (R_RISCV_TPREL_I, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TPREL_I", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* TP-relative TLS LE store. */
|
|
HOWTO (R_RISCV_TPREL_S, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_signed, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_TPREL_S", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
ENCODE_STYPE_IMM (-1U), /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* The paired relocation may be relaxed. */
|
|
HOWTO (R_RISCV_RELAX, /* type */
|
|
0, /* rightshift */
|
|
3, /* size */
|
|
0, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_RELAX", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 6-bit in-place addition, for local label subtraction. */
|
|
HOWTO (R_RISCV_SUB6, /* type */
|
|
0, /* rightshift */
|
|
0, /* size */
|
|
8, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
riscv_elf_add_sub_reloc, /* special_function */
|
|
"R_RISCV_SUB6", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0x3f, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 6-bit in-place setting, for local label subtraction. */
|
|
HOWTO (R_RISCV_SET6, /* type */
|
|
0, /* rightshift */
|
|
0, /* size */
|
|
8, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_SET6", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
0x3f, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 8-bit in-place setting, for local label subtraction. */
|
|
HOWTO (R_RISCV_SET8, /* type */
|
|
0, /* rightshift */
|
|
0, /* size */
|
|
8, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_SET8", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 16-bit in-place setting, for local label subtraction. */
|
|
HOWTO (R_RISCV_SET16, /* type */
|
|
0, /* rightshift */
|
|
1, /* size */
|
|
16, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_SET16", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 32-bit in-place setting, for local label subtraction. */
|
|
HOWTO (R_RISCV_SET32, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
FALSE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_SET32", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
|
|
/* 32-bit PC relative. */
|
|
HOWTO (R_RISCV_32_PCREL, /* type */
|
|
0, /* rightshift */
|
|
2, /* size */
|
|
32, /* bitsize */
|
|
TRUE, /* pc_relative */
|
|
0, /* bitpos */
|
|
complain_overflow_dont, /* complain_on_overflow */
|
|
bfd_elf_generic_reloc, /* special_function */
|
|
"R_RISCV_32_PCREL", /* name */
|
|
FALSE, /* partial_inplace */
|
|
0, /* src_mask */
|
|
MINUS_ONE, /* dst_mask */
|
|
FALSE), /* pcrel_offset */
|
|
};
|
|
|
|
/* A mapping from BFD reloc types to RISC-V ELF reloc types. */
|
|
|
|
struct elf_reloc_map
|
|
{
|
|
bfd_reloc_code_real_type bfd_val;
|
|
enum elf_riscv_reloc_type elf_val;
|
|
};
|
|
|
|
static const struct elf_reloc_map riscv_reloc_map[] =
|
|
{
|
|
{ BFD_RELOC_NONE, R_RISCV_NONE },
|
|
{ BFD_RELOC_32, R_RISCV_32 },
|
|
{ BFD_RELOC_64, R_RISCV_64 },
|
|
{ BFD_RELOC_RISCV_ADD8, R_RISCV_ADD8 },
|
|
{ BFD_RELOC_RISCV_ADD16, R_RISCV_ADD16 },
|
|
{ BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 },
|
|
{ BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 },
|
|
{ BFD_RELOC_RISCV_SUB8, R_RISCV_SUB8 },
|
|
{ BFD_RELOC_RISCV_SUB16, R_RISCV_SUB16 },
|
|
{ BFD_RELOC_RISCV_SUB32, R_RISCV_SUB32 },
|
|
{ BFD_RELOC_RISCV_SUB64, R_RISCV_SUB64 },
|
|
{ BFD_RELOC_CTOR, R_RISCV_64 },
|
|
{ BFD_RELOC_12_PCREL, R_RISCV_BRANCH },
|
|
{ BFD_RELOC_RISCV_HI20, R_RISCV_HI20 },
|
|
{ BFD_RELOC_RISCV_LO12_I, R_RISCV_LO12_I },
|
|
{ BFD_RELOC_RISCV_LO12_S, R_RISCV_LO12_S },
|
|
{ BFD_RELOC_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_I },
|
|
{ BFD_RELOC_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_S },
|
|
{ BFD_RELOC_RISCV_CALL, R_RISCV_CALL },
|
|
{ BFD_RELOC_RISCV_CALL_PLT, R_RISCV_CALL_PLT },
|
|
{ BFD_RELOC_RISCV_PCREL_HI20, R_RISCV_PCREL_HI20 },
|
|
{ BFD_RELOC_RISCV_JMP, R_RISCV_JAL },
|
|
{ BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 },
|
|
{ BFD_RELOC_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
|
|
{ BFD_RELOC_RISCV_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
|
|
{ BFD_RELOC_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
|
|
{ BFD_RELOC_RISCV_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
|
|
{ BFD_RELOC_RISCV_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
|
|
{ BFD_RELOC_RISCV_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
|
|
{ BFD_RELOC_RISCV_TPREL_HI20, R_RISCV_TPREL_HI20 },
|
|
{ BFD_RELOC_RISCV_TPREL_ADD, R_RISCV_TPREL_ADD },
|
|
{ BFD_RELOC_RISCV_TPREL_LO12_S, R_RISCV_TPREL_LO12_S },
|
|
{ BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
|
|
{ BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
|
|
{ BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
|
|
{ BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
|
|
{ BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
|
|
{ BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
|
|
{ BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI },
|
|
{ BFD_RELOC_RISCV_GPREL_I, R_RISCV_GPREL_I },
|
|
{ BFD_RELOC_RISCV_GPREL_S, R_RISCV_GPREL_S },
|
|
{ BFD_RELOC_RISCV_TPREL_I, R_RISCV_TPREL_I },
|
|
{ BFD_RELOC_RISCV_TPREL_S, R_RISCV_TPREL_S },
|
|
{ BFD_RELOC_RISCV_RELAX, R_RISCV_RELAX },
|
|
{ BFD_RELOC_RISCV_SUB6, R_RISCV_SUB6 },
|
|
{ BFD_RELOC_RISCV_SET6, R_RISCV_SET6 },
|
|
{ BFD_RELOC_RISCV_SET8, R_RISCV_SET8 },
|
|
{ BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
|
|
{ BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
|
|
{ BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
|
|
};
|
|
|
|
/* Given a BFD reloc type, return a howto structure. */
|
|
|
|
reloc_howto_type *
|
|
riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
|
|
bfd_reloc_code_real_type code)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++)
|
|
if (riscv_reloc_map[i].bfd_val == code)
|
|
return &howto_table[(int) riscv_reloc_map[i].elf_val];
|
|
|
|
bfd_set_error (bfd_error_bad_value);
|
|
return NULL;
|
|
}
|
|
|
|
reloc_howto_type *
|
|
riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE (howto_table); i++)
|
|
if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0)
|
|
return &howto_table[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
reloc_howto_type *
|
|
riscv_elf_rtype_to_howto (unsigned int r_type)
|
|
{
|
|
if (r_type >= ARRAY_SIZE (howto_table))
|
|
{
|
|
(*_bfd_error_handler) (_("unrecognized relocation (0x%x)"), r_type);
|
|
bfd_set_error (bfd_error_bad_value);
|
|
return NULL;
|
|
}
|
|
return &howto_table[r_type];
|
|
}
|
|
|
|
/* Special_function of RISCV_ADD and RISCV_SUB relocations. */
|
|
|
|
static bfd_reloc_status_type
|
|
riscv_elf_add_sub_reloc (bfd *abfd,
|
|
arelent *reloc_entry,
|
|
asymbol *symbol,
|
|
void *data,
|
|
asection *input_section,
|
|
bfd *output_bfd,
|
|
char **error_message ATTRIBUTE_UNUSED)
|
|
{
|
|
reloc_howto_type *howto = reloc_entry->howto;
|
|
bfd_vma relocation;
|
|
|
|
if (output_bfd != NULL
|
|
&& (symbol->flags & BSF_SECTION_SYM) == 0
|
|
&& (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0))
|
|
{
|
|
reloc_entry->address += input_section->output_offset;
|
|
return bfd_reloc_ok;
|
|
}
|
|
|
|
if (output_bfd != NULL)
|
|
return bfd_reloc_continue;
|
|
|
|
relocation = symbol->value + symbol->section->output_section->vma
|
|
+ symbol->section->output_offset + reloc_entry->addend;
|
|
bfd_vma old_value = bfd_get (howto->bitsize, abfd,
|
|
data + reloc_entry->address);
|
|
|
|
switch (howto->type)
|
|
{
|
|
case R_RISCV_ADD8:
|
|
case R_RISCV_ADD16:
|
|
case R_RISCV_ADD32:
|
|
case R_RISCV_ADD64:
|
|
relocation = old_value + relocation;
|
|
break;
|
|
case R_RISCV_SUB6:
|
|
case R_RISCV_SUB8:
|
|
case R_RISCV_SUB16:
|
|
case R_RISCV_SUB32:
|
|
case R_RISCV_SUB64:
|
|
relocation = old_value - relocation;
|
|
break;
|
|
}
|
|
bfd_put (howto->bitsize, abfd, relocation, data + reloc_entry->address);
|
|
|
|
return bfd_reloc_ok;
|
|
}
|