+ ret = mips_elf64_final_gp (output_bfd, symbol, relocateable, error_message,
+ &gp);
+ if (ret != bfd_reloc_ok)
+ return ret;
+
+ return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
+ input_section, relocateable,
+ data, gp);
+}
+
+/* Do a R_MIPS_GPREL16 RELA relocation. */
+
+bfd_reloc_status_type
+mips_elf64_gprel16_reloca (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ boolean relocateable;
+ bfd_vma gp;
+
+ /* This works only for NewABI. */
+ BFD_ASSERT (reloc_entry->howto->src_mask == 0);
+
+ /* If we're relocating, and this is an external symbol with no
+ addend, we don't want to change anything. We will only have an
+ addend if this is a newly created reloc, not read from an ELF
+ file. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ if (output_bfd != (bfd *) NULL)
+ relocateable = true;
+ else
+ {
+ relocateable = false;
+ output_bfd = symbol->section->output_section->owner;
+ }
+
+ if (prev_reloc_address != reloc_entry->address)
+ prev_reloc_address = reloc_entry->address;
+ else
+ {
+ mips_elf64_final_gp (output_bfd, symbol, relocateable, error_message,
+ &gp);
+ prev_reloc_addend = reloc_entry->addend + reloc_entry->address - gp;
+ if (symbol->flags & BSF_LOCAL)
+ prev_reloc_addend += _bfd_get_gp_value (abfd);
+/*fprintf(stderr, "Addend: %lx, Next Addend: %lx\n", reloc_entry->addend, prev_reloc_addend);*/
+ }
+
+ return bfd_reloc_ok;
+}
+
+/* Do a R_MIPS_LITERAL relocation. */
+
+bfd_reloc_status_type
+mips_elf64_literal_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ /* If we're relocating, and this is an external symbol, we don't
+ want to change anything. */
+ if (output_bfd != (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;
+ }
+
+ /* FIXME: The entries in the .lit8 and .lit4 sections should be merged.
+ Currently we simply call mips_elf64_gprel16_reloc. */
+ return mips_elf64_gprel16_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+}
+
+/* Do a R_MIPS_GPREL32 relocation. Is this 32 bit value the offset
+ from the gp register? XXX */
+
+bfd_reloc_status_type
+mips_elf64_gprel32_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ boolean relocateable;
+ bfd_reloc_status_type ret;
+ bfd_vma gp;
+ bfd_vma relocation;
+ unsigned long val;
+
+ /* If we're relocating, and this is an external symbol with no
+ addend, we don't want to change anything. We will only have an
+ addend if this is a newly created reloc, not read from an ELF
+ file. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ *error_message = (char *)
+ _("32bits gp relative relocation occurs for an external symbol");
+ return bfd_reloc_outofrange;
+ }
+
+ if (output_bfd != (bfd *) NULL)
+ {
+ relocateable = true;
+ gp = _bfd_get_gp_value (output_bfd);
+ }
+ else
+ {
+ relocateable = false;
+ output_bfd = symbol->section->output_section->owner;
+
+ ret = mips_elf64_final_gp (output_bfd, symbol, relocateable,
+ error_message, &gp);
+ if (ret != bfd_reloc_ok)
+ return ret;
+ }
+
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+
+ if (reloc_entry->address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ if (reloc_entry->howto->src_mask == 0)
+ {
+ /* This case arises with the 64-bit MIPS ELF ABI. */
+ val = 0;
+ }
+ else
+ val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+
+ /* Set val to the offset into the section or symbol. */
+ val += reloc_entry->addend;
+
+ /* Adjust val for the final section location and GP value. If we
+ are producing relocateable output, we don't want to do this for
+ an external symbol. */
+ if (! relocateable
+ || (symbol->flags & BSF_SECTION_SYM) != 0)
+ val += relocation - gp;
+
+ bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
+
+ if (relocateable)
+ reloc_entry->address += input_section->output_offset;
+
+ return bfd_reloc_ok;
+}
+
+/* Do a R_MIPS_SHIFT6 relocation. The MSB of the shift is stored at bit 2,
+ the rest is at bits 6-10. The bitpos alredy got right by the howto. */
+
+bfd_reloc_status_type
+mips_elf64_shift6_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ /* If we're relocating, and this is an external symbol, we don't
+ want to change anything. */
+ if (output_bfd != (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;
+ }
+
+ reloc_entry->addend = (reloc_entry->addend & 0x00007c0)
+ | (reloc_entry->addend & 0x00000800) >> 9;
+
+ return bfd_reloc_continue;
+}
+
+/* Given a BFD reloc type, return a howto structure. */
+
+static reloc_howto_type *
+bfd_elf64_bfd_reloc_type_lookup (abfd, code)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ bfd_reloc_code_real_type code;
+{
+ /* FIXME: We default to RELA here instead of choosing the right
+ relocation variant. */
+ reloc_howto_type *howto_table = mips_elf64_howto_table_rela;
+
+ switch (code)
+ {
+ case BFD_RELOC_NONE:
+ return &howto_table[R_MIPS_NONE];
+ case BFD_RELOC_16:
+ return &howto_table[R_MIPS_16];
+ case BFD_RELOC_32:
+ return &howto_table[R_MIPS_32];
+ case BFD_RELOC_64:
+ case BFD_RELOC_CTOR:
+ return &howto_table[R_MIPS_64];
+ case BFD_RELOC_16_PCREL:
+ return &howto_table[R_MIPS_PC16];
+ case BFD_RELOC_HI16_S:
+ return &howto_table[R_MIPS_HI16];
+ case BFD_RELOC_LO16:
+ return &howto_table[R_MIPS_LO16];
+ case BFD_RELOC_GPREL16:
+ return &howto_table[R_MIPS_GPREL16];
+ case BFD_RELOC_GPREL32:
+ return &howto_table[R_MIPS_GPREL32];
+ case BFD_RELOC_MIPS_JMP:
+ return &howto_table[R_MIPS_26];
+ case BFD_RELOC_MIPS_LITERAL:
+ return &howto_table[R_MIPS_LITERAL];
+ case BFD_RELOC_MIPS_GOT16:
+ return &howto_table[R_MIPS_GOT16];
+ case BFD_RELOC_MIPS_CALL16:
+ return &howto_table[R_MIPS_CALL16];
+ case BFD_RELOC_MIPS_SHIFT5:
+ return &howto_table[R_MIPS_SHIFT5];
+ case BFD_RELOC_MIPS_SHIFT6:
+ return &howto_table[R_MIPS_SHIFT6];
+ case BFD_RELOC_MIPS_GOT_DISP:
+ return &howto_table[R_MIPS_GOT_DISP];
+ case BFD_RELOC_MIPS_GOT_PAGE:
+ return &howto_table[R_MIPS_GOT_PAGE];
+ case BFD_RELOC_MIPS_GOT_OFST:
+ return &howto_table[R_MIPS_GOT_OFST];
+ case BFD_RELOC_MIPS_GOT_HI16:
+ return &howto_table[R_MIPS_GOT_HI16];
+ case BFD_RELOC_MIPS_GOT_LO16:
+ return &howto_table[R_MIPS_GOT_LO16];
+ case BFD_RELOC_MIPS_SUB:
+ return &howto_table[R_MIPS_SUB];
+ case BFD_RELOC_MIPS_INSERT_A:
+ return &howto_table[R_MIPS_INSERT_A];
+ case BFD_RELOC_MIPS_INSERT_B:
+ return &howto_table[R_MIPS_INSERT_B];
+ case BFD_RELOC_MIPS_DELETE:
+ return &howto_table[R_MIPS_DELETE];
+ case BFD_RELOC_MIPS_HIGHEST:
+ return &howto_table[R_MIPS_HIGHEST];
+ case BFD_RELOC_MIPS_HIGHER:
+ return &howto_table[R_MIPS_HIGHER];
+ case BFD_RELOC_MIPS_CALL_HI16:
+ return &howto_table[R_MIPS_CALL_HI16];
+ case BFD_RELOC_MIPS_CALL_LO16:
+ return &howto_table[R_MIPS_CALL_LO16];
+ case BFD_RELOC_MIPS_SCN_DISP:
+ return &howto_table[R_MIPS_SCN_DISP];
+ case BFD_RELOC_MIPS_REL16:
+ return &howto_table[R_MIPS_REL16];
+ /* Use of R_MIPS_ADD_IMMEDIATE and R_MIPS_PJUMP is deprecated. */
+ case BFD_RELOC_MIPS_RELGOT:
+ return &howto_table[R_MIPS_RELGOT];
+ case BFD_RELOC_MIPS_JALR:
+ return &howto_table[R_MIPS_JALR];
+/*
+ case BFD_RELOC_MIPS16_JMP:
+ return &elf_mips16_jump_howto;
+ case BFD_RELOC_MIPS16_GPREL:
+ return &elf_mips16_gprel_howto;
+ case BFD_RELOC_VTABLE_INHERIT:
+ return &elf_mips_gnu_vtinherit_howto;
+ case BFD_RELOC_VTABLE_ENTRY:
+ return &elf_mips_gnu_vtentry_howto;
+ case BFD_RELOC_PCREL_HI16_S:
+ return &elf_mips_gnu_rel_hi16;
+ case BFD_RELOC_PCREL_LO16:
+ return &elf_mips_gnu_rel_lo16;
+ case BFD_RELOC_16_PCREL_S2:
+ return &elf_mips_gnu_rel16_s2;
+ case BFD_RELOC_64_PCREL:
+ return &elf_mips_gnu_pcrel64;
+ case BFD_RELOC_32_PCREL:
+ return &elf_mips_gnu_pcrel32;
+*/
+ default:
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+}
+
+/* Given a MIPS Elf64_Internal_Rel, fill in an arelent structure. */
+
+static reloc_howto_type *
+mips_elf64_rtype_to_howto (r_type, rela_p)
+ unsigned int r_type;
+ boolean rela_p;
+{
+ switch (r_type)
+ {
+/*
+ case R_MIPS16_26:
+ return &elf_mips16_jump_howto;
+ break;
+ case R_MIPS16_GPREL:
+ return &elf_mips16_gprel_howto;
+ break;
+ case R_MIPS_GNU_VTINHERIT:
+ return &elf_mips_gnu_vtinherit_howto;
+ break;
+ case R_MIPS_GNU_VTENTRY:
+ return &elf_mips_gnu_vtentry_howto;
+ break;
+ case R_MIPS_GNU_REL_HI16:
+ return &elf_mips_gnu_rel_hi16;
+ break;
+ case R_MIPS_GNU_REL_LO16:
+ return &elf_mips_gnu_rel_lo16;
+ break;
+ case R_MIPS_GNU_REL16_S2:
+ return &elf_mips_gnu_rel16_s2;
+ break;
+ case R_MIPS_PC64:
+ return &elf_mips_gnu_pcrel64;
+ break;
+ case R_MIPS_PC32:
+ return &elf_mips_gnu_pcrel32;
+ break;
+*/
+
+ default:
+ BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
+ if (rela_p)
+ return &mips_elf64_howto_table_rela[r_type];
+ else
+ return &mips_elf64_howto_table_rel[r_type];
+ break;
+ }
+}
+
+/* Prevent relocation handling by bfd for MIPS ELF64. */
+
+static void
+mips_elf64_info_to_howto_rel (abfd, cache_ptr, dst)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *cache_ptr ATTRIBUTE_UNUSED;
+ Elf64_Internal_Rel *dst ATTRIBUTE_UNUSED;
+{
+ BFD_ASSERT (0);
+}
+
+static void
+mips_elf64_info_to_howto_rela (abfd, cache_ptr, dst)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *cache_ptr ATTRIBUTE_UNUSED;
+ Elf64_Internal_Rela *dst ATTRIBUTE_UNUSED;
+{
+ BFD_ASSERT (0);