diff options
Diffstat (limited to 'bfd/elfxx-mips.c')
-rw-r--r-- | bfd/elfxx-mips.c | 134 |
1 files changed, 130 insertions, 4 deletions
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index ee0204d..2c7b35f 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -799,6 +799,11 @@ static bfd *reldyn_sorting_bfd; #define MICROMIPS_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0) +/* Nonzero if ABFD is MIPS R6. */ +#define MIPSR6_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6 \ + || (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6) + /* The IRIX compatibility level we are striving for. */ #define IRIX_COMPAT(abfd) \ (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd)) @@ -1100,6 +1105,17 @@ static const bfd_vma mips_exec_plt_entry[] = 0x03200008 /* jr $25 */ }; +/* In the following PLT entry the JR and ADDIU instructions will + be swapped in _bfd_mips_elf_finish_dynamic_symbol because + LOAD_INTERLOCKS_P will be true for MIPS R6. */ +static const bfd_vma mipsr6_exec_plt_entry[] = +{ + 0x3c0f0000, /* lui $15, %hi(.got.plt entry) */ + 0x01f90000, /* l[wd] $25, %lo(.got.plt entry)($15) */ + 0x25f80000, /* addiu $24, $15, %lo(.got.plt entry) */ + 0x03200009 /* jr $25 */ +}; + /* The format of subsequent MIPS16 o32 PLT entries. We use v0 ($2) and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not directly addressable. */ @@ -2180,7 +2196,8 @@ hi16_reloc_p (int r_type) { return (r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16 - || r_type == R_MICROMIPS_HI16); + || r_type == R_MICROMIPS_HI16 + || r_type == R_MIPS_PCHI16); } static inline bfd_boolean @@ -2188,7 +2205,8 @@ lo16_reloc_p (int r_type) { return (r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16 - || r_type == R_MICROMIPS_LO16); + || r_type == R_MICROMIPS_LO16 + || r_type == R_MIPS_PCLO16); } static inline bfd_boolean @@ -2206,6 +2224,13 @@ jal_reloc_p (int r_type) } static inline bfd_boolean +aligned_pcrel_reloc_p (int r_type) +{ + return (r_type == R_MIPS_PC18_S3 + || r_type == R_MIPS_PC19_S2); +} + +static inline bfd_boolean micromips_branch_reloc_p (int r_type) { return (r_type == R_MICROMIPS_26_S1 @@ -5161,6 +5186,8 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type, { case R_MIPS_26: case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: case R_MICROMIPS_26_S1: case R_MICROMIPS_PC7_S1: case R_MICROMIPS_PC10_S1: @@ -5951,6 +5978,71 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, value &= howto->dst_mask; break; + case R_MIPS_PC21_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 23); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + overflowed_p = mips_elf_overflow_p (value, 23); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC26_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 28); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + overflowed_p = mips_elf_overflow_p (value, 28); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC18_S3: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 21); + + if ((symbol + addend) & 7) + return bfd_reloc_outofrange; + + value = symbol + addend - ((p | 7) ^ 7); + overflowed_p = mips_elf_overflow_p (value, 21); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PC19_S2: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 21); + + if ((symbol + addend) & 3) + return bfd_reloc_outofrange; + + value = symbol + addend - p; + overflowed_p = mips_elf_overflow_p (value, 21); + value >>= howto->rightshift; + value &= howto->dst_mask; + break; + + case R_MIPS_PCHI16: + value = mips_elf_high (symbol + addend - p); + overflowed_p = mips_elf_overflow_p (value, 16); + value &= howto->dst_mask; + break; + + case R_MIPS_PCLO16: + if (howto->partial_inplace) + addend = _bfd_mips_elf_sign_extend (addend, 16); + value = symbol + addend - p; + value &= howto->dst_mask; + break; + case R_MICROMIPS_PC7_S1: value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p; overflowed_p = mips_elf_overflow_p (value, 8); @@ -6517,6 +6609,12 @@ _bfd_elf_mips_mach (flagword flags) case E_MIPS_ARCH_64R2: return bfd_mach_mipsisa64r2; + + case E_MIPS_ARCH_32R6: + return bfd_mach_mipsisa32r6; + + case E_MIPS_ARCH_64R6: + return bfd_mach_mipsisa64r6; } } @@ -7693,6 +7791,8 @@ mips_elf_add_lo16_rel_addend (bfd *abfd, lo16_type = R_MIPS16_LO16; else if (micromips_reloc_p (r_type)) lo16_type = R_MICROMIPS_LO16; + else if (r_type == R_MIPS_PCHI16) + lo16_type = R_MIPS_PCLO16; else lo16_type = R_MIPS_LO16; @@ -8205,6 +8305,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_26: case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: case R_MIPS16_26: case R_MICROMIPS_26_S1: case R_MICROMIPS_PC7_S1: @@ -10129,6 +10231,13 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, (info, msg, name, input_bfd, input_section, rel->r_offset); return FALSE; } + if (aligned_pcrel_reloc_p (howto->type)) + { + msg = _("PC-relative load from unaligned address"); + info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + return FALSE; + } /* Fall through. */ default: @@ -10418,7 +10527,11 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, load = MIPS_ELF_LOAD_WORD (output_bfd); /* Fill in the PLT entry itself. */ - plt_entry = mips_exec_plt_entry; + + if (MIPSR6_P (output_bfd)) + plt_entry = mipsr6_exec_plt_entry; + else + plt_entry = mips_exec_plt_entry; bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc); bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load, loc + 4); @@ -11755,6 +11868,14 @@ mips_set_isa_flags (bfd *abfd) case bfd_mach_mipsisa64r5: val = E_MIPS_ARCH_64R2; break; + + case bfd_mach_mipsisa32r6: + val = E_MIPS_ARCH_32R6; + break; + + case bfd_mach_mipsisa64r6: + val = E_MIPS_ARCH_64R6; + break; } elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); elf_elfheader (abfd)->e_flags |= val; @@ -13839,7 +13960,8 @@ mips_32bit_flags_p (flagword flags) || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1 || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2 || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32 - || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2); + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2 + || (flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6); } /* Infer the content of the ABI flags based on the elf header. */ @@ -15528,6 +15650,10 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) fprintf (file, " [mips32r2]"); else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2) fprintf (file, " [mips64r2]"); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6) + fprintf (file, " [mips32r6]"); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R6) + fprintf (file, " [mips64r6]"); else fprintf (file, _(" [unknown ISA]")); |