-static void
-mips_elf64_swap_reloc_out (abfd, src, dst)
- bfd *abfd;
- const Elf64_Mips_Internal_Rel *src;
- Elf64_Mips_External_Rel *dst;
-{
- H_PUT_64 (abfd, src->r_offset, dst->r_offset);
- H_PUT_32 (abfd, src->r_sym, dst->r_sym);
- H_PUT_8 (abfd, src->r_ssym, dst->r_ssym);
- H_PUT_8 (abfd, src->r_type3, dst->r_type3);
- H_PUT_8 (abfd, src->r_type2, dst->r_type2);
- H_PUT_8 (abfd, src->r_type, 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;
-{
- H_PUT_64 (abfd, src->r_offset, dst->r_offset);
- H_PUT_32 (abfd, src->r_sym, dst->r_sym);
- H_PUT_8 (abfd, src->r_ssym, dst->r_ssym);
- H_PUT_8 (abfd, src->r_type3, dst->r_type3);
- H_PUT_8 (abfd, src->r_type2, dst->r_type2);
- H_PUT_8 (abfd, src->r_type, dst->r_type);
- H_PUT_S64 (abfd, src->r_addend, dst->r_addend);
-}
-
-/* Swap in a MIPS 64-bit Rel reloc. */
-
-static void
-mips_elf64_be_swap_reloc_in (abfd, src, dst)
- bfd *abfd;
- const bfd_byte *src;
- Elf_Internal_Rel *dst;
-{
- Elf64_Mips_Internal_Rel mirel;
-
- mips_elf64_swap_reloc_in (abfd,
- (const Elf64_Mips_External_Rel *) src,
- &mirel);
-
- dst[0].r_offset = mirel.r_offset;
- dst[0].r_info = ELF64_R_INFO (mirel.r_sym, mirel.r_type);
- dst[1].r_offset = mirel.r_offset;
- dst[1].r_info = ELF64_R_INFO (mirel.r_ssym, mirel.r_type2);
- dst[2].r_offset = mirel.r_offset;
- dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirel.r_type3);
-}
-
-/* Swap in a MIPS 64-bit Rela reloc. */
-
-static void
-mips_elf64_be_swap_reloca_in (abfd, src, dst)
- bfd *abfd;
- const bfd_byte *src;
- Elf_Internal_Rela *dst;
-{
- Elf64_Mips_Internal_Rela mirela;
-
- mips_elf64_swap_reloca_in (abfd,
- (const Elf64_Mips_External_Rela *) src,
- &mirela);
-
- dst[0].r_offset = mirela.r_offset;
- dst[0].r_info = ELF64_R_INFO (mirela.r_sym, mirela.r_type);
- dst[0].r_addend = mirela.r_addend;
- dst[1].r_offset = mirela.r_offset;
- dst[1].r_info = ELF64_R_INFO (mirela.r_ssym, mirela.r_type2);
- dst[1].r_addend = 0;
- dst[2].r_offset = mirela.r_offset;
- dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirela.r_type3);
- dst[2].r_addend = 0;
-}
-
-/* Swap out a MIPS 64-bit Rel reloc. */
-
-static void
-mips_elf64_be_swap_reloc_out (abfd, src, dst)
- bfd *abfd;
- const Elf_Internal_Rel *src;
- bfd_byte *dst;
-{
- Elf64_Mips_Internal_Rel mirel;
-
- mirel.r_offset = src[0].r_offset;
- BFD_ASSERT(src[0].r_offset == src[1].r_offset);
- BFD_ASSERT(src[0].r_offset == src[2].r_offset);
-
- mirel.r_type = ELF64_MIPS_R_TYPE (src[0].r_info);
- mirel.r_sym = ELF64_R_SYM (src[0].r_info);
- mirel.r_type2 = ELF64_MIPS_R_TYPE2 (src[1].r_info);
- mirel.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info);
- mirel.r_type3 = ELF64_MIPS_R_TYPE3 (src[2].r_info);
-
- mips_elf64_swap_reloc_out (abfd, &mirel,
- (Elf64_Mips_External_Rel *) dst);
-}
-
-/* Swap out a MIPS 64-bit Rela reloc. */
-
-static void
-mips_elf64_be_swap_reloca_out (abfd, src, dst)
- bfd *abfd;
- const Elf_Internal_Rela *src;
- bfd_byte *dst;
-{
- Elf64_Mips_Internal_Rela mirela;
-
- mirela.r_offset = src[0].r_offset;
- BFD_ASSERT(src[0].r_offset == src[1].r_offset);
- BFD_ASSERT(src[0].r_offset == src[2].r_offset);
-
- mirela.r_type = ELF64_MIPS_R_TYPE (src[0].r_info);
- mirela.r_sym = ELF64_R_SYM (src[0].r_info);
- mirela.r_addend = src[0].r_addend;
- BFD_ASSERT(src[1].r_addend == 0);
- BFD_ASSERT(src[2].r_addend == 0);
-
- mirela.r_type2 = ELF64_MIPS_R_TYPE2 (src[1].r_info);
- mirela.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info);
- mirela.r_type3 = ELF64_MIPS_R_TYPE3 (src[2].r_info);
-
- mips_elf64_swap_reloca_out (abfd, &mirela,
- (Elf64_Mips_External_Rela *) dst);
-}
-
-/* Calculate the %high function. */
-
-static bfd_vma
-mips_elf64_high (value)
- bfd_vma value;
-{
- return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff;
-}
-
-/* Calculate the %higher function. */
-
-static bfd_vma
-mips_elf64_higher (value)
- bfd_vma value;
-{
- return ((value + (bfd_vma) 0x80008000) >> 32) & 0xffff;
-}
-
-/* Calculate the %highest function. */
-
-static bfd_vma
-mips_elf64_highest (value)
- bfd_vma value;
-{
- return ((value + (bfd_vma) 0x800080008000) >> 48) & 0xffff;
-}
-
-/* Do a R_MIPS_HI16 relocation. */
-
-bfd_reloc_status_type
-mips_elf64_hi16_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;
- }
-
- if (((reloc_entry->addend & 0xffff) + 0x8000) & ~0xffff)
- reloc_entry->addend += 0x8000;
-
- return bfd_reloc_continue;
-}
-
-/* Do a R_MIPS_HIGHER relocation. */
-
-bfd_reloc_status_type
-mips_elf64_higher_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;
- }
-
- if (((reloc_entry->addend & 0xffffffff) + 0x80008000)
- & ~0xffffffff)
- reloc_entry->addend += 0x80008000;
-
- return bfd_reloc_continue;
-}
-
-/* Do a R_MIPS_HIGHEST relocation. */
-
-bfd_reloc_status_type
-mips_elf64_highest_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;
- }
-
- if (((reloc_entry->addend & 0xffffffffffff) + 0x800080008000)
- & ~0xffffffffffff)
- reloc_entry->addend += 0x800080008000;
-
- return bfd_reloc_continue;
-}
-
-/* Do a R_MIPS_GOT16 reloc. This is a reloc against the global offset
- table used for PIC code. If the symbol is an external symbol, the
- instruction is modified to contain the offset of the appropriate
- entry in the global offset table. If the symbol is a section
- symbol, the next reloc is a R_MIPS_LO16 reloc. The two 16 bit
- addends are combined to form the real addend against the section
- symbol; the GOT16 is modified to contain the offset of an entry in
- the global offset table, and the LO16 is modified to offset it
- appropriately. Thus an offset larger than 16 bits requires a
- modified value in the global offset table.
-
- This implementation suffices for the assembler, but the linker does
- not yet know how to create global offset tables. */
-
-bfd_reloc_status_type
-mips_elf64_got16_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 an external symbol, we don't want
- to change anything. */
- 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 we're relocating, and this is a local symbol, we can handle it
- just like HI16. */
- if (output_bfd != (bfd *) NULL
- && (symbol->flags & BSF_SECTION_SYM) != 0)
- return mips_elf64_hi16_reloc (abfd, reloc_entry, symbol, data,
- input_section, output_bfd, error_message);
-
- abort ();
-}
-
-/* Set the GP value for OUTPUT_BFD. Returns false if this is a
- dangerous relocation. */
-
-static boolean
-mips_elf64_assign_gp (output_bfd, pgp)
- bfd *output_bfd;
- bfd_vma *pgp;
-{
- unsigned int count;
- asymbol **sym;
- unsigned int i;
-
- /* If we've already figured out what GP will be, just return it. */
- *pgp = _bfd_get_gp_value (output_bfd);
- if (*pgp)
- return true;
-
- count = bfd_get_symcount (output_bfd);
- sym = bfd_get_outsymbols (output_bfd);
-
- /* The linker script will have created a symbol named `_gp' with the
- appropriate value. */
- if (sym == (asymbol **) NULL)
- i = count;
- else
- {
- for (i = 0; i < count; i++, sym++)
- {
- register CONST char *name;
-
- name = bfd_asymbol_name (*sym);
- if (*name == '_' && strcmp (name, "_gp") == 0)
- {
- *pgp = bfd_asymbol_value (*sym);
- _bfd_set_gp_value (output_bfd, *pgp);
- break;
- }
- }
- }
-
- if (i >= count)
- {
- /* Only get the error once. */
- *pgp = 4;
- _bfd_set_gp_value (output_bfd, *pgp);
- return false;
- }
-
- return true;
-}
-
-/* We have to figure out the gp value, so that we can adjust the
- symbol value correctly. We look up the symbol _gp in the output
- BFD. If we can't find it, we're stuck. We cache it in the ELF
- target data. We don't need to adjust the symbol value for an
- external symbol if we are producing relocateable output. */
-
-static bfd_reloc_status_type
-mips_elf64_final_gp (output_bfd, symbol, relocateable, error_message, pgp)
- bfd *output_bfd;
- asymbol *symbol;
- boolean relocateable;
- char **error_message;
- bfd_vma *pgp;
-{
- if (bfd_is_und_section (symbol->section)
- && ! relocateable)
- {
- *pgp = 0;
- return bfd_reloc_undefined;
- }
-
- *pgp = _bfd_get_gp_value (output_bfd);
- if (*pgp == 0
- && (! relocateable
- || (symbol->flags & BSF_SECTION_SYM) != 0))
- {
- if (relocateable)
- {
- /* Make up a value. */
- *pgp = symbol->section->output_section->vma + 0x4000;
- _bfd_set_gp_value (output_bfd, *pgp);
- }
- else if (!mips_elf64_assign_gp (output_bfd, pgp))
- {
- *error_message =
- (char *) _("GP relative relocation when _gp not defined");
- return bfd_reloc_dangerous;
- }
- }
-
- return bfd_reloc_ok;
-}
-
-/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must
- become the offset from the gp register. */
-
-bfd_reloc_status_type
-mips_elf64_gprel16_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;
-
- /* 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;
- }
-
- ret = mips_elf64_final_gp (output_bfd, symbol, relocateable, error_message,
- &gp);
- if (ret != bfd_reloc_ok)
- return ret;
-
- return gprel16_with_gp (abfd, symbol, reloc_entry, input_section,
- relocateable, data, gp);
-}
-
-static bfd_reloc_status_type
-gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
- gp)
- bfd *abfd;
- asymbol *symbol;
- arelent *reloc_entry;
- asection *input_section;
- boolean relocateable;
- PTR data;
- bfd_vma gp;
-{
- bfd_vma relocation;
- unsigned long insn;
- unsigned long val;
-
- 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;
-
- insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
-
- /* Set val to the offset into the section or symbol. */
- if (reloc_entry->howto->src_mask == 0)
- {
- /* This case occurs with the 64-bit MIPS ELF ABI. */
- val = reloc_entry->addend;
- }
- else
- {
- val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
- if (val & 0x8000)
- val -= 0x10000;
- }
-
- /* 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;
-
- insn = (insn & ~0xffff) | (val & 0xffff);
- bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
-
- if (relocateable)
- reloc_entry->address += input_section->output_offset;
-
- else if ((long) val >= 0x8000 || (long) val < -0x8000)
- return bfd_reloc_overflow;
-
- return bfd_reloc_ok;
-}
-
-/* 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;
-}
-
-static int
-mips_elf64_additional_program_headers (abfd)
- bfd *abfd;
-{
- int ret = 0;
-
- /* See if we need a PT_MIPS_OPTIONS segment. */
- if (bfd_get_section_by_name (abfd, ".MIPS.options"))
- ++ret;
-
- return ret;
-}
-
-/* Given a BFD reloc type, return a howto structure. */
-
-static reloc_howto_type *
-mips_elf64_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:
- /* We need to handle these specially. Select the right
- relocation (R_MIPS_32 or R_MIPS_64) based on the
- size of addresses on this architecture. */
- if (bfd_arch_bits_per_address (abfd) == 32)
- return &howto_table[R_MIPS_32];
- else
- 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;
- }
-}
-
-/* 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);
-}
-
-/* Since each entry in an SHT_REL or SHT_RELA section can represent up
- to three relocs, we must tell the user to allocate more space. */
-
-static long
-mips_elf64_get_reloc_upper_bound (abfd, sec)
- bfd *abfd ATTRIBUTE_UNUSED;
- asection *sec;
-{
- return (sec->reloc_count * 3 + 1) * sizeof (arelent *);
-}
-
-/* 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;
- bfd_vma count;
- bfd_vma i;
- int entsize;
- reloc_howto_type *howto_table;
-
- allocated = (PTR) bfd_malloc (rel_hdr->sh_size);
- if (allocated == NULL)
- return false;
-
- if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
- || (bfd_bread (allocated, 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 elf_mips_reloc_type type;
-
- switch (ir)
- {
- default:
- abort ();
- case 0:
- type = (enum elf_mips_reloc_type) rela.r_type;
- break;
- case 1:
- type = (enum elf_mips_reloc_type) rela.r_type2;
- break;
- case 2:
- type = (enum elf_mips_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, dynamic)
- bfd *abfd;
- asection *asect;
- asymbol **symbols;
- boolean dynamic;
-{
- bfd_size_type amt;
- struct bfd_elf_section_data * const d = elf_section_data (asect);
-
- if (dynamic)
- {
- bfd_set_error (bfd_error_invalid_operation);
- return false;
- }
-
- 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. */
- amt = asect->reloc_count;
- amt *= 3 * sizeof (arelent);
- asect->relocation = (arelent *) bfd_alloc (abfd, amt);
- 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;
-{
- boolean *failedp = (boolean *) data;
- int count;
- Elf_Internal_Shdr *rel_hdr;
- unsigned int idx;
-
- /* If we have already failed, don't do anything. */
- if (*failedp)
- return;
-
- if ((sec->flags & SEC_RELOC) == 0)
- return;
-
- /* The linker backend writes the relocs out itself, and sets the
- reloc_count field to zero to inhibit writing them here. Also,
- sometimes the SEC_RELOC flag gets set even when there aren't any
- relocs. */
- if (sec->reloc_count == 0)
- return;
-
- /* We can combine up to three relocs that refer to the same address
- if the latter relocs have no associated symbol. */
- count = 0;
- for (idx = 0; idx < sec->reloc_count; idx++)
- {
- bfd_vma addr;
- unsigned int i;
-
- ++count;
-
- addr = sec->orelocation[idx]->address;
- for (i = 0; i < 2; i++)
- {
- arelent *r;
-
- if (idx + 1 >= sec->reloc_count)
- break;
- r = sec->orelocation[idx + 1];
- if (r->address != addr
- || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
- || (*r->sym_ptr_ptr)->value != 0)
- break;
-
- /* We can merge the reloc at IDX + 1 with the reloc at IDX. */
-
- ++idx;
- }
- }
-
- rel_hdr = &elf_section_data (sec)->rel_hdr;
-
- /* Do the actual relocation. */
-
- if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rel))
- mips_elf64_write_rel (abfd, sec, rel_hdr, &count, data);
- else if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rela))
- mips_elf64_write_rela (abfd, sec, rel_hdr, &count, data);
- else
- BFD_ASSERT (0);
-}
-
-static void
-mips_elf64_write_rel (abfd, sec, rel_hdr, count, data)
- bfd *abfd;
- asection *sec;
- Elf_Internal_Shdr *rel_hdr;
- int *count;
- PTR data;
-{
- boolean *failedp = (boolean *) data;
- Elf64_Mips_External_Rel *ext_rel;
- unsigned int idx;
- asymbol *last_sym = 0;
- int last_sym_idx = 0;
-
- rel_hdr->sh_size = (bfd_vma)(rel_hdr->sh_entsize * *count);
- rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
- if (rel_hdr->contents == NULL)
- {
- *failedp = true;
- return;
- }
-
- ext_rel = (Elf64_Mips_External_Rel *) rel_hdr->contents;
- for (idx = 0; idx < sec->reloc_count; idx++, ext_rel++)
- {
- arelent *ptr;
- Elf64_Mips_Internal_Rel int_rel;
- asymbol *sym;
- int n;
- unsigned int i;
-
- ptr = sec->orelocation[idx];
-
- /* 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)
- int_rel.r_offset = ptr->address;
- else
- int_rel.r_offset = ptr->address + sec->vma;
-
- sym = *ptr->sym_ptr_ptr;
- if (sym == last_sym)
- n = last_sym_idx;
- else
- {
- last_sym = sym;
- n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
- if (n < 0)
- {
- *failedp = true;
- return;
- }
- last_sym_idx = n;
- }
-
- int_rel.r_sym = n;
- int_rel.r_ssym = RSS_UNDEF;
-
- if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
- && ! _bfd_elf_validate_reloc (abfd, ptr))
- {
- *failedp = true;
- return;
- }
-
- int_rel.r_type = ptr->howto->type;
- int_rel.r_type2 = (int) R_MIPS_NONE;
- int_rel.r_type3 = (int) R_MIPS_NONE;
-
- for (i = 0; i < 2; i++)
- {
- arelent *r;
-
- if (idx + 1 >= sec->reloc_count)
- break;
- r = sec->orelocation[idx + 1];
- if (r->address != ptr->address
- || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
- || (*r->sym_ptr_ptr)->value != 0)
- break;
-
- /* We can merge the reloc at IDX + 1 with the reloc at IDX. */
-
- if (i == 0)
- int_rel.r_type2 = r->howto->type;
- else
- int_rel.r_type3 = r->howto->type;
-
- ++idx;
- }
-
- mips_elf64_swap_reloc_out (abfd, &int_rel, ext_rel);
- }
-
- BFD_ASSERT (ext_rel - (Elf64_Mips_External_Rel *) rel_hdr->contents
- == *count);
-}
-
-static void
-mips_elf64_write_rela (abfd, sec, rela_hdr, count, data)
- bfd *abfd;
- asection *sec;
- Elf_Internal_Shdr *rela_hdr;
- int *count;
- PTR data;
-{
- boolean *failedp = (boolean *) data;
- Elf64_Mips_External_Rela *ext_rela;
- unsigned int idx;
- asymbol *last_sym = 0;
- int last_sym_idx = 0;
-
- rela_hdr->sh_size = (bfd_vma)(rela_hdr->sh_entsize * *count);
- rela_hdr->contents = (PTR) bfd_alloc (abfd, rela_hdr->sh_size);
- if (rela_hdr->contents == NULL)
- {
- *failedp = true;
- return;
- }
-
- ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents;
- for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++)
- {
- arelent *ptr;
- Elf64_Mips_Internal_Rela int_rela;
- asymbol *sym;
- int n;
- unsigned int i;
-
- ptr = sec->orelocation[idx];
-
- /* 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)
- int_rela.r_offset = ptr->address;
- else
- int_rela.r_offset = ptr->address + sec->vma;
-
- sym = *ptr->sym_ptr_ptr;
- if (sym == last_sym)
- n = last_sym_idx;
- else
- {
- last_sym = sym;
- n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
- if (n < 0)
- {
- *failedp = true;
- return;
- }
- last_sym_idx = n;
- }
-
- int_rela.r_sym = n;
- int_rela.r_addend = ptr->addend;
- int_rela.r_ssym = RSS_UNDEF;
-
- if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
- && ! _bfd_elf_validate_reloc (abfd, ptr))
- {
- *failedp = true;
- return;
- }
-
- int_rela.r_type = ptr->howto->type;
- int_rela.r_type2 = (int) R_MIPS_NONE;
- int_rela.r_type3 = (int) R_MIPS_NONE;
-
- for (i = 0; i < 2; i++)
- {
- arelent *r;
-
- if (idx + 1 >= sec->reloc_count)
- break;
- r = sec->orelocation[idx + 1];
- if (r->address != ptr->address
- || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
- || (*r->sym_ptr_ptr)->value != 0)
- break;
-
- /* We can merge the reloc at IDX + 1 with the reloc at IDX. */
-
- if (i == 0)
- int_rela.r_type2 = r->howto->type;
- else
- int_rela.r_type3 = r->howto->type;
-
- ++idx;
- }
-
- mips_elf64_swap_reloca_out (abfd, &int_rela, ext_rela);
- }
-
- BFD_ASSERT (ext_rela - (Elf64_Mips_External_Rela *) rela_hdr->contents
- == *count);
-}
-\f
-/* This structure is used to hold .got information when linking. It
- is stored in the tdata field of the bfd_elf_section_data structure. */
-
-struct mips_elf64_got_info
-{
- /* The global symbol in the GOT with the lowest index in the dynamic
- symbol table. */
- struct elf_link_hash_entry *global_gotsym;
- /* The number of global .got entries. */
- unsigned int global_gotno;
- /* The number of local .got entries. */
- unsigned int local_gotno;
- /* The number of local .got entries we have used. */
- unsigned int assigned_gotno;
-};
-
-/* The MIPS ELF64 linker needs additional information for each symbol in
- the global hash table. */