[RFC] MIPS: Add option to control delay slots exploiting

Message ID 1525797855-28727-2-git-send-email-maksim.e.kozlov@gmail.com
State New
Headers show
Series
  • [RFC] MIPS: Add option to control delay slots exploiting
Related show

Commit Message

Maksim Kozlov May 8, 2018, 4:44 p.m.
This introduces --(no-)delayed-branch option to get possibility to
control whether delay slots exploiting allowed or not in PLT stubs.

bfd/
	* elfxx-mips.c: Changes with respect to --(no-)delayed-branch option
	* elfxx-mips.h: Add extra parameter in _bfd_mips_elf_linker_flags()
        prototype

ld/
	* emultempl/mipself.em: Introduce --(no-)delayed-branch option

Signed-off-by: Maksim E. Kozlov <maksim.e.kozlov@gmail.com>

---
 bfd/elfxx-mips.c        | 34 ++++++++++++++++++++++++++++++----
 bfd/elfxx-mips.h        |  2 +-
 ld/emultempl/mipself.em | 26 ++++++++++++++++++++++++--
 3 files changed, 55 insertions(+), 7 deletions(-)

-- 
2.7.4

Patch

diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index fc49f2f..322455f 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -449,6 +449,9 @@  struct mips_elf_link_hash_table
   /* True if we suppress checks for invalid branches between ISA modes.  */
   bfd_boolean ignore_branch_isa;
 
+  /* True if instructions can be put into delay slots.  */
+  bfd_boolean delayed_branch;
+
   /* True if we're generating code for VxWorks.  */
   bfd_boolean is_vxworks;
 
@@ -920,6 +923,7 @@  static bfd *reldyn_sorting_bfd;
    ((ABI_64_P (abfd)							\
     ? (0x64180000 + (VAL))	/* daddiu t8,zero,VAL sign extended */	\
     : (0x24180000 + (VAL))))	/* addiu t8,zero,VAL sign extended */
+#define STUB_NOP 0x00000000
 
 /* Likewise for the microMIPS ASE.  */
 #define STUB_LW_MICROMIPS(abfd)						\
@@ -9466,6 +9470,9 @@  mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
 				? MICROMIPS_FUNCTION_STUB_BIG_SIZE
 				: MICROMIPS_FUNCTION_STUB_NORMAL_SIZE);
 
+  if (!htab->delayed_branch)
+    htab->function_stub_size += 4;
+
   htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size;
 }
 
@@ -10731,7 +10738,9 @@  _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       bfd_boolean micromips_p = MICROMIPS_P (output_bfd);
       unsigned int other = micromips_p ? STO_MICROMIPS : 0;
       bfd_vma stub_size = htab->function_stub_size;
-      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
+      bfd_boolean delayed_branch = htab->delayed_branch;
+      /* Extra 4 bytes for NOP instruction if delay slots aren't exploited.  */
+      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE + 4];
       bfd_vma isa_bit = micromips_p;
       bfd_vma stub_big_size;
 
@@ -10742,6 +10751,9 @@  _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
       else
 	stub_big_size = MICROMIPS_FUNCTION_STUB_BIG_SIZE;
 
+      if (!delayed_branch)
+	stub_big_size += 4;
+
       /* This symbol has a stub.  Set it up.  */
 
       BFD_ASSERT (h->dynindx != -1);
@@ -10822,8 +10834,12 @@  _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 			  stub + idx);
 	      idx += 4;
 	    }
-	  bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
-	  idx += 4;
+
+	  if (delayed_branch)
+	    {
+	      bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
+	      idx += 4;
+	    }
 
 	  /* If a large stub is not required and sign extension is not a
 	     problem, then use legacy code in the stub.  */
@@ -10836,6 +10852,14 @@  _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
 	  else
 	    bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
 			stub + idx);
+
+	  if (!delayed_branch)
+	    {
+	      idx += 4;
+	      bfd_put_32 (output_bfd, STUB_JALR, stub + idx);
+	      idx += 4;
+	      bfd_put_32 (output_bfd, STUB_NOP, stub + idx);
+	    }
 	}
 
       BFD_ASSERT (h->plt.plist->stub_offset <= htab->sstubs->size);
@@ -13911,10 +13935,12 @@  _bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
 
 void
 _bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
-			    bfd_boolean ignore_branch_isa)
+			    bfd_boolean ignore_branch_isa,
+			    bfd_boolean delayed_branch)
 {
   mips_elf_hash_table (info)->insn32 = insn32;
   mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+  mips_elf_hash_table (info)->delayed_branch = delayed_branch;
 }
 
 /* Structure for saying that BFD machine EXTENSION extends BASE.  */
diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
index b8ea714..3f0e658 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -147,7 +147,7 @@  extern bfd_boolean _bfd_mips_elf_ignore_undef_symbol
 extern void _bfd_mips_elf_use_plts_and_copy_relocs
   (struct bfd_link_info *);
 extern void _bfd_mips_elf_linker_flags
-  (struct bfd_link_info *, bfd_boolean, bfd_boolean);
+  (struct bfd_link_info *, bfd_boolean, bfd_boolean, bfd_boolean);
 extern bfd_boolean _bfd_mips_elf_init_stubs
   (struct bfd_link_info *,
    asection *(*) (const char *, asection *, asection *));
diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em
index 5d428d2..b8d0ef4 100644
--- a/ld/emultempl/mipself.em
+++ b/ld/emultempl/mipself.em
@@ -35,6 +35,7 @@  static bfd *stub_bfd;
 
 static bfd_boolean insn32;
 static bfd_boolean ignore_branch_isa;
+static bfd_boolean delayed_branch = TRUE;
 
 static void
 mips_after_parse (void)
@@ -203,7 +204,8 @@  mips_create_output_section_statements (void)
 
   htab = elf_hash_table (&link_info);
   if (is_elf_hash_table (htab) && is_mips_elf (link_info.output_bfd))
-    _bfd_mips_elf_linker_flags (&link_info, insn32, ignore_branch_isa);
+    _bfd_mips_elf_linker_flags (&link_info, insn32, ignore_branch_isa,
+                                delayed_branch);
 
   if (is_mips_elf (link_info.output_bfd))
     _bfd_mips_elf_init_stubs (&link_info, mips_add_stub_section);
@@ -259,7 +261,9 @@  enum
     OPTION_INSN32 = 301,
     OPTION_NO_INSN32,
     OPTION_IGNORE_BRANCH_ISA,
-    OPTION_NO_IGNORE_BRANCH_ISA
+    OPTION_NO_IGNORE_BRANCH_ISA,
+    OPTION_DELAYED_BRANCH,
+    OPTION_NO_DELAYED_BRANCH
   };
 '
 
@@ -268,6 +272,8 @@  PARSE_AND_LIST_LONGOPTS='
   { "no-insn32", no_argument, NULL, OPTION_NO_INSN32 },
   { "ignore-branch-isa", no_argument, NULL, OPTION_IGNORE_BRANCH_ISA },
   { "no-ignore-branch-isa", no_argument, NULL, OPTION_NO_IGNORE_BRANCH_ISA },
+  { "delayed-branch", no_argument, NULL, OPTION_DELAYED_BRANCH },
+  { "no-delayed-branch", no_argument, NULL, OPTION_NO_DELAYED_BRANCH },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -285,6 +291,14 @@  PARSE_AND_LIST_OPTIONS='
   --no-ignore-branch-isa      Reject invalid branch relocations requiring\n\
                               an ISA mode switch\n"
 		   ));
+  fprintf (file, _("\
+  --delayed-branch            Exploit instruction slots available after\n\
+                              delayed branch instructions.\n"
+		   ));
+  fprintf (file, _("\
+  --no-delayed-branch         Do not exploit instruction slots available\n\
+                              after delayed branch instructions.\n"
+		   ));
 '
 
 PARSE_AND_LIST_ARGS_CASES='
@@ -303,6 +317,14 @@  PARSE_AND_LIST_ARGS_CASES='
     case OPTION_NO_IGNORE_BRANCH_ISA:
       ignore_branch_isa = FALSE;
       break;
+
+    case OPTION_DELAYED_BRANCH:
+      delayed_branch = TRUE;
+      break;
+
+    case OPTION_NO_DELAYED_BRANCH:
+      delayed_branch = FALSE;
+      break;
 '
 
 LDEMUL_AFTER_PARSE=mips_after_parse