diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 3493d4f0de41cb184710248ce6664700bca78cca..b5922ff222b48e0699a814c9742e0a61cdca9cb8 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3567,6 +3567,9 @@ field in the instruction. */ /* ARM 5-bit pc-relative branch for Branch Future instructions. */ BFD_RELOC_THUMB_PCREL_BRANCH5, +/* ARM 17-bit pc-relative branch for Branch Future instructions. */ + BFD_RELOC_ARM_THUMB_BF17, + /* 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/elf32-arm.c b/bfd/elf32-arm.c index 735fe122880c59633b0083b78b9b1e686cfd91c5..abdc2bbdac6f00e7ce631bcb1dfa477edf480063 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -1742,6 +1742,20 @@ static reloc_howto_type elf32_arm_howto_table_1[] = 0x00000000, /* src_mask. */ 0x00000000, /* dst_mask. */ FALSE), /* pcrel_offset. */ + /* Relocations for Armv8.1-M Mainline. */ + HOWTO (R_ARM_THM_BF16, /* type. */ + 0, /* rightshift. */ + 1, /* size (0 = byte, 1 = short, 2 = long). */ + 16, /* bitsize. */ + TRUE, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont,/* do not complain_on_overflow. */ + bfd_elf_generic_reloc, /* special_function. */ + "R_ARM_THM_BF16", /* name. */ + FALSE, /* partial_inplace. */ + 0x001f0ffe, /* src_mask. */ + 0x001f0ffe, /* dst_mask. */ + TRUE), /* pcrel_offset. */ }; /* 160 onwards: */ @@ -2053,7 +2067,8 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = {BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC, R_ARM_THM_ALU_ABS_G3_NC}, {BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC, R_ARM_THM_ALU_ABS_G2_NC}, {BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC, R_ARM_THM_ALU_ABS_G1_NC}, - {BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G0_NC} + {BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G0_NC}, + {BFD_RELOC_ARM_THUMB_BF17, R_ARM_THM_BF16} }; static reloc_howto_type * @@ -10250,6 +10265,59 @@ identify_add_or_sub (bfd_vma insn) return 0; } +/* Helper function to compute the Addend for Armv8.1-M Mainline relocations. */ +static bfd_vma +get_value_helper (bfd_vma plt_offset, + asection *splt, + asection *input_section, + asection *sym_sec, + struct elf_link_hash_entry * h, + struct bfd_link_info *info, + bfd *input_bfd, + Elf_Internal_Rela *rel, + const char *sym_name, + unsigned char st_type, + struct elf32_arm_link_hash_table *globals, + bfd_boolean *unresolved_reloc_p) +{ + bfd_vma value = 0; + enum arm_st_branch_type branch_type; + enum elf32_arm_stub_type stub_type = arm_stub_none; + struct elf32_arm_stub_hash_entry *stub_entry; + struct elf32_arm_link_hash_entry *hash + = (struct elf32_arm_link_hash_entry *)h; + + + if (plt_offset != (bfd_vma) -1) + { + value = (splt->output_section->vma + + splt->output_offset + + plt_offset); + value -= PLT_THUMB_STUB_SIZE; + *unresolved_reloc_p = FALSE; + } + + stub_type = arm_type_of_stub (info, input_section, rel, + st_type, &branch_type, + hash, value, sym_sec, + input_bfd, sym_name); + + if (stub_type != arm_stub_none) + { + stub_entry = elf32_arm_get_stub_entry (input_section, + sym_sec, h, + rel, globals, + stub_type); + if (stub_entry != NULL) + { + value = (stub_entry->stub_offset + + stub_entry->stub_sec->output_offset + + stub_entry->stub_sec->output_section->vma); + } + } + return value; +} + /* Perform a relocation as part of a final link. */ static bfd_reloc_status_type @@ -12855,6 +12923,51 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, *unresolved_reloc_p = FALSE; return bfd_reloc_ok; + case R_ARM_THM_BF16: + { + bfd_vma relocation; + bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); + bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); + + if (globals->use_rel) + { + bfd_vma immA = (upper_insn & 0x001f); + bfd_vma immB = (lower_insn & 0x07fe) >> 1; + bfd_vma immC = (lower_insn & 0x0800) >> 11; + addend = (immA << 12); + addend |= (immB << 2); + addend |= (immC << 1); + addend |= 1; + /* Sign extend. */ + addend = (addend & 0x10000) ? addend - (1 << 17) : addend; + } + + value = get_value_helper (plt_offset, splt, input_section, sym_sec, h, + info, input_bfd, rel, sym_name, st_type, + globals, unresolved_reloc_p); + + relocation = value + addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + + /* Put RELOCATION back into the insn. */ + { + bfd_vma immA = (relocation & 0x0001f000) >> 12; + bfd_vma immB = (relocation & 0x00000ffc) >> 2; + bfd_vma immC = (relocation & 0x00000002) >> 1; + + upper_insn = (upper_insn & 0xffe0) | immA; + lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1); + } + + /* Put the relocated value back in the object file: */ + bfd_put_16 (input_bfd, upper_insn, hit_data); + bfd_put_16 (input_bfd, lower_insn, hit_data + 2); + + return bfd_reloc_ok; + } + default: return bfd_reloc_notsupported; } diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 02daa29b433e390507fe91e7a045f43eb85d548d..4a3fa144ad25b5a800501c352e6f0aa79509bb27 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1530,6 +1530,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_ARM_PCREL_CALL", "BFD_RELOC_ARM_PCREL_JUMP", "BFD_RELOC_THUMB_PCREL_BRANCH5", + "BFD_RELOC_ARM_THUMB_BF17", "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 a071dc75c0499192077da30aba8ee7fc3d62dacb..b351d120d1d1894ba64a3eb2d32e21884648fd6a 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3019,6 +3019,11 @@ ENUM ENUMDOC ARM 5-bit pc-relative branch for Branch Future instructions. +ENUM + BFD_RELOC_ARM_THUMB_BF17 +ENUMDOC + ARM 17-bit pc-relative branch for Branch Future instructions. + ENUM BFD_RELOC_THUMB_PCREL_BRANCH7 ENUMX diff --git a/elfcpp/arm.h b/elfcpp/arm.h index fb5cc25f0695fb62e398c6c9a26b7e2c59e40be0..b4cd67f87ce49288ee40adb7653443b493774267 100644 --- a/elfcpp/arm.h +++ b/elfcpp/arm.h @@ -194,7 +194,10 @@ enum R_ARM_ME_TOO = 128, // Obsolete R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16 R_ARM_THM_TLS_DESCSEQ32 = 130,// Static Thumb32 - // 131 - 139 Unallocated + // 131 - 135 Unallocated + // Relocations for Armv8.1-M Mainline (BF/BFL) + R_ARM_THM_BF16 = 136, // Static Thumb32 ((S + A) | T) – P + // 139 Unallocated // 140 - 159 Dynamic Reserved for future allocation R_ARM_IRELATIVE = 160, // Dynamic // 161 - 255 Unallocated diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 14d114adbeec62b11fa3bc7d4f7cb3cdd030bf8f..d3a21d63575c194051606bb723a224d3c10334e9 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -22853,6 +22853,7 @@ md_pcrel_from_section (fixS * fixP, segT seg) case BFD_RELOC_THUMB_PCREL_BRANCH12: case BFD_RELOC_THUMB_PCREL_BRANCH20: case BFD_RELOC_THUMB_PCREL_BRANCH25: + case BFD_RELOC_ARM_THUMB_BF17: return base + 4; case BFD_RELOC_THUMB_PCREL_BRANCH23: @@ -24750,6 +24751,39 @@ md_apply_fix (fixS * fixP, } break; + case BFD_RELOC_ARM_THUMB_BF17: + 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 17 bits wide. */ + fixP->fx_done = 0; + } + + if (v8_1_branch_value_check (value, 17, TRUE) == FAIL) + as_bad_where (fixP->fx_file, fixP->fx_line, + BAD_BRANCH_OFF); + + if (fixP->fx_done || !seg->use_rela_p) + { + offsetT newval2; + addressT immA, immB, immC; + + immA = (value & 0x0001f000) >> 12; + immB = (value & 0x00000ffc) >> 2; + immC = (value & 0x00000002) >> 1; + + newval = md_chars_to_number (buf, THUMB_SIZE); + newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE); + newval |= immA; + newval2 |= (immC << 11) | (immB << 1); + md_number_to_chars (buf, newval, THUMB_SIZE); + md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE); + } + break; + case BFD_RELOC_ARM_V4BX: /* This will need to go in the object file. */ fixP->fx_done = 0; @@ -24932,6 +24966,7 @@ tc_gen_reloc (asection *section, fixS *fixp) case BFD_RELOC_ARM_GOTFUNCDESC: case BFD_RELOC_ARM_GOTOFFFUNCDESC: case BFD_RELOC_ARM_FUNCDESC: + case BFD_RELOC_ARM_THUMB_BF17: code = fixp->fx_r_type; break; diff --git a/include/elf/arm.h b/include/elf/arm.h index daf1d94391ea23c49cb646af430d2db8ef46c51e..2c6d4ef18a96e10fb206248df151c44a67757042 100644 --- a/include/elf/arm.h +++ b/include/elf/arm.h @@ -241,6 +241,7 @@ START_RELOC_NUMBERS (elf_arm_reloc_type) RELOC_NUMBER (R_ARM_THM_ALU_ABS_G1_NC,133) RELOC_NUMBER (R_ARM_THM_ALU_ABS_G2_NC,134) RELOC_NUMBER (R_ARM_THM_ALU_ABS_G3_NC,135) + RELOC_NUMBER (R_ARM_THM_BF16, 136) RELOC_NUMBER (R_ARM_IRELATIVE, 160) RELOC_NUMBER (R_ARM_GOTFUNCDESC, 161) diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index 0fe44877db243b8cbce50fed451e65fcacf9fabc..71443d3ea41966309d4516754eb8f2e38e3e6df0 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -2715,6 +2715,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 + %W print an offset for BF instruction %b print a conditional branch offset %B print an unconditional branch offset %s print the shift field of an SSAT instruction @@ -5871,6 +5872,23 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) } break; + case 'W': + { + unsigned int immA = (given & 0x001f0000u) >> 16; + unsigned int immB = (given & 0x000007feu) >> 1; + unsigned int immC = (given & 0x00000800u) >> 11; + bfd_vma offset = 0; + + offset |= immA << 12; + offset |= immB << 2; + offset |= immC << 1; + /* Sign extend. */ + offset = (offset & 0x10000) ? offset - (1 << 17) : offset; + + info->print_address_func (pc + 4 + offset, info); + } + break; + case 'b': { unsigned int S = (given & 0x04000000u) >> 26;