diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 4f63fe50e6bf8003fb25beec9e64927a672e444b..3493d4f0de41cb184710248ce6664700bca78cca 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3564,6 +3564,9 @@ field in the instruction. */ /* ARM 26-bit pc-relative branch for B or conditional BL instruction. */ BFD_RELOC_ARM_PCREL_JUMP, +/* ARM 5-bit pc-relative branch for Branch Future instructions. */ + BFD_RELOC_THUMB_PCREL_BRANCH5, + /* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. The lowest bit must be zero and is not stored in the instruction. Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 36284d71a9bdb0237ad678027441ccf0fe880430..02daa29b433e390507fe91e7a045f43eb85d548d 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1529,6 +1529,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_THUMB_PCREL_BLX", "BFD_RELOC_ARM_PCREL_CALL", "BFD_RELOC_ARM_PCREL_JUMP", + "BFD_RELOC_THUMB_PCREL_BRANCH5", "BFD_RELOC_THUMB_PCREL_BRANCH7", "BFD_RELOC_THUMB_PCREL_BRANCH9", "BFD_RELOC_THUMB_PCREL_BRANCH12", diff --git a/bfd/reloc.c b/bfd/reloc.c index e6446a78098602d91d3c7f4a0b20807b805bb829..a071dc75c0499192077da30aba8ee7fc3d62dacb 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3014,6 +3014,11 @@ ENUM ENUMDOC ARM 26-bit pc-relative branch for B or conditional BL instruction. +ENUM + BFD_RELOC_THUMB_PCREL_BRANCH5 +ENUMDOC + ARM 5-bit pc-relative branch for Branch Future instructions. + ENUM BFD_RELOC_THUMB_PCREL_BRANCH7 ENUMX diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 11d593c2626199d0dad4f4d81a276decb0300d3c..a13baa603486623836977d4c8f68ac283d02cbab 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -235,6 +235,8 @@ static const arm_feature_set arm_ext_pan = ARM_FEATURE_CORE_HIGH (ARM_EXT2_PAN); static const arm_feature_set arm_ext_v8m = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M); static const arm_feature_set arm_ext_v8m_main = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M_MAIN); +static const arm_feature_set arm_ext_v8_1m_main = +ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN); /* Instructions in ARMv8-M only found in M profile architectures. */ static const arm_feature_set arm_ext_v8m_m_only = ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M | ARM_EXT2_V8M_MAIN); @@ -843,6 +845,7 @@ struct asm_opcode #define BAD_THUMB32 _("instruction not supported in Thumb16 mode") #define BAD_ADDR_MODE _("instruction does not accept this addressing mode"); #define BAD_BRANCH _("branch must be last instruction in IT block") +#define BAD_BRANCH_OFF _("branch out of range or not a multiple of 2") #define BAD_NOT_IT _("instruction not allowed in IT block") #define BAD_FPU _("selected FPU does not support instruction") #define BAD_OUT_IT _("thumb conditional instruction should be in IT block") @@ -13272,6 +13275,26 @@ do_t_usat16 (void) inst.instruction |= Rn << 16; } +/* Checking the range of the branch offset (VAL) with NBITS bits + and IS_SIGNED signedness. Also checks the LSB to be 0. */ +static int +v8_1_branch_value_check (int val, int nbits, int is_signed) +{ + gas_assert (nbits > 0 && nbits <= 32); + if (is_signed) + { + int cmp = (1 << (nbits - 1)); + if ((val < -cmp) || (val >= cmp) || (val & 0x01)) + return FAIL; + } + else + { + if ((val <= 0) || (val >= (1 << nbits)) || (val & 0x1)) + return FAIL; + } + return SUCCESS; +} + /* Neon instruction encoder helpers. */ /* Encodings for the different types for various Neon opcodes. */ @@ -22791,6 +22814,7 @@ md_pcrel_from_section (fixS * fixP, segT seg) return (base + 4) & ~3; /* Thumb branches are simply offset by +4. */ + case BFD_RELOC_THUMB_PCREL_BRANCH5: case BFD_RELOC_THUMB_PCREL_BRANCH7: case BFD_RELOC_THUMB_PCREL_BRANCH9: case BFD_RELOC_THUMB_PCREL_BRANCH12: @@ -24669,6 +24693,30 @@ md_apply_fix (fixS * fixP, } break; + case BFD_RELOC_THUMB_PCREL_BRANCH5: + if (fixP->fx_addsy + && (S_GET_SEGMENT (fixP->fx_addsy) == seg) + && !S_FORCE_RELOC (fixP->fx_addsy, TRUE) + && ARM_IS_FUNC (fixP->fx_addsy) + && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main)) + { + /* Force a relocation for a branch 5 bits wide. */ + fixP->fx_done = 0; + } + if (v8_1_branch_value_check (value, 5, FALSE) == FAIL) + as_bad_where (fixP->fx_file, fixP->fx_line, + BAD_BRANCH_OFF); + + if (fixP->fx_done || !seg->use_rela_p) + { + addressT boff = value >> 1; + + newval = md_chars_to_number (buf, THUMB_SIZE); + newval |= (boff << 7); + md_number_to_chars (buf, newval, THUMB_SIZE); + } + break; + case BFD_RELOC_ARM_V4BX: /* This will need to go in the object file. */ fixP->fx_done = 0; @@ -24880,6 +24928,12 @@ tc_gen_reloc (asection *section, fixS *fixp) _("ADRL used for a symbol not defined in the same file")); return NULL; + case BFD_RELOC_THUMB_PCREL_BRANCH5: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("%s used for a symbol not defined in the same file"), + bfd_get_reloc_code_name (fixp->fx_r_type)); + return NULL; + case BFD_RELOC_ARM_OFFSET_IMM: if (section->use_rela_p) { diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index be9879da621c14e4dd8a816a371aaad6ccc4a696..0fe44877db243b8cbce50fed451e65fcacf9fabc 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -2714,6 +2714,7 @@ static const struct opcode16 thumb_opcodes[] = %E print the lsb and width fields of a bfc/bfi instruction %F print the lsb and width fields of a sbfx/ubfx instruction + %G print a fallback offset for Branch Future instructions %b print a conditional branch offset %B print an unconditional branch offset %s print the shift field of an SSAT instruction @@ -5863,6 +5864,13 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) } break; + case 'G': + { + unsigned int boff = (((given & 0x07800000) >> 23) << 1); + func (stream, "%x", boff); + } + break; + case 'b': { unsigned int S = (given & 0x04000000u) >> 26;