summaryrefslogtreecommitdiff
path: root/bfd/elfxx-mips.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@imgtec.com>2016-06-28 01:23:36 +0100
committerMaciej W. Rozycki <macro@imgtec.com>2016-06-28 01:29:56 +0100
commitc9775dde32773c57d4eb5dfb4265eda9cb8adbe8 (patch)
tree59735930ba2df8d7a5e885c7d388b45e341ecd04 /bfd/elfxx-mips.c
parentbac13b9c13a0169aea400335776310b1f1ff2d16 (diff)
MIPS16: Add R_MIPS16_PC16_S1 branch relocation support
For R_MIPS16_PC16_S1 the calculation is `(sign_extend(A) + S - P) >> 1' and the usual MIPS16 bit shuffling applies to relocated field handling, as per the encoding of the branch target in the extended form of the MIPS16 B, BEQZ, BNEZ, BTEQZ and BTNEZ instructions. include/ * elf/mips.h (R_MIPS16_PC16_S1): New relocation. bfd/ * elf32-mips.c (elf_mips16_howto_table_rel): Add R_MIPS16_PC16_S1. (mips16_reloc_map): Likewise. * elf64-mips.c (mips16_elf64_howto_table_rel): Likewise. (mips16_elf64_howto_table_rela): Likewise. (mips16_reloc_map): Likewise. * elfn32-mips.c (elf_mips16_howto_table_rel): Likewise. (elf_mips16_howto_table_rela): Likewise. (mips16_reloc_map): Likewise. * elfxx-mips.c (mips16_branch_reloc_p): New function. (mips16_reloc_p): Handle R_MIPS16_PC16_S1. (b_reloc_p): Likewise. (mips_elf_calculate_relocation): Likewise. (_bfd_mips_elf_check_relocs): Likewise. * reloc.c (BFD_RELOC_MIPS16_16_PCREL_S1): New relocation. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. gas/ * config/tc-mips.c (mips16_reloc_p): Handle BFD_RELOC_MIPS16_16_PCREL_S1. (b_reloc_p): Likewise. (limited_pcrel_reloc_p): Likewise. (md_pcrel_from): Likewise. (md_apply_fix): Likewise. (tc_gen_reloc): Likewise. (md_convert_frag): Likewise. (mips_fix_adjustable): Update comment. * testsuite/gas/mips/mips16-branch-reloc-2.d: Remove error output, add dump patterns. * testsuite/gas/mips/mips16-branch-reloc-3.d: Remove error output, add dump patterns. * testsuite/gas/mips/mips16-branch-addend-2.d: Remove error output, add dump patterns. * testsuite/gas/mips/mips16-branch-addend-3.d: Remove error output, add dump patterns. * testsuite/gas/mips/mips16-branch-absolute.d: Remove error output, add dump patterns. * testsuite/gas/mips/mips16-branch-reloc-2.l: Remove file. * testsuite/gas/mips/mips16-branch-reloc-3.l: Remove file. * testsuite/gas/mips/mips16-branch-addend-2.l: Remove file. * testsuite/gas/mips/mips16-branch-addend-3.l: Remove file. * testsuite/gas/mips/mips16-branch-absolute.l: Remove file. * testsuite/gas/mips/mips16-branch-addend-2.s: Add padding. * testsuite/gas/mips/branch-weak.s: Adjust alignment, avoid implicit instruction padding, avoid MIPS16 JR->JRC conversion. * testsuite/gas/mips/branch-weak-6.d: New test. * testsuite/gas/mips/branch-weak-7.d: New test. * testsuite/gas/mips/mips.exp: Run the new tests. ld/ * testsuite/ld-mips-elf/mips16-branch-2.d: New test. * testsuite/ld-mips-elf/mips16-branch-3.d: New test. * testsuite/ld-mips-elf/mips16-branch-addend-2.d: New test. * testsuite/ld-mips-elf/mips16-branch-addend-3.d: New test. * testsuite/ld-mips-elf/mips16-branch.s: New test source. * testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.
Diffstat (limited to 'bfd/elfxx-mips.c')
-rw-r--r--bfd/elfxx-mips.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 3b7723e3d0..e47276bc61 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -2090,7 +2090,11 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
All we need to do here is shuffle the bits appropriately.
As above, the two 16-bit halves must be swapped on a
- little-endian system. */
+ little-endian system.
+
+ Finally R_MIPS16_PC16_S1 corresponds to R_MIPS_PC16, however the
+ relocatable field is shifted by 1 rather than 2 and the same bit
+ shuffling is done as with the relocations above. */
static inline bfd_boolean
mips16_reloc_p (int r_type)
@@ -2110,6 +2114,7 @@ mips16_reloc_p (int r_type)
case R_MIPS16_TLS_GOTTPREL:
case R_MIPS16_TLS_TPREL_HI16:
case R_MIPS16_TLS_TPREL_LO16:
+ case R_MIPS16_PC16_S1:
return TRUE;
default:
@@ -2221,7 +2226,8 @@ b_reloc_p (int r_type)
return (r_type == R_MIPS_PC26_S2
|| r_type == R_MIPS_PC21_S2
|| r_type == R_MIPS_PC16
- || r_type == R_MIPS_GNU_REL16_S2);
+ || r_type == R_MIPS_GNU_REL16_S2
+ || r_type == R_MIPS16_PC16_S1);
}
static inline bfd_boolean
@@ -2232,6 +2238,13 @@ aligned_pcrel_reloc_p (int r_type)
}
static inline bfd_boolean
+mips16_branch_reloc_p (int r_type)
+{
+ return (r_type == R_MIPS16_26
+ || r_type == R_MIPS16_PC16_S1);
+}
+
+static inline bfd_boolean
micromips_branch_reloc_p (int r_type)
{
return (r_type == R_MICROMIPS_26_S1
@@ -5562,7 +5575,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
}
/* Make sure MIPS16 and microMIPS are not used together. */
- if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+ if ((mips16_branch_reloc_p (r_type) && target_is_micromips_code_p)
|| (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
{
(*_bfd_error_handler)
@@ -5994,6 +6007,21 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
value &= howto->dst_mask;
break;
+ case R_MIPS16_PC16_S1:
+ if (howto->partial_inplace)
+ addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+ if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ && ((symbol + addend) & 1) == 0)
+ return bfd_reloc_outofrange;
+
+ value = symbol + addend - p;
+ if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ overflowed_p = mips_elf_overflow_p (value, 17);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
case R_MIPS_PC21_S2:
if (howto->partial_inplace)
addend = _bfd_mips_elf_sign_extend (addend, 23);
@@ -8346,6 +8374,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_MIPS_PC21_S2:
case R_MIPS_PC26_S2:
case R_MIPS16_26:
+ case R_MIPS16_PC16_S1:
case R_MICROMIPS_26_S1:
case R_MICROMIPS_PC7_S1:
case R_MICROMIPS_PC10_S1: