[ARC] Add linker relaxation.
authorClaudiu Zissulescu <claziss@gmail.com>
Wed, 24 Jul 2019 13:33:29 +0000 (16:33 +0300)
committerClaudiu Zissulescu <claziss@gmail.com>
Wed, 24 Jul 2019 13:33:29 +0000 (16:33 +0300)
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  <claziss@synopsys.com>

* 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  <claziss@synopsys.com>

* ld-arc/relax-local-pic.d: New test.
* ld-arc/relax-local-pic.s: New file.

bfd/ChangeLog
bfd/elf32-arc.c
ld/ChangeLog
ld/testsuite/ld-arc/relax-local-pic.d [new file with mode: 0644]
ld/testsuite/ld-arc/relax-local-pic.s [new file with mode: 0644]

index 6d7e42510aad2ac2a847175402fd9309da216d23..50027c63f3fbbdaec4892fbb5cd42752ca0637fe 100644 (file)
@@ -1,3 +1,10 @@
+2019-07-24  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * 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  <amodra@gmail.com>
 
        * elf-bfd.h (struct elf_backend_data): Return bfd_boolean from
index c7ffc6a6f9df1d05fed79eba32ab83867af22ece..b069e3fda5ccf3585dce3ebb83725f0c3e31ec7d 100644 (file)
@@ -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
index de47676ab69bb02311c6f4be1f8d80c239d5db48..b42f4a7ecb923806b08dd71ab32b771e449900dc 100644 (file)
@@ -1,3 +1,8 @@
+2019-07-24  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * ld-arc/relax-local-pic.d: New test.
+       * ld-arc/relax-local-pic.s: New file.
+
 2019-07-22  Martin Liska  <mliska@suse.cz>
 
        * 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 (file)
index 0000000..5ed2688
--- /dev/null
@@ -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 (file)
index 0000000..66c48b4
--- /dev/null
@@ -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