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..7c596eafd77 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 @@ -1440,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); @@ -1786,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; @@ -1957,6 +1961,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; @@ -2038,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) { @@ -2947,13 +2959,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 +3100,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 +3130,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 +3227,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 +3329,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/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; } 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},