/* MIPS-specific support for 64-bit ELF Copyright 1996 Free Software Foundation, Inc. Ian Lance Taylor, Cygnus Support 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 2 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; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "libbfd.h" #include "bfdlink.h" #include "genlink.h" #include "elf-bfd.h" #include "elf/mips.h" /* This file supports the 64-bit MIPS ELF ABI. The MIPS 64-bit ELF ABI uses an unusual reloc format. This file overrides the usual ELF reloc handling, and handles reading and writing the relocations here. */ static void mips_elf64_swap_reloc_in PARAMS ((bfd *, const Elf64_Mips_External_Rel *, Elf64_Mips_Internal_Rel *)); static void mips_elf64_swap_reloca_in PARAMS ((bfd *, const Elf64_Mips_External_Rela *, Elf64_Mips_Internal_Rela *)); static void mips_elf64_swap_reloc_out PARAMS ((bfd *, const Elf64_Mips_Internal_Rel *, Elf64_Mips_External_Rel *)); static void mips_elf64_swap_reloca_out PARAMS ((bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rela *)); static reloc_howto_type *mips_elf64_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type)); static boolean mips_elf64_slurp_one_reloc_table PARAMS ((bfd *, asection *, asymbol **, const Elf_Internal_Shdr *)); static boolean mips_elf64_slurp_reloc_table PARAMS ((bfd *, asection *, asymbol **)); static void mips_elf64_write_relocs PARAMS ((bfd *, asection *, PTR)); static boolean mips_elf64_section_from_shdr PARAMS ((bfd *, Elf_Internal_Shdr *, char *)); /* The relocation types. */ enum mips_elf64_reloc_type { R_MIPS_NONE = 0, R_MIPS_16 = 1, R_MIPS_32 = 2, R_MIPS_ADD = 2, R_MIPS_REL32 = 3, R_MIPS_REL = 3, R_MIPS_26 = 4, R_MIPS_HI16 = 5, R_MIPS_LO16 = 6, R_MIPS_GPREL16 = 7, R_MIPS_GPREL = 7, R_MIPS_LITERAL = 8, R_MIPS_GOT16 = 9, R_MIPS_GOT = 9, R_MIPS_PC16 = 10, R_MIPS_CALL16 = 11, R_MIPS_CALL = 11, R_MIPS_GPREL32 = 12, R_MIPS_SHIFT5 = 16, R_MIPS_SHIFT6 = 17, R_MIPS_64 = 18, R_MIPS_GOT_DISP = 19, R_MIPS_GOT_PAGE = 20, R_MIPS_GOT_OFST = 21, R_MIPS_GOT_HI16 = 22, R_MIPS_GOT_LO16 = 23, R_MIPS_SUB = 24, R_MIPS_INSERT_A = 25, R_MIPS_INSERT_B = 26, R_MIPS_DELETE = 27, R_MIPS_HIGHER = 28, R_MIPS_HIGHEST = 29, R_MIPS_CALL_HI16 = 30, R_MIPS_CALL_LO16 = 31, R_MIPS_SCN_DISP = 32, R_MIPS_REL16 = 33, R_MIPS_ADD_IMMEDIATE = 34 }; /* In case we're on a 32-bit machine, construct a 64-bit "-1" value from smaller values. Start with zero, widen, *then* decrement. */ #define MINUS_ONE (((bfd_vma)0) - 1) /* FIXME: These need to be rewritten, or we need to use the versions in elf32-mips.c. */ #define mips_elf_hi16_reloc bfd_elf_generic_reloc #define mips_elf_lo16_reloc bfd_elf_generic_reloc #define mips_elf_gprel16_reloc bfd_elf_generic_reloc #define mips_elf_got16_reloc bfd_elf_generic_reloc #define mips_elf_gprel32_reloc bfd_elf_generic_reloc /* The relocation table used for SHT_REL sections. */ static reloc_howto_type mips_elf64_howto_table_rel[] = { /* No relocation. */ HOWTO (R_MIPS_NONE, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_NONE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* 16 bit relocation. */ HOWTO (R_MIPS_16, /* type */ 0, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 32 bit relocation. */ HOWTO (R_MIPS_32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_32", /* name */ true, /* partial_inplace */ 0xffffffff, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ /* 32 bit symbol relative relocation. */ HOWTO (R_MIPS_REL32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_REL32", /* name */ true, /* partial_inplace */ 0xffffffff, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ /* 26 bit branch address. */ HOWTO (R_MIPS_26, /* type */ 2, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 26, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ /* This needs complex overflow detection, because the upper four bits must match the PC. */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_26", /* name */ true, /* partial_inplace */ 0x3ffffff, /* src_mask */ 0x3ffffff, /* dst_mask */ false), /* pcrel_offset */ /* High 16 bits of symbol value. */ HOWTO (R_MIPS_HI16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ mips_elf_hi16_reloc, /* special_function */ "R_MIPS_HI16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Low 16 bits of symbol value. */ HOWTO (R_MIPS_LO16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ mips_elf_lo16_reloc, /* special_function */ "R_MIPS_LO16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* GP relative reference. */ HOWTO (R_MIPS_GPREL16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_GPREL16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Reference to literal section. */ HOWTO (R_MIPS_LITERAL, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_LITERAL", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Reference to global offset table. */ HOWTO (R_MIPS_GOT16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ mips_elf_got16_reloc, /* special_function */ "R_MIPS_GOT16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 16 bit PC relative reference. */ HOWTO (R_MIPS_PC16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_PC16", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 16 bit call through global offset table. */ /* FIXME: This is not handled correctly. */ HOWTO (R_MIPS_CALL16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_CALL16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 32 bit GP relative reference. */ HOWTO (R_MIPS_GPREL32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ mips_elf_gprel32_reloc, /* special_function */ "R_MIPS_GPREL32", /* name */ true, /* partial_inplace */ 0xffffffff, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ { 13 }, { 14 }, { 15 }, /* A 5 bit shift field. */ HOWTO (R_MIPS_SHIFT5, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 5, /* bitsize */ false, /* pc_relative */ 6, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SHIFT5", /* name */ true, /* partial_inplace */ 0x000007c0, /* src_mask */ 0x000007c0, /* dst_mask */ false), /* pcrel_offset */ /* A 6 bit shift field. */ /* FIXME: This is not handled correctly; a special function is needed to put the most significant bit in the right place. */ HOWTO (R_MIPS_SHIFT6, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 6, /* bitsize */ false, /* pc_relative */ 6, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SHIFT6", /* name */ true, /* partial_inplace */ 0x000007c4, /* src_mask */ 0x000007c4, /* dst_mask */ false), /* pcrel_offset */ /* 64 bit relocation. */ HOWTO (R_MIPS_64, /* type */ 0, /* rightshift */ 4, /* size (0 = byte, 1 = short, 2 = long) */ 64, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_64", /* name */ true, /* partial_inplace */ MINUS_ONE, /* src_mask */ MINUS_ONE, /* dst_mask */ false), /* pcrel_offset */ /* Displacement in the global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_DISP, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_DISP", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Displacement to page pointer in the global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_PAGE, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_PAGE", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Offset from page pointer in the global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_OFST, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_OFST", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* High 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_HI16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_HI16", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Low 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_LO16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_LO16", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* 64 bit substraction. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_SUB, /* type */ 0, /* rightshift */ 4, /* size (0 = byte, 1 = short, 2 = long) */ 64, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SUB", /* name */ true, /* partial_inplace */ MINUS_ONE, /* src_mask */ MINUS_ONE, /* dst_mask */ false), /* pcrel_offset */ /* Insert the addend as an instruction. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_INSERT_A, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_INSERT_A", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* Insert the addend as an instruction, and change all relocations to refer to the old instruction at the address. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_INSERT_B, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_INSERT_B", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* Delete a 32 bit instruction. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_DELETE, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_DELETE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* Get the higher value of a 64 bit addend. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_HIGHER, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_HIGHER", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Get the highest value of a 64 bit addend. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_HIGHEST, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_HIGHEST", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* High 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_CALL_HI16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_CALL_HI16", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Low 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_CALL_LO16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_CALL_LO16", /* name */ true, /* partial_inplace */ 0x0000ffff, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* I'm not sure what the remaining relocs are, but they are defined on Irix 6. */ HOWTO (R_MIPS_SCN_DISP, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SCN_DISP", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ HOWTO (R_MIPS_REL16, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_REL16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ HOWTO (R_MIPS_ADD_IMMEDIATE, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_ADD_IMMEDIATE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false) /* pcrel_offset */ }; /* The relocation table used for SHT_RELA sections. */ static reloc_howto_type mips_elf64_howto_table_rela[] = { /* No relocation. */ HOWTO (R_MIPS_NONE, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_NONE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* 16 bit relocation. */ HOWTO (R_MIPS_16, /* type */ 0, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 32 bit relocation. */ HOWTO (R_MIPS_32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_32", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ /* 32 bit symbol relative relocation. */ HOWTO (R_MIPS_REL32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_REL32", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ /* 26 bit branch address. */ HOWTO (R_MIPS_26, /* type */ 2, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 26, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ /* This needs complex overflow detection, because the upper four bits must match the PC. */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_26", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x3ffffff, /* dst_mask */ false), /* pcrel_offset */ /* High 16 bits of symbol value. */ HOWTO (R_MIPS_HI16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_HI16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Low 16 bits of symbol value. */ HOWTO (R_MIPS_LO16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_LO16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* GP relative reference. */ HOWTO (R_MIPS_GPREL16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_GPREL16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Reference to literal section. */ HOWTO (R_MIPS_LITERAL, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ mips_elf_gprel16_reloc, /* special_function */ "R_MIPS_LITERAL", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Reference to global offset table. */ HOWTO (R_MIPS_GOT16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ mips_elf_got16_reloc, /* special_function */ "R_MIPS_GOT16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 16 bit PC relative reference. */ HOWTO (R_MIPS_PC16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_PC16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 16 bit call through global offset table. */ /* FIXME: This is not handled correctly. */ HOWTO (R_MIPS_CALL16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_CALL16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* 32 bit GP relative reference. */ HOWTO (R_MIPS_GPREL32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ mips_elf_gprel32_reloc, /* special_function */ "R_MIPS_GPREL32", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ { 13 }, { 14 }, { 15 }, /* A 5 bit shift field. */ HOWTO (R_MIPS_SHIFT5, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 5, /* bitsize */ false, /* pc_relative */ 6, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SHIFT5", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x000007c0, /* dst_mask */ false), /* pcrel_offset */ /* A 6 bit shift field. */ /* FIXME: This is not handled correctly; a special function is needed to put the most significant bit in the right place. */ HOWTO (R_MIPS_SHIFT6, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 6, /* bitsize */ false, /* pc_relative */ 6, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SHIFT6", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x000007c4, /* dst_mask */ false), /* pcrel_offset */ /* 64 bit relocation. */ HOWTO (R_MIPS_64, /* type */ 0, /* rightshift */ 4, /* size (0 = byte, 1 = short, 2 = long) */ 64, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_64", /* name */ true, /* partial_inplace */ 0, /* src_mask */ MINUS_ONE, /* dst_mask */ false), /* pcrel_offset */ /* Displacement in the global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_DISP, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_DISP", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Displacement to page pointer in the global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_PAGE, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_PAGE", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Offset from page pointer in the global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_OFST, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_OFST", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* High 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_HI16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_HI16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Low 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_GOT_LO16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_GOT_LO16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* 64 bit substraction. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_SUB, /* type */ 0, /* rightshift */ 4, /* size (0 = byte, 1 = short, 2 = long) */ 64, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SUB", /* name */ true, /* partial_inplace */ 0, /* src_mask */ MINUS_ONE, /* dst_mask */ false), /* pcrel_offset */ /* Insert the addend as an instruction. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_INSERT_A, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_INSERT_A", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* Insert the addend as an instruction, and change all relocations to refer to the old instruction at the address. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_INSERT_B, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_INSERT_B", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* Delete a 32 bit instruction. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_DELETE, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_DELETE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ /* Get the higher value of a 64 bit addend. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_HIGHER, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_HIGHER", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* Get the highest value of a 64 bit addend. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_HIGHEST, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_HIGHEST", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ /* High 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_CALL_HI16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_CALL_HI16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* Low 16 bits of displacement in global offset table. */ /* FIXME: Not handled correctly. */ HOWTO (R_MIPS_CALL_LO16, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_CALL_LO16", /* name */ true, /* partial_inplace */ 0, /* src_mask */ 0x0000ffff, /* dst_mask */ false), /* pcrel_offset */ /* I'm not sure what the remaining relocs are, but they are defined on Irix 6. */ HOWTO (R_MIPS_SCN_DISP, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_SCN_DISP", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ HOWTO (R_MIPS_REL16, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_REL16", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false), /* pcrel_offset */ HOWTO (R_MIPS_ADD_IMMEDIATE, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_ADD_IMMEDIATE", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false) /* pcrel_offset */ }; /* Swap in a MIPS 64-bit Rel reloc. */ static void mips_elf64_swap_reloc_in (abfd, src, dst) bfd *abfd; const Elf64_Mips_External_Rel *src; Elf64_Mips_Internal_Rel *dst; { dst->r_offset = bfd_h_get_64 (abfd, (bfd_byte *) src->r_offset); dst->r_sym = bfd_h_get_32 (abfd, (bfd_byte *) src->r_sym); dst->r_ssym = bfd_h_get_8 (abfd, (bfd_byte *) src->r_ssym); dst->r_type3 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type3); dst->r_type2 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type2); dst->r_type = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type); } /* Swap in a MIPS 64-bit Rela reloc. */ static void mips_elf64_swap_reloca_in (abfd, src, dst) bfd *abfd; const Elf64_Mips_External_Rela *src; Elf64_Mips_Internal_Rela *dst; { dst->r_offset = bfd_h_get_64 (abfd, (bfd_byte *) src->r_offset); dst->r_sym = bfd_h_get_32 (abfd, (bfd_byte *) src->r_sym); dst->r_ssym = bfd_h_get_8 (abfd, (bfd_byte *) src->r_ssym); dst->r_type3 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type3); dst->r_type2 = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type2); dst->r_type = bfd_h_get_8 (abfd, (bfd_byte *) src->r_type); dst->r_addend = bfd_h_get_64 (abfd, (bfd_byte *) src->r_addend); } /* Swap out a MIPS 64-bit Rel reloc. */ static void mips_elf64_swap_reloc_out (abfd, src, dst) bfd *abfd; const Elf64_Mips_Internal_Rel *src; Elf64_Mips_External_Rel *dst; { bfd_h_put_64 (abfd, src->r_offset, (bfd_byte *) dst->r_offset); bfd_h_put_32 (abfd, src->r_sym, (bfd_byte *) dst->r_sym); bfd_h_put_8 (abfd, src->r_ssym, (bfd_byte *) dst->r_ssym); bfd_h_put_8 (abfd, src->r_type3, (bfd_byte *) dst->r_type3); bfd_h_put_8 (abfd, src->r_type2, (bfd_byte *) dst->r_type2); bfd_h_put_8 (abfd, src->r_type, (bfd_byte *) dst->r_type); } /* Swap out a MIPS 64-bit Rela reloc. */ static void mips_elf64_swap_reloca_out (abfd, src, dst) bfd *abfd; const Elf64_Mips_Internal_Rela *src; Elf64_Mips_External_Rela *dst; { bfd_h_put_64 (abfd, src->r_offset, (bfd_byte *) dst->r_offset); bfd_h_put_32 (abfd, src->r_sym, (bfd_byte *) dst->r_sym); bfd_h_put_8 (abfd, src->r_ssym, (bfd_byte *) dst->r_ssym); bfd_h_put_8 (abfd, src->r_type3, (bfd_byte *) dst->r_type3); bfd_h_put_8 (abfd, src->r_type2, (bfd_byte *) dst->r_type2); bfd_h_put_8 (abfd, src->r_type, (bfd_byte *) dst->r_type); bfd_h_put_64 (abfd, src->r_offset, (bfd_byte *) dst->r_offset); } /* A mapping from BFD reloc types to MIPS ELF reloc types. */ struct elf_reloc_map { bfd_reloc_code_real_type bfd_reloc_val; enum mips_elf64_reloc_type elf_reloc_val; }; static CONST struct elf_reloc_map mips_reloc_map[] = { { BFD_RELOC_NONE, R_MIPS_NONE, }, { BFD_RELOC_16, R_MIPS_16 }, { BFD_RELOC_32, R_MIPS_32 }, { BFD_RELOC_64, R_MIPS_64 }, { BFD_RELOC_CTOR, R_MIPS_64 }, { BFD_RELOC_32_PCREL, R_MIPS_REL32 }, { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, { BFD_RELOC_HI16_S, R_MIPS_HI16 }, { BFD_RELOC_LO16, R_MIPS_LO16 }, { BFD_RELOC_MIPS_GPREL, R_MIPS_GPREL16 }, { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, { BFD_RELOC_16_PCREL, R_MIPS_PC16 }, { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, { BFD_RELOC_MIPS_GPREL32, R_MIPS_GPREL32 }, { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 }, { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 }, { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 }, { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 } }; /* Given a BFD reloc type, return a howto structure. */ static reloc_howto_type * mips_elf64_reloc_type_lookup (abfd, code) bfd *abfd; bfd_reloc_code_real_type code; { unsigned int i; for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); i++) { if (mips_reloc_map[i].bfd_reloc_val == code) { int v; v = (int) mips_reloc_map[i].elf_reloc_val; return &mips_elf64_howto_table_rel[v]; } } return NULL; } /* Read the relocations from one reloc section. */ static boolean mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, rel_hdr) bfd *abfd; asection *asect; asymbol **symbols; const Elf_Internal_Shdr *rel_hdr; { PTR allocated = NULL; bfd_byte *native_relocs; arelent *relents; arelent *relent; unsigned int count; unsigned int i; int entsize; reloc_howto_type *howto_table; allocated = (PTR) bfd_malloc (rel_hdr->sh_size); if (allocated == NULL) goto error_return; if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0 || (bfd_read (allocated, 1, rel_hdr->sh_size, abfd) != rel_hdr->sh_size)) goto error_return; native_relocs = (bfd_byte *) allocated; relents = asect->relocation + asect->reloc_count; entsize = rel_hdr->sh_entsize; BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel) || entsize == sizeof (Elf64_Mips_External_Rela)); count = rel_hdr->sh_size / entsize; if (entsize == sizeof (Elf64_Mips_External_Rel)) howto_table = mips_elf64_howto_table_rel; else howto_table = mips_elf64_howto_table_rela; relent = relents; for (i = 0; i < count; i++, native_relocs += entsize) { Elf64_Mips_Internal_Rela rela; boolean used_sym, used_ssym; int ir; if (entsize == sizeof (Elf64_Mips_External_Rela)) mips_elf64_swap_reloca_in (abfd, (Elf64_Mips_External_Rela *) native_relocs, &rela); else { Elf64_Mips_Internal_Rel rel; mips_elf64_swap_reloc_in (abfd, (Elf64_Mips_External_Rel *) native_relocs, &rel); rela.r_offset = rel.r_offset; rela.r_sym = rel.r_sym; rela.r_ssym = rel.r_ssym; rela.r_type3 = rel.r_type3; rela.r_type2 = rel.r_type2; rela.r_type = rel.r_type; rela.r_addend = 0; } /* Each entry represents up to three actual relocations. */ used_sym = false; used_ssym = false; for (ir = 0; ir < 3; ir++) { enum mips_elf64_reloc_type type; switch (ir) { default: abort (); case 0: type = (enum mips_elf64_reloc_type) rela.r_type; break; case 1: type = (enum mips_elf64_reloc_type) rela.r_type2; break; case 2: type = (enum mips_elf64_reloc_type) rela.r_type3; break; } if (type == R_MIPS_NONE) { /* There are no more relocations in this entry. If this is the first entry, we need to generate a dummy relocation so that the generic linker knows that there has been a break in the sequence of relocations applying to a particular address. */ if (ir == 0) { relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) relent->address = rela.r_offset; else relent->address = rela.r_offset - asect->vma; relent->addend = 0; relent->howto = &howto_table[(int) R_MIPS_NONE]; ++relent; } break; } /* Some types require symbols, whereas some do not. */ switch (type) { case R_MIPS_NONE: case R_MIPS_LITERAL: case R_MIPS_INSERT_A: case R_MIPS_INSERT_B: case R_MIPS_DELETE: relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; break; default: if (! used_sym) { if (rela.r_sym == 0) relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; else { asymbol **ps, *s; ps = symbols + rela.r_sym - 1; s = *ps; if ((s->flags & BSF_SECTION_SYM) == 0) relent->sym_ptr_ptr = ps; else relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; } used_sym = true; } else if (! used_ssym) { switch (rela.r_ssym) { case RSS_UNDEF: relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; break; case RSS_GP: case RSS_GP0: case RSS_LOC: /* FIXME: I think these need to be handled using special howto structures. */ BFD_ASSERT (0); break; default: BFD_ASSERT (0); break; } used_ssym = true; } else relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; break; } /* The address of an ELF reloc is section relative for an object file, and absolute for an executable file or shared library. The address of a BFD reloc is always section relative. */ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) relent->address = rela.r_offset; else relent->address = rela.r_offset - asect->vma; relent->addend = rela.r_addend; relent->howto = &howto_table[(int) type]; ++relent; } } asect->reloc_count += relent - relents; if (allocated != NULL) free (allocated); return true; error_return: if (allocated != NULL) free (allocated); return false; } /* Read the relocations. On Irix 6, there can be two reloc sections associated with a single data section. */ static boolean mips_elf64_slurp_reloc_table (abfd, asect, symbols) bfd *abfd; asection *asect; asymbol **symbols; { struct bfd_elf_section_data * const d = elf_section_data (asect); if (asect->relocation != NULL || (asect->flags & SEC_RELOC) == 0 || asect->reloc_count == 0) return true; /* Allocate space for 3 arelent structures for each Rel structure. */ asect->relocation = ((arelent *) bfd_alloc (abfd, asect->reloc_count * 3 * sizeof (arelent))); if (asect->relocation == NULL) return false; /* The slurp_one_reloc_table routine increments reloc_count. */ asect->reloc_count = 0; if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, &d->rel_hdr)) return false; if (d->rel_hdr2 != NULL) { if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, d->rel_hdr2)) return false; } return true; } /* Write out the relocations. */ static void mips_elf64_write_relocs (abfd, sec, data) bfd *abfd; asection *sec; PTR data; { /* FIXME. */ abort (); } /* Handle a 64-bit MIPS ELF specific section. */ static boolean mips_elf64_section_from_shdr (abfd, hdr, name) bfd *abfd; Elf_Internal_Shdr *hdr; char *name; { if (! _bfd_mips_elf_section_from_shdr (abfd, hdr, name)) return false; return true; } /* Relocations in the 64 bit MIPS ELF ABI are more complex than in standard ELF. This structure is used to redirect the relocation handling routines. */ const struct elf_size_info mips_elf64_size_info = { sizeof (Elf64_External_Ehdr), sizeof (Elf64_External_Phdr), sizeof (Elf64_External_Shdr), sizeof (Elf64_Mips_External_Rel), sizeof (Elf64_Mips_External_Rela), sizeof (Elf64_External_Sym), sizeof (Elf64_External_Dyn), sizeof (Elf_External_Note), 64, /* arch_size */ 8, /* file_align */ ELFCLASS64, EV_CURRENT, bfd_elf64_write_out_phdrs, bfd_elf64_write_shdrs_and_ehdr, mips_elf64_write_relocs, bfd_elf64_swap_symbol_out, mips_elf64_slurp_reloc_table, bfd_elf64_slurp_symbol_table, bfd_elf64_swap_dyn_in }; #define TARGET_LITTLE_SYM bfd_elf64_littlemips_vec #define TARGET_LITTLE_NAME "elf64-littlemips" #define TARGET_BIG_SYM bfd_elf64_bigmips_vec #define TARGET_BIG_NAME "elf64-bigmips" #define ELF_ARCH bfd_arch_mips #define ELF_MACHINE_CODE EM_MIPS #define ELF_MAXPAGESIZE 0x1000 #define elf_backend_size_info mips_elf64_size_info #define elf_backend_section_from_shdr mips_elf64_section_from_shdr #define bfd_elf64_bfd_reloc_type_lookup mips_elf64_reloc_type_lookup #include "elf64-target.h"