From cb1efead5ceb9edd45f891f540fda358a3695aa7 Mon Sep 17 00:00:00 2001 From: Claudiu Zissulescu Date: Tue, 5 Mar 2019 14:30:45 +0200 Subject: [PATCH 1/4] binutils: Relax from BL to BL_S instruction. Adds to linker relaxation the possibility of performing linker relaxation from BL instruction to BL_S, if possible. This relaxation also requires the object file to be prepared for shrinking by the assembler. If that operation is not performed, then this linker relaxation operation will not take place. bfd/ xxxx-xx-xx Claudiu Zissulescu * bfd-in2.h: Regenerate. * elf32-arc.c (arc_elf_merge_attributes): Take into account if an object can be relaxed. (ICARRY): Define. (arc_relax_delete_bytes): New function. (arc_elf_relax_section): Add BL to BL_S relaxation rule. * libbfd.h: Regenerate. * reloc.c: Add extra relocs. binutils/ xxxx-xx-xx Claudiu Zissulescu * readelf.c (display_arc_attribute): Recognize relaxable object. gas/ xxxx-xx-xx Claudiu Zissulescu * config/tc-arc.c (relaxation_state): Change it from int to bfd_boolean. (enum options): Add linker_relax option. (md_longopts): Likewise. (md_begin): Initialize linkrelax variable. (md_apply_fix): Cleanup unused code. (md_parse_option): Recognize linker_relax option. (arc_make_nops): New function. (arc_handle_align): Change it to generate ARC_ALIGN reloc when needed. (tc_arc_fix_adjustable): All relocs are using the original symbol. (arc_cons_fix_new): Generate corresponding relocs when we have symbol difference. (arc_set_public_attributes): Set relaxable attribute whenever is necessary. (arc_allow_local_substract): New function. * config/tc-arc.h (TC_LINKRELAX_FIXUP): Define. (LINKER_RELAXING_SHRINKS_ONLY): Likewise. (TC_VALIDATE_FIX): Update with known relocs. (TC_FORCE_RELOCATION_SUB_LOCAL): Delete. (md_allow_local_subtract): Define. (TC_VALIDATE_FIX_SUB): Delete. include/ xxxx-xx-xx Claudiu Zissulescu * elf/arc-reloc.def (ARC_S9H_PCREL): Add new reloc. (ARC_S7H_PCREL): Likewise. (ARC_S8H_PCREL): Likewise. (ARC_S10H_PCREL): Likewise. (ARC_S13H_PCREL): Likewise. (ARC_ALIGN): Likewise. (ARC_ADD8): Likewise. (ARC_ADD16): Likewise. (ARC_SUB8): Likewise. (ARC_SUB16): Likewise. (ARC_SUB32): Likewise. * opcode/arc-func.h (replace_bits9): New function. (replace_bits10): Likewise. (replace_bits7): Likewise. (replace_disp8h): Likewise. (replace_bits13): Likewise. ld/ xxxx-xx-xx Claudiu Zissulescu * emulparams/arcelf.sh (EXTRA_EM_FILE): Add. * emulparams/arcv2elf.sh (EXTRA_EM_FILE): Likewise. * emulparams/arcv2elfx.sh (EXTRA_EM_FILE): Likewise. * emultempl/arcelf.em: New file. * testsuite/ld-arc/jli-simple.rd: New file. * testsuite/ld-arc/relax-call-1.d: Likewise. * testsuite/ld-arc/relax-call-1.s: Likewise. * testsuite/ld-arc/relax-call-2.d: Likewise. * testsuite/ld-arc/relax-call-2.s: Likewise. * testsuite/ld-arc/relax-call-3.d: Likewise. * testsuite/ld-arc/relax-call-3.s: Likewise. opcodes/ xxxx-xx-xx Claudiu Zissulescu * arc-opc.c (SIMM9_A16_8): Use external reloc. (SIMM10_A16_7_S): Likewise. (SIMM7_A16_10_S): Likewise. (SIMM8_A16_9_S): Likewise. (SIMM13_A16_20): Likewise. [RLX][FIX] Fix relocations when we don't linkrelax --- bfd/bfd-in2.h | 11 + bfd/elf32-arc.c | 340 +++++++++++++++++++++++++---- bfd/libbfd.h | 11 + bfd/reloc.c | 22 ++ binutils/readelf.c | 18 +- gas/config/tc-arc.c | 228 +++++++++++++++---- gas/config/tc-arc.h | 29 ++- gas/write.c | 12 +- include/elf/arc-reloc.def | 79 ++++++- include/opcode/arc-func.h | 72 ++++++ ld/emulparams/arcelf.sh | 1 + ld/emulparams/arcv2elf.sh | 2 +- ld/emulparams/arcv2elfx.sh | 2 +- ld/emultempl/arcelf.em | 40 ++++ ld/testsuite/ld-arc/relax-call-1.d | 20 ++ ld/testsuite/ld-arc/relax-call-1.s | 14 ++ ld/testsuite/ld-arc/relax-call-2.d | 27 +++ ld/testsuite/ld-arc/relax-call-2.s | 23 ++ ld/testsuite/ld-arc/relax-call-3.d | 36 +++ ld/testsuite/ld-arc/relax-call-3.s | 27 +++ opcodes/arc-opc.c | 10 +- 21 files changed, 900 insertions(+), 124 deletions(-) create mode 100644 ld/emultempl/arcelf.em create mode 100644 ld/testsuite/ld-arc/relax-call-1.d create mode 100644 ld/testsuite/ld-arc/relax-call-1.s create mode 100644 ld/testsuite/ld-arc/relax-call-2.d create mode 100644 ld/testsuite/ld-arc/relax-call-2.s create mode 100644 ld/testsuite/ld-arc/relax-call-3.d create mode 100644 ld/testsuite/ld-arc/relax-call-3.s diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 7eff85b7eaa..9065ae3b037 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3423,6 +3423,17 @@ pc-relative or some form of GOT-indirect relocation. */ BFD_RELOC_ARC_S21H_PCREL_PLT, BFD_RELOC_ARC_NPS_CMEM16, BFD_RELOC_ARC_JLI_SECTOFF, + BFD_RELOC_ARC_S7H_PCREL, + BFD_RELOC_ARC_S8H_PCREL, + BFD_RELOC_ARC_S9H_PCREL, + BFD_RELOC_ARC_S10H_PCREL, + BFD_RELOC_ARC_S13H_PCREL, + BFD_RELOC_ARC_ALIGN, + BFD_RELOC_ARC_ADD8, + BFD_RELOC_ARC_ADD16, + BFD_RELOC_ARC_SUB8, + BFD_RELOC_ARC_SUB16, + BFD_RELOC_ARC_SUB32, /* ADI Blackfin 16 bit immediate absolute reloc. */ BFD_RELOC_BFIN_16_IMM, diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c index df12fd33a10..4b34e5b40f5 100644 --- a/bfd/elf32-arc.c +++ b/bfd/elf32-arc.c @@ -48,7 +48,6 @@ name_for_global_symbol (struct elf_link_hash_entry *h) #define ARC_DEBUG(...) #endif - #define ADD_RELA(BFD, SECTION, OFFSET, SYM_IDX, TYPE, ADDEND) \ { \ struct elf_link_hash_table *_htab = elf_hash_table (info); \ @@ -629,20 +628,21 @@ arc_elf_merge_attributes (bfd *ibfd, struct bfd_link_info *info) case Tag_ARC_PCS_config: if (out_attr[i].i == 0) out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i) + else if ((in_attr[i].i & 0xff) != 0 + && ((out_attr[i].i & 0xff) != (in_attr[i].i & 0xff))) { const char *tagval[] = { "Absent", "Bare-metal/mwdt", - "Bare-metal/newlib", "Linux/uclibc", - "Linux/glibc" }; - BFD_ASSERT (in_attr[i].i < 5); - BFD_ASSERT (out_attr[i].i < 5); + "Bare-metal/newlib", "Linux/uclibc", + "Linux/glibc" }; + BFD_ASSERT ((in_attr[i].i & 0xff) < 5); + BFD_ASSERT ((out_attr[i].i & 0xff) < 5); /* It's sometimes ok to mix different configs, so this is only a warning. */ _bfd_error_handler (_("warning: %pB: conflicting platform configuration " "%s with %s"), ibfd, - tagval[in_attr[i].i], - tagval[out_attr[i].i]); + tagval[in_attr[i].i & 0xff], + tagval[out_attr[i].i & 0xff]); } break; @@ -1230,6 +1230,7 @@ arc_special_overflow_checks (const struct arc_relocation_data reloc_data, ((elf_hash_table (info))->tls_sec->output_section->vma) #define TLS_TBSS (align_power(TCB_SIZE, \ reloc_data.sym_section->alignment_power)) +#define ICARRY insn #define none (0) @@ -1404,6 +1405,7 @@ arc_do_relocation (bfd_byte * contents, #undef SECTSTART #undef JLI #undef _SDA_BASE_ +#undef ICARRY #undef none #undef ARC_RELOC_HOWTO @@ -2947,13 +2949,137 @@ elf32_arc_section_from_shdr (bfd *abfd, return TRUE; } +/* Delete a number of bytes from a given section while relaxing. */ + +static bfd_boolean +arc_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, + asection *sec, bfd_vma addr, int count) +{ + Elf_Internal_Shdr *symtab_hdr; + unsigned int sec_shndx; + bfd_byte *contents; + Elf_Internal_Rela *irel, *irelend; + bfd_vma toaddr; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + struct elf_link_hash_entry **sym_hashes; + struct elf_link_hash_entry **end_hashes; + struct elf_link_hash_entry **start_hashes; + unsigned int symcount; + + sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + contents = elf_section_data (sec)->this_hdr.contents; + + toaddr = sec->size; + + irel = elf_section_data (sec)->relocs; + irelend = irel + sec->reloc_count; + + /* Actually delete the bytes. */ + memmove (contents + addr, contents + addr + count, + (size_t) (toaddr - addr - count)); + sec->size -= count; + + /* Adjust all the relocs. */ + for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) + /* Get the new reloc address. */ + if ((irel->r_offset > addr && irel->r_offset < toaddr)) + irel->r_offset -= count; + + /* Adjust the local symbols defined in this section. */ + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + isym = (Elf_Internal_Sym *) symtab_hdr->contents; + for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) + { + if (isym->st_shndx == sec_shndx + && isym->st_value > addr + && isym->st_value <= toaddr) + { + /* Adjust the addend of SWITCH relocations in this section, + which reference this local symbol. */ + isym->st_value -= count; + } + } + + /* Now adjust the global symbols defined in this section. */ + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) + - symtab_hdr->sh_info); + sym_hashes = start_hashes = elf_sym_hashes (abfd); + end_hashes = sym_hashes + symcount; + + for (; sym_hashes < end_hashes; sym_hashes++) + { + struct elf_link_hash_entry *sym_hash = *sym_hashes; + + /* The '--wrap SYMBOL' option is causing a pain when the object file, + containing the definition of __wrap_SYMBOL, includes a direct + call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference + the same symbol (which is __wrap_SYMBOL), but still exist as two + different symbols in 'sym_hashes', we don't want to adjust + the global symbol __wrap_SYMBOL twice. + This check is only relevant when symbols are being wrapped. */ + if (link_info->wrap_hash != NULL) + { + struct elf_link_hash_entry **cur_sym_hashes; + + /* Loop only over the symbols whom been already checked. */ + for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; + cur_sym_hashes++) + /* If the current symbol is identical to 'sym_hash', that means + the symbol was already adjusted (or at least checked). */ + if (*cur_sym_hashes == sym_hash) + break; + + /* Don't adjust the symbol again. */ + if (cur_sym_hashes < sym_hashes) + continue; + } + + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) + && sym_hash->root.u.def.section == sec) + { + /* As above, adjust the value if needed. */ + if (sym_hash->root.u.def.value > addr + && sym_hash->root.u.def.value <= toaddr) + sym_hash->root.u.def.value -= count; + + /* As above, adjust the size if needed. */ + if (sym_hash->root.u.def.value <= addr + && sym_hash->root.u.def.value + sym_hash->size > addr + && sym_hash->root.u.def.value + sym_hash->size <= toaddr) + sym_hash->size -= count; + } + } + + return TRUE; +} + +/* Check Tag_ARC_PCS_config if we can relax. */ +static bfd_boolean +arc_can_relax_p (bfd *abfd) +{ + obj_attribute *attr = elf_known_obj_attributes_proc (abfd); + + if (attr[Tag_ARC_PCS_config].i & 0x100) + return TRUE; + return FALSE; +} + /* Relaxation hook. These are the current relaxing opportunities available: * R_ARC_GOTPC32 => R_ARC_PCREL. + * R_ARC_S25W_PCREL => R_ARC_S13_PCREL. -*/ + This is a two step relaxation procedure, in the first round, we + relax all the above opportunities. In the second round, we deal + with function align by removing unnecessary NOP_S placed by the + assembler. + + Inspired from CRX and RISCV backends. */ static bfd_boolean arc_elf_relax_section (bfd *abfd, asection *sec, @@ -2964,16 +3090,21 @@ arc_elf_relax_section (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, *irelend; bfd_byte *contents = NULL; Elf_Internal_Sym *isymbuf = NULL; + bfd_boolean do_relax = FALSE; /* Assume nothing changes. */ *again = FALSE; + /* Check if we can do size related relaxation. */ + do_relax = arc_can_relax_p (abfd); + /* We don't have to do anything for a relocatable link, if this section does not have relocs, or if this is not a code section. */ if (bfd_link_relocatable (link_info) || (sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 + || sec->sec_flg0 || (sec->flags & SEC_CODE) == 0) return TRUE; @@ -2989,45 +3120,78 @@ arc_elf_relax_section (bfd *abfd, asection *sec, irelend = internal_relocs + sec->reloc_count; for (irel = internal_relocs; irel < irelend; irel++) { - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_ARC_GOTPC32) - continue; + asection *sym_sec; + struct elf_link_hash_entry *htop = NULL; + bfd_vma symval; + + /* If this isn't something that can be relaxed, then ignore this + reloc. */ + if (ELF32_R_TYPE (irel->r_info) != (int) R_ARC_GOTPC32 + && ELF32_R_TYPE (irel->r_info) != (int) R_ARC_S25W_PCREL + && ELF32_R_TYPE (irel->r_info) != (int) R_ARC_ALIGN) + continue; /* Get the section contents if we haven't done so already. */ if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } + { + /* Get cached copy if it exists. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + /* Go get them off disk. */ + else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + goto error_return; + } /* Read this BFD's local symbols if we haven't done so already. */ if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - struct elf_link_hash_entry *htop = NULL; + { + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL) + isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (isymbuf == NULL) + goto error_return; + } - if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) + /* Get the value of the symbol referred to by the reloc. */ + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + { + /* A local symbol. */ + Elf_Internal_Sym *isym; + + isym = isymbuf + ELF32_R_SYM (irel->r_info); + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); + symval = isym->st_value; + /* If the reloc is absolute, it will not have + a symbol or section associated with it. */ + if (sym_sec) + symval += sym_sec->output_section->vma + + sym_sec->output_offset; + } + else { /* An external symbol. */ unsigned int indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; htop = elf_sym_hashes (abfd)[indx]; + + BFD_ASSERT (htop != NULL); + if (htop->root.type != bfd_link_hash_defined + && htop->root.type != bfd_link_hash_defweak) + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + continue; + + symval = (htop->root.u.def.value + + htop->root.u.def.section->output_section->vma + + htop->root.u.def.section->output_offset); + sym_sec = htop->root.u.def.section; } if (ELF32_R_TYPE (irel->r_info) == (int) R_ARC_GOTPC32 - && SYMBOL_REFERENCES_LOCAL (link_info, htop)) + && SYMBOL_REFERENCES_LOCAL (link_info, htop) + && link_info->relax_pass == 0) { unsigned int code; @@ -3053,7 +3217,101 @@ arc_elf_relax_section (bfd *abfd, asection *sec, bfd_put_32_me (abfd, code, contents + irel->r_offset - 4); /* The size isn't changed, don't redo. */ - *again = FALSE; + } + + /* Any of the next relax rules are changing the size, allow them + is assembler was informed. */ + if (!do_relax) + continue; + + if (ELF32_R_TYPE (irel->r_info) == (int) R_ARC_S25W_PCREL + && link_info->relax_pass == 0) + { + unsigned int code; + bfd_vma value = symval + irel->r_addend; + bfd_vma dot, gap; + + /* Get the address (PCL) of this instruction. */ + dot = (sec->output_section->vma + + sec->output_offset + irel->r_offset) & ~0x03; + + /* Compute the distance from this insn to the branch target. */ + gap = value - dot; + + /* Check if the gap falls in the range that can be + accomodated in 13bit signed range (32-bit aligned). */ + if ((int) gap < -4094 || (int) gap > 4097 || ((int) gap & 0x3) != 0) + continue; + + /* Get the opcode. */ + code = bfd_get_32_me (abfd, contents + irel->r_offset); + /* bl @symb@pcl -> bl_s @symb@pcl. */ + /* 0000 1sss ssss ss10 SSSS SSSS SSNR tttt. */ + BFD_ASSERT ((code & 0xF8030000) == 0x08020000); + + /* Check for delay slot bit. */ + if (code & 0x20) + continue; + + /* Note that we've changed the relocs, section contents, etc. */ + elf_section_data (sec)->relocs = internal_relocs; + elf_section_data (sec)->this_hdr.contents = contents; + symtab_hdr->contents = (unsigned char *) isymbuf; + + /* Fix the relocation's type. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_ARC_S13_PCREL); + + /* Write back bl_s instruction. */ + bfd_put_16 (abfd, 0xF800, contents + irel->r_offset); + /* Delete two bytes of data. */ + if (!arc_relax_delete_bytes (link_info, abfd, sec, + irel->r_offset + 2, 2)) + goto error_return; + + *again = TRUE; + } + + if (ELF32_R_TYPE (irel->r_info) == (int) R_ARC_ALIGN + && link_info->relax_pass == 1) + { + bfd_vma aligned_addr; + bfd_vma nop_bytes; + bfd_vma alignment = 4; + + if (irel->r_addend == 2) + alignment = 2; + aligned_addr = ((irel->r_offset - 1) & ~(alignment - 1)) + alignment; + nop_bytes = aligned_addr - irel->r_offset; + + /* Cannot remove more than we have left. */ + BFD_ASSERT (irel->r_addend >= nop_bytes); + /* I should be always 16bit multiple quantum. */ + BFD_ASSERT (nop_bytes == 0 || nop_bytes == 2); + + /* Once we aligned we cannot relax anything else. */ + sec->sec_flg0 = TRUE; + + /* Note that we've changed the relocs, section contents, etc. */ + elf_section_data (sec)->relocs = internal_relocs; + elf_section_data (sec)->this_hdr.contents = contents; + symtab_hdr->contents = (unsigned char *) isymbuf; + + /* Delete the relocation's type. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_ARC_NONE); + + /* Add an NOP_S if needed. */ + if (nop_bytes != 0) + bfd_put_16 (abfd, 0x78E0, contents + irel->r_offset); + + /* Delete nop_bytes bytes of data. */ + if (!arc_relax_delete_bytes (link_info, abfd, sec, + irel->r_offset + nop_bytes, + irel->r_addend - nop_bytes)) + goto error_return; + + *again = TRUE; } } @@ -3061,20 +3319,20 @@ arc_elf_relax_section (bfd *abfd, asection *sec, && symtab_hdr->contents != (unsigned char *) isymbuf) { if (!link_info->keep_memory) - free (isymbuf); + free (isymbuf); else - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; + /* Cache the symbols for elf_link_input_bfd. */ + symtab_hdr->contents = (unsigned char *) isymbuf; } if (contents != NULL && elf_section_data (sec)->this_hdr.contents != contents) { if (!link_info->keep_memory) - free (contents); + free (contents); else - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; } if (elf_section_data (sec)->relocs != internal_relocs) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 7271a2ad5a1..cb2aaf42572 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1900,6 +1900,17 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_ARC_S21H_PCREL_PLT", "BFD_RELOC_ARC_NPS_CMEM16", "BFD_RELOC_ARC_JLI_SECTOFF", + "BFD_RELOC_ARC_S7H_PCREL", + "BFD_RELOC_ARC_S8H_PCREL", + "BFD_RELOC_ARC_S9H_PCREL", + "BFD_RELOC_ARC_S10H_PCREL", + "BFD_RELOC_ARC_S13H_PCREL", + "BFD_RELOC_ARC_ALIGN", + "BFD_RELOC_ARC_ADD8", + "BFD_RELOC_ARC_ADD16", + "BFD_RELOC_ARC_SUB8", + "BFD_RELOC_ARC_SUB16", + "BFD_RELOC_ARC_SUB32", "BFD_RELOC_BFIN_16_IMM", "BFD_RELOC_BFIN_16_HIGH", "BFD_RELOC_BFIN_4_PCREL", diff --git a/bfd/reloc.c b/bfd/reloc.c index 4f4b95a0b7f..5831727700b 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3745,6 +3745,28 @@ ENUMX BFD_RELOC_ARC_NPS_CMEM16 ENUMX BFD_RELOC_ARC_JLI_SECTOFF +ENUMX + BFD_RELOC_ARC_S7H_PCREL +ENUMX + BFD_RELOC_ARC_S8H_PCREL +ENUMX + BFD_RELOC_ARC_S9H_PCREL +ENUMX + BFD_RELOC_ARC_S10H_PCREL +ENUMX + BFD_RELOC_ARC_S13H_PCREL +ENUMX + BFD_RELOC_ARC_ALIGN +ENUMX + BFD_RELOC_ARC_ADD8 +ENUMX + BFD_RELOC_ARC_ADD16 +ENUMX + BFD_RELOC_ARC_SUB8 +ENUMX + BFD_RELOC_ARC_SUB16 +ENUMX + BFD_RELOC_ARC_SUB32 ENUMDOC ARC relocs. diff --git a/binutils/readelf.c b/binutils/readelf.c index ad16b4571c9..a6d60258dab 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -15459,27 +15459,31 @@ display_arc_attribute (unsigned char * p, case Tag_ARC_PCS_config: READ_ULEB (val, p, end); printf (" Tag_ARC_PCS_config: "); - switch (val) + switch (val & 0xff) { case 0: - printf (_("Absent/Non standard\n")); + printf (_("Absent/Non standard")); break; case 1: - printf (_("Bare metal/mwdt\n")); + printf (_("Bare metal/mwdt")); break; case 2: - printf (_("Bare metal/newlib\n")); + printf (_("Bare metal/newlib")); break; case 3: - printf (_("Linux/uclibc\n")); + printf (_("Linux/uclibc")); break; case 4: - printf (_("Linux/glibc\n")); + printf (_("Linux/glibc")); break; default: - printf (_("Unknown\n")); + printf (_("Unknown")); break; } + if (val & 0x100) + printf (_(" -linkrelax-\n")); + else + printf (_("\n")); break; case Tag_ARC_CPU_base: diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c index 958eada844c..49a994c41f4 100644 --- a/gas/config/tc-arc.c +++ b/gas/config/tc-arc.c @@ -148,7 +148,12 @@ static int byte_order = DEFAULT_BYTE_ORDER; static segT arcext_section; /* By default relaxation is disabled. */ -static int relaxation_state = 0; +static bfd_boolean relaxation_state = FALSE; + +/* Status of the linker relaxation. It is a tristate variable: 0 is + non initialized/disabled, 1 is enabled, -1 forced disable (no PCS + attribute found). */ +static int do_linker_relax = 0; extern int arc_get_mach (char *); @@ -199,6 +204,7 @@ enum options OPTION_CD, OPTION_RELAX, OPTION_NPS400, + OPTION_LINKER_RELAX, OPTION_SPFP, OPTION_DPFP, @@ -243,6 +249,7 @@ struct option md_longopts[] = { "mcode-density", no_argument, NULL, OPTION_CD }, { "mrelax", no_argument, NULL, OPTION_RELAX }, { "mnps400", no_argument, NULL, OPTION_NPS400 }, + { "mlinker-relax", no_argument, NULL, OPTION_LINKER_RELAX }, /* Floating point options */ { "mspfp", no_argument, NULL, OPTION_SPFP}, @@ -2710,6 +2717,8 @@ md_begin (void) declare_addrtype ("csd", ARC_NPS400_ADDRTYPE_CSD); declare_addrtype ("cxa", ARC_NPS400_ADDRTYPE_CXA); declare_addrtype ("cxd", ARC_NPS400_ADDRTYPE_CXD); + + linkrelax = (do_linker_relax == 1) ? 1 : 0; } /* Write a value out to the object file, using the appropriate @@ -2788,6 +2797,11 @@ md_pcrel_from_section (fixS *fixP, case BFD_RELOC_ARC_S13_PCREL: case BFD_RELOC_ARC_S21W_PCREL: case BFD_RELOC_ARC_S25W_PCREL: + case BFD_RELOC_ARC_S10H_PCREL: + case BFD_RELOC_ARC_S13H_PCREL: + case BFD_RELOC_ARC_S9H_PCREL: + case BFD_RELOC_ARC_S8H_PCREL: + case BFD_RELOC_ARC_S7H_PCREL: base &= ~3; break; default: @@ -2903,7 +2917,6 @@ md_apply_fix (fixS *fixP, symbolS *fx_addsy, *fx_subsy; offsetT fx_offset; segT add_symbol_segment = absolute_section; - segT sub_symbol_segment = absolute_section; const struct arc_operand *operand = NULL; extended_bfd_reloc_code_real_type reloc; @@ -2922,34 +2935,9 @@ md_apply_fix (fixS *fixP, add_symbol_segment = S_GET_SEGMENT (fx_addsy); } - if (fx_subsy - && fixP->fx_r_type != BFD_RELOC_ARC_TLS_DTPOFF - && fixP->fx_r_type != BFD_RELOC_ARC_TLS_DTPOFF_S9 - && fixP->fx_r_type != BFD_RELOC_ARC_TLS_GD_LD) - { - resolve_symbol_value (fx_subsy); - sub_symbol_segment = S_GET_SEGMENT (fx_subsy); - - if (sub_symbol_segment == absolute_section) - { - /* The symbol is really a constant. */ - fx_offset -= S_GET_VALUE (fx_subsy); - fx_subsy = NULL; - } - else - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("can't resolve `%s' {%s section} - `%s' {%s section}"), - fx_addsy ? S_GET_NAME (fx_addsy) : "0", - segment_name (add_symbol_segment), - S_GET_NAME (fx_subsy), - segment_name (sub_symbol_segment)); - return; - } - } - if (fx_addsy - && !S_IS_WEAK (fx_addsy)) + && !S_IS_WEAK (fx_addsy) + && !fx_subsy) { if (add_symbol_segment == seg && fixP->fx_pcrel) @@ -3119,6 +3107,11 @@ md_apply_fix (fixS *fixP, case BFD_RELOC_ARC_S21H_PCREL: case BFD_RELOC_ARC_S25H_PCREL: case BFD_RELOC_ARC_S13_PCREL: + case BFD_RELOC_ARC_S10H_PCREL: + case BFD_RELOC_ARC_S13H_PCREL: + case BFD_RELOC_ARC_S9H_PCREL: + case BFD_RELOC_ARC_S8H_PCREL: + case BFD_RELOC_ARC_S7H_PCREL: solve_plt: operand = find_operand_for_reloc (reloc); gas_assert (operand); @@ -3470,7 +3463,13 @@ md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED) break; case OPTION_RELAX: - relaxation_state = 1; + relaxation_state = TRUE; + do_linker_relax = -1; + break; + + case OPTION_LINKER_RELAX: + relaxation_state = FALSE; + do_linker_relax = (do_linker_relax == 0) ? 1 : do_linker_relax; break; case OPTION_NPS400: @@ -4171,26 +4170,64 @@ assemble_insn (const struct arc_opcode *opcode, arc_last_insns[0].opcode->name); } +static void +arc_make_nops (char *buf, bfd_vma bytes) +{ + bfd_vma i = 0; + + /* ARC instructions cannot begin or end on odd addresses, so this case + means we are not within a valid instruction sequence. It is thus safe + to use a zero byte, even though that is not a valid instruction. */ + if (bytes % 2 == 1) + buf[i++] = 0; + + /* Use 2-byte NOP. */ + for ( ; i < bytes; i += 2) + md_number_to_chars_midend (buf + i, NOP_OPCODE_S, 2); +} + +/* Implement HANDLE_ALIGN. */ + void arc_handle_align (fragS* fragP) { - if ((fragP)->fr_type == rs_align_code) + char *dest = (fragP)->fr_literal + (fragP)->fr_fix; + valueT count = ((fragP)->fr_next->fr_address + - (fragP)->fr_address - (fragP)->fr_fix); + bfd_signed_vma size = count & ~0x01; + bfd_signed_vma excess = count & 0x01; + expressionS ex; + + if (fragP->fr_type != rs_align_code) + return; + + if (count <= 0) + return; + + /* Insert zeros to get 2 byte alignment. */ + if (excess && fragP->fr_type == rs_align_code) { - char *dest = (fragP)->fr_literal + (fragP)->fr_fix; - valueT count = ((fragP)->fr_next->fr_address - - (fragP)->fr_address - (fragP)->fr_fix); + arc_make_nops (dest, excess); + fragP->fr_fix += excess; + dest += excess; + } - (fragP)->fr_var = 2; + /* Only emit this reloc when linker relaxation is required. */ + if (linkrelax && size) + { + ex.X_op = O_constant; + ex.X_add_number = size; + fix_new_exp (fragP, fragP->fr_fix, 0, &ex, FALSE, BFD_RELOC_ARC_ALIGN); + } + else + { + if (size > MAX_MEM_FOR_RS_ALIGN_CODE) + size &= MAX_MEM_FOR_RS_ALIGN_CODE; - if (count & 1)/* Padding in the gap till the next 2-byte - boundary with 0s. */ - { - (fragP)->fr_fix++; - *dest++ = 0; - } - /* Writing nop_s. */ - md_number_to_chars (dest, NOP_OPCODE_S, 2); + /* Insert variable number of 2 bytes NOPs. */ + arc_make_nops (dest, size); } + fragP->fr_fix += size; } /* Here we decide which fixups can be adjusted to make them relative @@ -4202,7 +4239,6 @@ arc_handle_align (fragS* fragP) int tc_arc_fix_adjustable (fixS *fixP) { - /* Prevent all adjustments to global symbols. */ if (S_IS_EXTERNAL (fixP->fx_addsy)) return 0; @@ -4224,7 +4260,7 @@ tc_arc_fix_adjustable (fixS *fixP) break; } - return 1; + return !linkrelax; } /* Compute the reloc type of an expression EXP. */ @@ -4255,23 +4291,88 @@ arc_cons_fix_new (fragS *frag, switch (size) { case 1: - r_type = BFD_RELOC_8; + if (exp->X_op == O_subtract && exp->X_op_symbol != NULL && linkrelax) + { + if (S_IS_LOCAL (exp->X_add_symbol) && S_IS_LOCAL (exp->X_op_symbol)) + { + expressionS exps; + memcpy (&exps, exp, sizeof (expressionS)); + exps.X_op = O_symbol; + exps.X_add_symbol = exp->X_op_symbol; + exps.X_op_symbol = NULL; + exp->X_op_symbol = NULL; + exp->X_op = O_symbol; + fix_new_exp (frag, off, size, exp, 0, BFD_RELOC_ARC_ADD8); + fix_new_exp (frag, off, size, &exps, 0, BFD_RELOC_ARC_SUB8); + return; + } + else + as_bad_where (frag->fr_file, frag->fr_line, + _("Unknown substract operation. " + "Cannot generate reloc")); + } + else + r_type = BFD_RELOC_8; break; case 2: - r_type = BFD_RELOC_16; + if (exp->X_op == O_subtract && exp->X_op_symbol != NULL && linkrelax) + { + if (S_IS_LOCAL (exp->X_add_symbol) && S_IS_LOCAL (exp->X_op_symbol)) + { + expressionS exps; + memcpy (&exps, exp, sizeof (expressionS)); + exps.X_op = O_symbol; + exps.X_add_symbol = exp->X_op_symbol; + exps.X_op_symbol = NULL; + exp->X_op_symbol = NULL; + exp->X_op = O_symbol; + fix_new_exp (frag, off, size, exp, 0, BFD_RELOC_ARC_ADD16); + fix_new_exp (frag, off, size, &exps, 0, BFD_RELOC_ARC_SUB16); + return; + } + else + as_bad_where (frag->fr_file, frag->fr_line, + _("Unknown substract operation. " + "Cannot generate reloc")); + } + else + r_type = BFD_RELOC_16; break; case 3: + gas_assert (!linkrelax); r_type = BFD_RELOC_24; break; case 4: - r_type = BFD_RELOC_32; + if (exp->X_op == O_subtract && exp->X_op_symbol != NULL && linkrelax) + { + if (S_IS_LOCAL (exp->X_add_symbol) && S_IS_LOCAL (exp->X_op_symbol)) + { + expressionS exps; + memcpy (&exps, exp, sizeof (expressionS)); + exps.X_op = O_symbol; + exps.X_add_symbol = exp->X_op_symbol; + exps.X_op_symbol = NULL; + exp->X_op_symbol = NULL; + exp->X_op = O_symbol; + fix_new_exp (frag, off, size, exp, 0, BFD_RELOC_32); + fix_new_exp (frag, off, size, &exps, 0, BFD_RELOC_ARC_SUB32); + return; + } + else + as_bad_where (frag->fr_file, frag->fr_line, + _("Unknown substract operation. " + "Cannot generate reloc")); + } + else + r_type = BFD_RELOC_32; arc_check_reloc (exp, &r_type); break; case 8: + gas_assert (!linkrelax); r_type = BFD_RELOC_64; break; @@ -5059,6 +5160,17 @@ arc_set_public_attributes (void) "register file")); bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_ABI_rf16, 0); } + + /* Tag_ARC_PCS_config. */ + if (attributes_set_explicitly[Tag_ARC_PCS_config]) + { + int val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC, + Tag_ARC_PCS_config); + val |= (do_linker_relax == 1) ? 0x100 : 0x00; + bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_PCS_config, val); + } + else if (do_linker_relax == 1) + arc_set_attribute_int (Tag_ARC_PCS_config, 0x100); } /* Add the default contents for the .ARC.attributes section. */ @@ -5119,6 +5231,26 @@ int arc_convert_symbolic_attribute (const char *name) return -1; } +/* Implements md_allow_local_substract. */ + +bfd_boolean arc_allow_local_subtract (expressionS * left, + expressionS * right, + segT section) +{ + /* if we don't relax allow substraction. */ + if (!linkrelax) + return TRUE; + + /* if the symbols are not in a code section then they are OK. */ + if ((section->flags & SEC_CODE) == 0) + return TRUE; + + if (left->X_add_symbol == right->X_add_symbol) + return TRUE; + + return FALSE; +} + /* Local variables: eval: (c-set-style "gnu") indent-tabs-mode: t diff --git a/gas/config/tc-arc.h b/gas/config/tc-arc.h index d12a466f106..9c6e59248ef 100644 --- a/gas/config/tc-arc.h +++ b/gas/config/tc-arc.h @@ -125,6 +125,10 @@ extern const char *arc_target_format; #define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC) \ arc_cons_fix_new ((FRAG), (OFF), (LEN), (EXP), (RELOC)) +/* We don't want to do any fixup when linker is relaxing. */ +#define TC_LINKRELAX_FIXUP(SEG) 1 +#define LINKER_RELAXING_SHRINKS_ONLY 1 + /* We don't want gas to fixup the following program memory related relocations. Check also that fx_addsy is not NULL, in order to make sure that the fixup refers to some sort of label. */ @@ -134,26 +138,21 @@ extern const char *arc_target_format; || FIXP->fx_r_type == BFD_RELOC_ARC_S25W_PCREL_PLT \ || FIXP->fx_r_type == BFD_RELOC_ARC_S25H_PCREL_PLT \ || FIXP->fx_r_type == BFD_RELOC_ARC_S21W_PCREL_PLT \ - || FIXP->fx_r_type == BFD_RELOC_ARC_S21H_PCREL_PLT) \ - && FIXP->fx_addsy != NULL \ - && FIXP->fx_subsy == NULL) \ + || FIXP->fx_r_type == BFD_RELOC_ARC_S21H_PCREL_PLT \ + || (linkrelax \ + && (FIXP->fx_r_type == BFD_RELOC_ARC_S7H_PCREL \ + || FIXP->fx_r_type == BFD_RELOC_ARC_S8H_PCREL))) \ + && (FIXP->fx_addsy != NULL) \ + && (FIXP->fx_subsy == NULL)) \ { \ symbol_mark_used_in_reloc (FIXP->fx_addsy); \ goto SKIP; \ } -/* BFD_RELOC_ARC_TLS_GD_LD may use fx_subsy to store a label that is - later turned into fx_offset. */ -#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \ - ((FIX)->fx_r_type == BFD_RELOC_ARC_TLS_GD_LD) - -#define TC_VALIDATE_FIX_SUB(FIX, SEG) \ - ((md_register_arithmetic || (SEG) != reg_section) \ - && ((FIX)->fx_r_type == BFD_RELOC_GPREL32 \ - || (FIX)->fx_r_type == BFD_RELOC_GPREL16 \ - || (FIX)->fx_r_type == BFD_RELOC_ARC_TLS_DTPOFF \ - || (FIX)->fx_r_type == BFD_RELOC_ARC_TLS_DTPOFF_S9 \ - || TC_FORCE_RELOCATION_SUB_LOCAL (FIX, SEG))) +/* The difference between same-section symbols may be affected by linker + relaxation, so do not resolve such expressions in the assembler. */ +#define md_allow_local_subtract(l,r,s) arc_allow_local_subtract(l, r, s) +extern bfd_boolean arc_allow_local_subtract (expressionS *, expressionS *, segT); /* We use this to mark the end-loop label. We use this mark for ZOL validity checks. */ diff --git a/gas/write.c b/gas/write.c index 95922bb25a0..3329a5df55c 100644 --- a/gas/write.c +++ b/gas/write.c @@ -2632,7 +2632,8 @@ relax_frag (segT segment, fragS *fragP, long stretch) lowest order bits all 0s, return size of adjustment made. */ static relax_addressT relax_align (relax_addressT address, /* Address now. */ - int alignment /* Alignment (binary). */) + int alignment, /* Alignment (binary). */ + enum _relax_state fr_type) { relax_addressT mask; relax_addressT new_address; @@ -2640,7 +2641,7 @@ relax_align (relax_addressT address, /* Address now. */ mask = ~((relax_addressT) ~0 << alignment); new_address = (address + mask) & (~mask); #ifdef LINKER_RELAXING_SHRINKS_ONLY - if (linkrelax) + if (linkrelax && fr_type == rs_align_code) /* We must provide lots of padding, so the linker can discard it when needed. The linker will not add extra space, ever. */ new_address += (1 << alignment); @@ -2693,7 +2694,8 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass) case rs_align_code: case rs_align_test: { - addressT offset = relax_align (address, (int) fragP->fr_offset); + addressT offset = relax_align (address, (int) fragP->fr_offset, + fragP->fr_type); if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype) offset = 0; @@ -2910,9 +2912,9 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass) addressT oldoff, newoff; oldoff = relax_align (was_address + fragP->fr_fix, - (int) offset); + (int) offset, fragP->fr_type); newoff = relax_align (address + fragP->fr_fix, - (int) offset); + (int) offset, fragP->fr_type); if (fragP->fr_subtype != 0) { diff --git a/include/elf/arc-reloc.def b/include/elf/arc-reloc.def index 7d1e868fd7c..2ee4983cbe4 100644 --- a/include/elf/arc-reloc.def +++ b/include/elf/arc-reloc.def @@ -90,7 +90,7 @@ ARC_RELOC_HOWTO(ARC_N32, 11, \ 32, \ replace_word32, \ bitfield, \ - ( A - S )) + ( A - S)) ARC_RELOC_HOWTO(ARC_SDA, 12, \ 2, \ @@ -511,3 +511,80 @@ ARC_RELOC_HOWTO(ARC_NPS_CMEM16, 78, \ replace_bits16, \ dont, \ ( ME ( S + A ))) + +ARC_RELOC_HOWTO(ARC_S9H_PCREL, 80, \ + 2, \ + 8, \ + replace_bits9, \ + signed, \ + ( ME ( ( ( ( S + A ) - P ) >> 1 ) ) ) ) + +ARC_RELOC_HOWTO(ARC_S7H_PCREL, 81, \ + 1, \ + 6, \ + replace_bits7, \ + signed, \ + ( ( ( ( S + A ) - P ) >> 1 ) ) ) + +ARC_RELOC_HOWTO(ARC_S8H_PCREL, 82, \ + 1, \ + 7, \ + replace_disp8h, \ + signed, \ + ( ( ( ( S + A ) - P ) >> 1 ) ) ) + +ARC_RELOC_HOWTO(ARC_S10H_PCREL, 83, \ + 1, \ + 9, \ + replace_bits10, \ + signed, \ + ( ( ( ( S + A ) - P ) >> 1 ) ) ) + +ARC_RELOC_HOWTO(ARC_S13H_PCREL, 84, \ + 2, \ + 12, \ + replace_bits13, \ + signed, \ + ( ME ( ( ( ( S + A ) - P ) >> 1 ) ) ) ) + +ARC_RELOC_HOWTO(ARC_ALIGN, 85, \ + 2, \ + 0, \ + replace_none, \ + dont, \ + 0 ) + +ARC_RELOC_HOWTO(ARC_ADD8, 86, \ + 0, \ + 8, \ + replace_bits8, \ + dont, \ + ( S + A )) + +ARC_RELOC_HOWTO(ARC_ADD16, 87, \ + 1, \ + 16, \ + replace_bits16, \ + dont, \ + ( S + A )) + +ARC_RELOC_HOWTO(ARC_SUB8, 88, \ + 0, \ + 8, \ + replace_bits8, \ + dont, \ + ( A - S + ICARRY )) + +ARC_RELOC_HOWTO(ARC_SUB16, 89, \ + 1, \ + 16, \ + replace_bits16, \ + dont, \ + ( A - S + ICARRY )) + +ARC_RELOC_HOWTO(ARC_SUB32, 90, \ + 2, \ + 32, \ + replace_word32, \ + dont, \ + ( A - S + ICARRY)) diff --git a/include/opcode/arc-func.h b/include/opcode/arc-func.h index c16dbf3fe4f..f79d3538770 100644 --- a/include/opcode/arc-func.h +++ b/include/opcode/arc-func.h @@ -292,3 +292,75 @@ replace_jli (unsigned insn, int value) } #endif /* REPLACE_jli */ + +#ifndef REPLACE_bits9 +#define REPLACE_bits9 +/* mask = 0000 0000 1111 1110 2000 0000 0000 0000. */ +static unsigned +replace_bits9 (unsigned insn, int value) +{ + insn = insn & ~0x00fe8000; + insn |= ((value >> 0) & 0x007f) << 17; + insn |= ((value >> 7) & 0x0001) << 15; + + return insn; +} +#endif /* REPLACE_bits9 */ + +#ifndef REPLACE_bits10 +#define REPLACE_bits10 +/* mask = 0000000111111111 + insn = 1111001sssssssss. */ +static unsigned +replace_bits10 (unsigned insn, int value) +{ + insn &= ~0x01ff; + insn |= value & 0x01ff; + + return insn; +} +#endif /* REPLACE_bits10 */ + +#ifndef REPLACE_bits7 +#define REPLACE_bits7 +/* mask = 0000000000111111 + insn = 1111011000ssssss. */ +static unsigned +replace_bits7 (unsigned insn, int value) +{ + insn &= ~0x003f; + insn |= value & 0x003f; + + return insn; +} +#endif /* REPLACE_bits7 */ + +#ifndef REPLACE_disp8h +#define REPLACE_disp8h +/* mask = 0000000001111111 + insn = 11101bbb1sssssss. */ +static unsigned +replace_disp8h (unsigned insn, int value) +{ + insn &= ~0x7f; + insn |= value & 0x007f; + + return insn; +} +#endif /* REPLACE_disp8h */ + +#ifndef REPLACE_bits13 +#define REPLACE_bits13 +/* mask = 00000000000000000000111111222222 + insn = 00100RRR101010000RRRssssssSSSSSS. */ +static unsigned +replace_bits13 (unsigned insn, int value) +{ + + insn &= ~0x0FFF; + insn |= ((value) & 0x003f) << 6; + insn |= ((value >> 6) & 0x003f) << 0; + + return insn; +} +#endif /* REPLACE_bits13 */ diff --git a/ld/emulparams/arcelf.sh b/ld/emulparams/arcelf.sh index 625ec397790..06c7e1a79d1 100644 --- a/ld/emulparams/arcelf.sh +++ b/ld/emulparams/arcelf.sh @@ -21,3 +21,4 @@ OTHER_SECTIONS="/DISCARD/ : { *(.__arc_profile_*) }" EMBEDDED=yes GENERATE_SHLIB_SCRIPT=yes +EXTRA_EM_FILE=arcelf diff --git a/ld/emulparams/arcv2elf.sh b/ld/emulparams/arcv2elf.sh index 4824f3540c8..4a21daec759 100644 --- a/ld/emulparams/arcv2elf.sh +++ b/ld/emulparams/arcv2elf.sh @@ -24,4 +24,4 @@ TEXT_START_ADDR=0x100 ENTRY=__start SDATA_START_SYMBOLS='__SDATA_BEGIN__ = . + 0x100;' JLI_START_TABLE='__JLI_TABLE__ = .;' -OTHER_SECTIONS="/DISCARD/ : { *(.__arc_profile_*) }" +EXTRA_EM_FILE=arcelf diff --git a/ld/emulparams/arcv2elfx.sh b/ld/emulparams/arcv2elfx.sh index ad134441255..3477e74a604 100644 --- a/ld/emulparams/arcv2elfx.sh +++ b/ld/emulparams/arcv2elfx.sh @@ -20,5 +20,5 @@ TEXT_START_ADDR=0x100 ENTRY=__start SDATA_START_SYMBOLS='__SDATA_BEGIN__ = . + 0x100;' JLI_START_TABLE='__JLI_TABLE__ = .;' -OTHER_SECTIONS="/DISCARD/ : { *(.__arc_profile_*) }" EMBEDDED=yes +EXTRA_EM_FILE=arcelf diff --git a/ld/emultempl/arcelf.em b/ld/emultempl/arcelf.em new file mode 100644 index 00000000000..035d25d3cf5 --- /dev/null +++ b/ld/emultempl/arcelf.em @@ -0,0 +1,40 @@ +# This shell script emits a C file. -*- C -*- +# Copyright (C) 2019 Free Software Foundation, Inc. +# +# Copyright 2019 Synopsys Inc. +# +# This file is part of GLD, the Gnu Linker. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +# This file is sourced from elf32.em, and defines extra arcelf +# specific routines. +# +fragment <: + 100: f801 bl_s 4 ;104 + 100: R_ARC_S13_PCREL foo + 100: R_ARC_NONE \*ABS\*\+0x4 + 102: f801 bl_s 4 ;104 + 102: R_ARC_S13_PCREL foo + +00000104 : + 104: 2000 0000 add r0,r0,r0 + 104: R_ARC_NONE \*ABS\*\+0x6 diff --git a/ld/testsuite/ld-arc/relax-call-1.s b/ld/testsuite/ld-arc/relax-call-1.s new file mode 100644 index 00000000000..6993ae46f26 --- /dev/null +++ b/ld/testsuite/ld-arc/relax-call-1.s @@ -0,0 +1,14 @@ + .arc_attribute Tag_ARC_PCS_config, 2 + .section .text + .align 4 + .global __start + .type __start, @function +__start: + bl @foo + bl_s @foo + .size __start, .-__start + + .align 4 +foo: + add r0,r0,r0 + .size foo, .-foo diff --git a/ld/testsuite/ld-arc/relax-call-2.d b/ld/testsuite/ld-arc/relax-call-2.d new file mode 100644 index 00000000000..b72ca1d4a4d --- /dev/null +++ b/ld/testsuite/ld-arc/relax-call-2.d @@ -0,0 +1,27 @@ +#source: relax-call-2.s +#as: -mlinker-relax +#ld: -q -A elf32-arclittle -relax +#objdump: -dr + +[^:]+: file format elf32-.*arc + + +Disassembly of section \.text: + +00000100 <__start>: + [0-9a-f]+:\s+2000 0000\s+add.* +\s+100: R_ARC_NONE\s+\*ABS\*\+0x4 + [0-9a-f]+:\s+f801\s+bl_s\s+4\s+;[0-9a-f]+ +\s+104: R_ARC_S13_PCREL\s+foo + [0-9a-f]+:\s+78e0\s.* +\s+106: R_ARC_NONE\s+\*ABS\*\+0x4 + +00000108 : + [0-9a-f]+:\s+2000 0000\s+add.* + [0-9a-f]+:\s+fffd\s+bl_s\s+-12\s+;[0-9a-f]+ <__start> +\s+10c: R_ARC_S13_PCREL\s+__start + [0-9a-f]+:\s+78e0\s.* +\s+10e: R_ARC_NONE\s+\*ABS\*\+0x6 + +00000110 : + [0-9a-f]+:\s+2000 0000\s+add.* diff --git a/ld/testsuite/ld-arc/relax-call-2.s b/ld/testsuite/ld-arc/relax-call-2.s new file mode 100644 index 00000000000..8f5204e2c5a --- /dev/null +++ b/ld/testsuite/ld-arc/relax-call-2.s @@ -0,0 +1,23 @@ + .section .text + .align 4 + .global __start + .type __start, @function +__start: + add r0,r0,r0 + bl @foo + .size __start, .-__start + + .align 4 + .global foo + .type foo, @function +foo: + add r0,r0,r0 + bl_s @__start + .size foo, .-foo + + .align 4 + .global goo + .type goo, @function +goo: + add r0,r0,r0 + .size goo, .-goo diff --git a/ld/testsuite/ld-arc/relax-call-3.d b/ld/testsuite/ld-arc/relax-call-3.d new file mode 100644 index 00000000000..0e596091035 --- /dev/null +++ b/ld/testsuite/ld-arc/relax-call-3.d @@ -0,0 +1,36 @@ +#source: relax-call-3.s +#as: -mlinker-relax +#ld: -q -A elf32-arclittle -relax +#objdump: -dr + +[^:]+: file format elf32-.*arc + + +Disassembly of section \.text: + +00000100 <__start>: + [01]+: f803 bl_s 12 ;10c +\s+100: R_ARC_S13_PCREL foo +\s+100: R_ARC_NONE \*ABS\*\+0x4 + +00000102 <.L1>: + 102: 0002 0000.* +\s+102: R_ARC_32 \.L1 +\s+102: R_ARC_SUB32 \.L0 + 106: 0002 0002.* +\s+106: R_ARC_ADD16 \.L1 +\s+106: R_ARC_SUB16 \.L0 +\s+108: R_ARC_ADD8 \.L1 +\s+108: R_ARC_SUB8 \.L0 + 10a: 78e0\s+nop_s +\s+10a: R_ARC_NONE \*ABS\*\+0x4 + +0000010c : + 10c: 2000 0000 add r0,r0,r0 + 110: fffc bl_s -16 ;100 <__start> +\s+110: R_ARC_S13_PCREL __start + 112: 78e0\s+nop_s +\s+112: R_ARC_NONE \*ABS\*\+0x6 + +00000114 : + 114: 2000 0000 add r0,r0,r0 diff --git a/ld/testsuite/ld-arc/relax-call-3.s b/ld/testsuite/ld-arc/relax-call-3.s new file mode 100644 index 00000000000..371949ba6e1 --- /dev/null +++ b/ld/testsuite/ld-arc/relax-call-3.s @@ -0,0 +1,27 @@ + .section .text + .align 4 + .global __start + .type __start, @function +__start: +.L0: + bl @foo +.L1: + .word @.L1 - @.L0 + .hword @.L1 - @.L0 + .byte @.L1 - @.L0 + .size __start, .-__start + + .align 4 + .global foo + .type foo, @function +foo: + add r0,r0,r0 + bl_s @__start + .size foo, .-foo + + .align 4 + .global goo + .type goo, @function +goo: + add r0,r0,r0 + .size goo, .-goo diff --git a/opcodes/arc-opc.c b/opcodes/arc-opc.c index 14a1a3bfcf5..58f6274e199 100644 --- a/opcodes/arc-opc.c +++ b/opcodes/arc-opc.c @@ -2021,7 +2021,7 @@ const struct arc_operand arc_operands[] = /* SIMM9_A16_8 mask = 00000000111111102000000000000000. */ #define SIMM9_A16_8 (UIMM5_11_S + 1) - {9, 0, -SIMM9_A16_8, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 + {9, 0, BFD_RELOC_ARC_S9H_PCREL, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 | ARC_OPERAND_PCREL | ARC_OPERAND_TRUNCATE, insert_simm9_a16_8, extract_simm9_a16_8}, @@ -2043,7 +2043,7 @@ const struct arc_operand arc_operands[] = /* SIMM10_A16_7_S mask = 0000000111111111. */ #define SIMM10_A16_7_S (SIMM25_A16_5 + 1) - {10, 0, -SIMM10_A16_7_S, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 + {10, 0, BFD_RELOC_ARC_S10H_PCREL, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 | ARC_OPERAND_TRUNCATE | ARC_OPERAND_PCREL, insert_simm10_a16_7_s, extract_simm10_a16_7_s}, @@ -2053,7 +2053,7 @@ const struct arc_operand arc_operands[] = /* SIMM7_A16_10_S mask = 0000000000111111. */ #define SIMM7_A16_10_S (SIMM10_A16_7_Sbis + 1) - {7, 0, -SIMM7_A16_10_S, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 + {7, 0, BFD_RELOC_ARC_S7H_PCREL, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 | ARC_OPERAND_TRUNCATE | ARC_OPERAND_PCREL, insert_simm7_a16_10_s, extract_simm7_a16_10_s}, @@ -2077,7 +2077,7 @@ const struct arc_operand arc_operands[] = /* SIMM8_A16_9_S mask = 0000000001111111. */ #define SIMM8_A16_9_S (SIMM13_A32_5_S + 1) - {8, 0, -SIMM8_A16_9_S, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 + {8, 0, BFD_RELOC_ARC_S8H_PCREL, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 | ARC_OPERAND_TRUNCATE | ARC_OPERAND_PCREL, insert_simm8_a16_9_s, extract_simm8_a16_9_s}, @@ -2158,7 +2158,7 @@ const struct arc_operand arc_operands[] = /* SIMM13_A16_20 mask = 00000000000000000000111111222222. */ #define SIMM13_A16_20 (UIMM7_A16_20 + 1) - {13, 0, -SIMM13_A16_20, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 + {13, 0, BFD_RELOC_ARC_S13H_PCREL, ARC_OPERAND_SIGNED | ARC_OPERAND_ALIGNED16 | ARC_OPERAND_TRUNCATE | ARC_OPERAND_PCREL, insert_simm13_a16_20, extract_simm13_a16_20}, From a23bf9b30b816c30877d832e9e10bb9ce608cd56 Mon Sep 17 00:00:00 2001 From: Claudiu Zissulescu Date: Wed, 24 Jul 2019 17:01:21 +0300 Subject: [PATCH 2/4] binutils: Relaxation fix in mainline --- bfd/elflink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bfd/elflink.c b/bfd/elflink.c index 27564adb8c3..b62e97025e4 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -13580,7 +13580,7 @@ elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED, /* Return the local debug definition section. */ asection *isec = bfd_section_from_elf_index (sec->owner, sym->st_shndx); - if ((isec->flags & SEC_DEBUGGING) != 0) + if (isec && (isec->flags & SEC_DEBUGGING) != 0) return isec; } From 38b6b3944f818a58792a572d46773adf4e332194 Mon Sep 17 00:00:00 2001 From: Cupertino Miranda Date: Mon, 15 Jun 2020 16:43:04 +0100 Subject: [PATCH 3/4] Avoid creating dynamic relocations for debug sections. --- bfd/elf32-arc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c index 4b34e5b40f5..cafdd597e7d 100644 --- a/bfd/elf32-arc.c +++ b/bfd/elf32-arc.c @@ -1442,6 +1442,9 @@ elf_arc_relocate_section (bfd * output_bfd, Elf_Internal_Rela * relend; struct elf_link_hash_table * htab = elf_hash_table (info); + if((input_section->flags & SEC_DEBUGGING) != 0) + return TRUE; + symtab_hdr = &((elf_tdata (input_bfd))->symtab_hdr); sym_hashes = elf_sym_hashes (input_bfd); @@ -1959,6 +1962,12 @@ elf_arc_check_relocs (bfd * abfd, asection * sreloc = NULL; struct elf_link_hash_table * htab = elf_hash_table (info); + if((sec->flags & SEC_DEBUGGING) != 0) + { + BFD_ASSERT((sec->flags & SEC_DEBUGGING) != 0); + return TRUE; + } + if (bfd_link_relocatable (info)) return TRUE; From b5273ea68e58f745110350a22b1e295acfe08af2 Mon Sep 17 00:00:00 2001 From: Cupertino Miranda Date: Fri, 7 Aug 2020 13:30:21 +0100 Subject: [PATCH 4/4] This fix improves on ARC_NONE and remove .rela for debug sections. --- bfd/elf32-arc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c index cafdd597e7d..7c596eafd77 100644 --- a/bfd/elf32-arc.c +++ b/bfd/elf32-arc.c @@ -1791,8 +1791,7 @@ elf_arc_relocate_section (bfd * output_bfd, && (!IS_ARC_PCREL_TYPE (r_type) || (h != NULL && h->dynindx != -1 - && !h->def_regular - && (!info->symbolic || !h->def_regular)))) + && (!SYMBOL_REFERENCES_LOCAL (info, h))))) { Elf_Internal_Rela outrel; bfd_byte *loc; @@ -2049,10 +2048,12 @@ elf_arc_check_relocs (bfd * abfd, /* FALLTHROUGH */ case R_ARC_PC32: case R_ARC_32_PCREL: - if ((bfd_link_pic (info)) - && ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL) - || (h != NULL - && (!info->symbolic || !h->def_regular)))) + + if (!bfd_link_pic (info)) + break; + + if (((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL) + || (!SYMBOL_REFERENCES_LOCAL (info, h)))) { if (sreloc == NULL) {