From ef551643dc282159185cb9916c7cb0308ae03cdd Mon Sep 17 00:00:00 2001 From: Claudiu Zissulescu Date: Wed, 24 Jul 2019 16:33:29 +0300 Subject: [PATCH] [ARC] Add linker relaxation. Add linker relaxation. The first relaxation added is converting GOTPC32 to PCREL relocations. This relaxation doesn't change the size of the binary. bfd/ xxxx-xx-xx Claudiu Zissulescu * elf32-arc.c (bfd_get_32_me): New function. (bfd_put_32_me): Likewise. (arc_elf_relax_section): Likewise. (bfd_elf32_bfd_relax_section): Define. ld/testsuite/ xxxx-xx-xx Claudiu Zissulescu * ld-arc/relax-local-pic.d: New test. * ld-arc/relax-local-pic.s: New file. --- bfd/ChangeLog | 7 + bfd/elf32-arc.c | 176 ++++++++++++++++++++++++++ ld/ChangeLog | 5 + ld/testsuite/ld-arc/relax-local-pic.d | 14 ++ ld/testsuite/ld-arc/relax-local-pic.s | 16 +++ 5 files changed, 218 insertions(+) create mode 100644 ld/testsuite/ld-arc/relax-local-pic.d create mode 100644 ld/testsuite/ld-arc/relax-local-pic.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6d7e42510a..50027c63f3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2019-07-24 Claudiu Zissulescu + + * elf32-arc.c (bfd_get_32_me): New function. + (bfd_put_32_me): Likewise. + (arc_elf_relax_section): Likewise. + (bfd_elf32_bfd_relax_section): Define. + 2019-07-24 Alan Modra * elf-bfd.h (struct elf_backend_data): Return bfd_boolean from diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c index c7ffc6a6f9..b069e3fda5 100644 --- a/bfd/elf32-arc.c +++ b/bfd/elf32-arc.c @@ -96,6 +96,31 @@ reloc_type_to_name (unsigned int type) #define USE_REL 1 +static bfd_vma +bfd_get_32_me (bfd * abfd,const unsigned char * data) +{ + bfd_vma value = 0; + + if (bfd_big_endian(abfd)) { + value = bfd_get_32 (abfd, data); + } + else { + value = ((bfd_get_8 (abfd, data) & 255) << 16); + value |= ((bfd_get_8 (abfd, data + 1) & 255) << 24); + value |= (bfd_get_8 (abfd, data + 2) & 255); + value |= ((bfd_get_8 (abfd, data + 3) & 255) << 8); + } + + return value; +} + +static void +bfd_put_32_me (bfd *abfd, bfd_vma value,unsigned char *data) +{ + bfd_put_16 (abfd, (value & 0xffff0000) >> 16, data); + bfd_put_16 (abfd, value & 0xffff, data + 2); +} + static ATTRIBUTE_UNUSED bfd_boolean is_reloc_PC_relative (reloc_howto_type *howto) { @@ -2968,6 +2993,156 @@ elf32_arc_section_from_shdr (bfd *abfd, return TRUE; } +/* Relaxation hook. + + These are the current relaxing opportunities available: + + * R_ARC_GOTPC32 => R_ARC_PCREL. + +*/ + +static bfd_boolean +arc_elf_relax_section (bfd *abfd, asection *sec, + struct bfd_link_info *link_info, bfd_boolean *again) +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel, *irelend; + bfd_byte *contents = NULL; + Elf_Internal_Sym *isymbuf = NULL; + + /* Assume nothing changes. */ + *again = FALSE; + + /* 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->flags & SEC_CODE) == 0) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Get a copy of the native relocations. */ + internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + link_info->keep_memory); + if (internal_relocs == NULL) + goto error_return; + + /* Walk through them looking for relaxing opportunities. */ + 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; + + /* 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; + } + + /* 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; + + if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) + { + /* An external symbol. */ + unsigned int indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + htop = elf_sym_hashes (abfd)[indx]; + } + + if (ELF32_R_TYPE (irel->r_info) == (int) R_ARC_GOTPC32 + && SYMBOL_REFERENCES_LOCAL (link_info, htop)) + { + unsigned int code; + + /* Get the opcode. */ + code = bfd_get_32_me (abfd, contents + irel->r_offset - 4); + + /* 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_PC32); + + /* ld rA,[pcl,symbol@tgot] -> add rA,pcl,symbol@pcl. */ + /* 0010 0bbb aa11 0ZZX DBBB 1111 10AA AAAA. + 111 00 000 0111 xx xxxx*/ + code &= ~0x27307F80; + BFD_ASSERT (code <= 62UL); + code |= 0x27007F80; + + /* Write back the new instruction. */ + bfd_put_32_me (abfd, code, contents + irel->r_offset - 4); + + /* The size isn't changed, don't redo. */ + *again = FALSE; + } + } + + if (isymbuf != NULL + && symtab_hdr->contents != (unsigned char *) isymbuf) + { + if (!link_info->keep_memory) + free (isymbuf); + else + /* 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); + else + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + + return TRUE; + + error_return: + if (isymbuf != NULL + && symtab_hdr->contents != (unsigned char *) isymbuf) + free (isymbuf); + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + + return FALSE; +} + #define TARGET_LITTLE_SYM arc_elf32_le_vec #define TARGET_LITTLE_NAME "elf32-littlearc" #define TARGET_BIG_SYM arc_elf32_be_vec @@ -2985,6 +3160,7 @@ elf32_arc_section_from_shdr (bfd *abfd, #define bfd_elf32_bfd_set_private_flags arc_elf_set_private_flags #define bfd_elf32_bfd_print_private_bfd_data arc_elf_print_private_bfd_data #define bfd_elf32_bfd_copy_private_bfd_data arc_elf_copy_private_bfd_data +#define bfd_elf32_bfd_relax_section arc_elf_relax_section #define elf_info_to_howto_rel arc_info_to_howto_rel #define elf_backend_object_p arc_elf_object_p diff --git a/ld/ChangeLog b/ld/ChangeLog index de47676ab6..b42f4a7ecb 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,8 @@ +2019-07-24 Claudiu Zissulescu + + * ld-arc/relax-local-pic.d: New test. + * ld-arc/relax-local-pic.s: New file. + 2019-07-22 Martin Liska * testsuite/ld-plugin/lto-3r.d: Remove. diff --git a/ld/testsuite/ld-arc/relax-local-pic.d b/ld/testsuite/ld-arc/relax-local-pic.d new file mode 100644 index 0000000000..5ed268809a --- /dev/null +++ b/ld/testsuite/ld-arc/relax-local-pic.d @@ -0,0 +1,14 @@ +#source: relax-local-pic.s +#as: +#ld: -q -A elf32-arclittle -relax +#objdump: -dr + +[^:]+: file format elf32-.*arc + + +Disassembly of section \.text: + +00000100 <__start>: + 100: 2700 7f84 0000 [0-9a-f]+ add r4,pcl,0x[0-9a-f]+.* + 104: R_ARC_PC32 a_in_other_thread + 108: 1c00 [0-9a-f\s]+ st\s+.* diff --git a/ld/testsuite/ld-arc/relax-local-pic.s b/ld/testsuite/ld-arc/relax-local-pic.s new file mode 100644 index 0000000000..66c48b4ad7 --- /dev/null +++ b/ld/testsuite/ld-arc/relax-local-pic.s @@ -0,0 +1,16 @@ + .section .text + .align 4 + .global __start + .type __start, @function +__start: + ld r4,[pcl,@a_in_other_thread@gotpc] + st 1,[r4] + .size __start, .-__start + + .global a_in_other_thread + .section .data + .align 4 + .type a_in_other_thread, @object + .size a_in_other_thread, 4 +a_in_other_thread: + .word -559038737 -- 2.34.1