]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
PowerPC nops
authorAlan Modra <amodra@gmail.com>
Tue, 25 Jun 2019 00:42:58 +0000 (10:12 +0930)
committerAlan Modra <amodra@gmail.com>
Tue, 25 Jun 2019 03:34:40 +0000 (13:04 +0930)
This patch corrects ppc rs_align_code handling to choose the alignment
nops based on the machine in force at the alignment directive rather
than the machine at the end of file.

* config/tc-ppc.h (ppc_nop_select): Declare.
(NOP_OPCODE): Define.
* config/tc-ppc.c (ppc_elf_end, ppc_xcoff_end): Zero ppc_cpu.
(ppc_nop_encoding_for_rs_align_code): New enum.
(ppc_nop_select): New function.
(ppc_handle_align): Don't use ppc_cpu here.  Get nop type from frag.
* testsuite/gas/ppc/groupnop.d,
* testsuite/gas/ppc/groupnop.s: New test.
* testsuite/gas/ppc/ppc.exp: Run it.

gas/ChangeLog
gas/config/tc-ppc.c
gas/config/tc-ppc.h
gas/testsuite/gas/ppc/groupnop.d [new file with mode: 0644]
gas/testsuite/gas/ppc/groupnop.s [new file with mode: 0644]
gas/testsuite/gas/ppc/ppc.exp

index 1e9cf0b6b87acd0c36fbe6e9d91b788ff68773d8..1e2962763fa501e162967b5ebf044ca16d6c5b9c 100644 (file)
@@ -1,3 +1,15 @@
+2019-06-25  Alan Modra  <amodra@gmail.com>
+
+       * config/tc-ppc.h (ppc_nop_select): Declare.
+       (NOP_OPCODE): Define.
+       * config/tc-ppc.c (ppc_elf_end, ppc_xcoff_end): Zero ppc_cpu.
+       (ppc_nop_encoding_for_rs_align_code): New enum.
+       (ppc_nop_select): New function.
+       (ppc_handle_align): Don't use ppc_cpu here.  Get nop type from frag.
+       * testsuite/gas/ppc/groupnop.d,
+       * testsuite/gas/ppc/groupnop.s: New test.
+       * testsuite/gas/ppc/ppc.exp: Run it.
+
 2019-06-19  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR binutils/24700
index d7090102a29bbc0e7d5b26d1eef0571a7f32d8e3..de0f8da94845dfcf188c1724ffb9528a1832e390 100644 (file)
@@ -2608,6 +2608,12 @@ ppc_elf_end (void)
       elf_elfheader (stdoutput)->e_flags &= ~EF_PPC64_ABI;
       elf_elfheader (stdoutput)->e_flags |= ppc_abiversion & EF_PPC64_ABI;
     }
+  /* Any selection of opcodes based on ppc_cpu after gas has finished
+     parsing the file is invalid.  md_apply_fix and ppc_handle_align
+     must select opcodes based on the machine in force at the point
+     where the fixup or alignment frag was created, not the machine in
+     force at the end of file.  */
+  ppc_cpu = 0;
 }
 
 /* Validate any relocations emitted for -mrelocatable, possibly adding
@@ -5562,6 +5568,7 @@ ppc_xcoff_end (void)
             symbol_set_value_now (dwss->end_exp.X_add_symbol);
           }
     }
+  ppc_cpu = 0;
 }
 
 #endif /* OBJ_XCOFF */
@@ -7077,26 +7084,58 @@ ppc_frag_check (struct frag *fragP)
                  fragP->insn_addr + 1);
 }
 
-/* Implement HANDLE_ALIGN.  This writes the NOP pattern into an
-   rs_align_code frag.  */
+/* rs_align_code frag handling.  */
+
+enum ppc_nop_encoding_for_rs_align_code
+{
+  PPC_NOP_VANILLA,
+  PPC_NOP_VLE,
+  PPC_NOP_GROUP_P6,
+  PPC_NOP_GROUP_P7
+};
+
+unsigned int
+ppc_nop_select (void)
+{
+  if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
+    return PPC_NOP_VLE;
+  if ((ppc_cpu & (PPC_OPCODE_POWER9 | PPC_OPCODE_E500MC)) == 0)
+    {
+      if ((ppc_cpu & PPC_OPCODE_POWER7) != 0)
+       return PPC_NOP_GROUP_P7;
+      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0)
+       return PPC_NOP_GROUP_P6;
+    }
+  return PPC_NOP_VANILLA;
+}
 
 void
 ppc_handle_align (struct frag *fragP)
 {
   valueT count = (fragP->fr_next->fr_address
                  - (fragP->fr_address + fragP->fr_fix));
+  char *dest = fragP->fr_literal + fragP->fr_fix;
+  enum ppc_nop_encoding_for_rs_align_code nop_select = *dest & 0xff;
+
+  /* Pad with zeros if not inserting a whole number of instructions.
+     We could pad with zeros up to an instruction boundary then follow
+     with nops but odd counts indicate data in an executable section
+     so padding with zeros is most appropriate.  */
+  if (count == 0
+      || nop_select == PPC_NOP_VLE ? (count & 1) != 0 : (count & 3) != 0)
+    {
+      *dest = 0;
+      return;
+    }
 
-  if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && count != 0 && (count & 1) == 0)
+  if (nop_select == PPC_NOP_VLE)
     {
-      char *dest = fragP->fr_literal + fragP->fr_fix;
 
       fragP->fr_var = 2;
       md_number_to_chars (dest, 0x4400, 2);
     }
-  else if (count != 0 && (count & 3) == 0)
+  else
     {
-      char *dest = fragP->fr_literal + fragP->fr_fix;
-
       fragP->fr_var = 4;
 
       if (count > 4 * nop_limit && count < 0x2000000)
@@ -7125,8 +7164,7 @@ ppc_handle_align (struct frag *fragP)
 
       md_number_to_chars (dest, 0x60000000, 4);
 
-      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0
-         && (ppc_cpu & PPC_OPCODE_POWER9) == 0)
+      if (nop_select >= PPC_NOP_GROUP_P6)
        {
          /* For power6, power7, and power8, we want the last nop to
             be a group terminating one.  Do this by inserting an
@@ -7146,18 +7184,12 @@ ppc_handle_align (struct frag *fragP)
              dest = group_nop->fr_literal;
            }
 
-         if ((ppc_cpu & PPC_OPCODE_POWER7) != 0)
-           {
-             if (ppc_cpu & PPC_OPCODE_E500MC)
-               /* e500mc group terminating nop: "ori 0,0,0".  */
-               md_number_to_chars (dest, 0x60000000, 4);
-             else
-               /* power7/power8 group terminating nop: "ori 2,2,0".  */
-               md_number_to_chars (dest, 0x60420000, 4);
-           }
-         else
+         if (nop_select == PPC_NOP_GROUP_P6)
            /* power6 group terminating nop: "ori 1,1,0".  */
            md_number_to_chars (dest, 0x60210000, 4);
+         else
+           /* power7/power8 group terminating nop: "ori 2,2,0".  */
+           md_number_to_chars (dest, 0x60420000, 4);
        }
     }
 }
index 9de5c08441b5bd36768ecf5bc1ec9fc38299ad05..2b18ecda2fd15e140efe050ace4db2e7b9bbb464 100644 (file)
@@ -82,6 +82,9 @@ extern const char *ppc_target_format (void);
   if ((FRAGP)->fr_type == rs_align_code)                               \
     ppc_handle_align (FRAGP);
 
+extern unsigned int ppc_nop_select (void);
+#define NOP_OPCODE ppc_nop_select ()
+
 extern void ppc_handle_align (struct frag *);
 extern void ppc_frag_check (struct frag *);
 
diff --git a/gas/testsuite/gas/ppc/groupnop.d b/gas/testsuite/gas/ppc/groupnop.d
new file mode 100644 (file)
index 0000000..6568ccc
--- /dev/null
@@ -0,0 +1,19 @@
+#as:
+#objdump: -dr
+
+.*
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+   0:  (60 00 00 00|00 00 00 60) .*
+   4:  (60 00 00 00|00 00 00 60) .*
+   8:  (60 00 00 00|00 00 00 60) .*
+   c:  (60 42 00 00|00 00 42 60) .*
+  10:  (60 00 00 00|00 00 00 60) .*
+  14:  (60 42 00 00|00 00 42 60) .*
+  18:  (60 00 00 00|00 00 00 60) .*
+  1c:  (60 21 00 00|00 00 21 60) .*
+  20:  (60 00 00 00|00 00 00 60) .*
+  24:  (60 00 00 00|00 00 00 60) .*
+#pass
diff --git a/gas/testsuite/gas/ppc/groupnop.s b/gas/testsuite/gas/ppc/groupnop.s
new file mode 100644 (file)
index 0000000..ca6a9b4
--- /dev/null
@@ -0,0 +1,19 @@
+ .machine power9
+ nop
+ .p2align 3
+
+ .machine power8
+ nop
+ .p2align 3
+
+ .machine power7
+ nop
+ .p2align 3
+
+ .machine power6
+ nop
+ .p2align 3
+
+ .machine power5
+ nop
+ .p2align 3
index 3c7a36caff1844e36145dd7279a0b5afb9b91992..d87559e3c9e1f1b8647fe27a212d885c3b791983 100644 (file)
@@ -51,6 +51,7 @@ if { [istarget "*-*-aix*"]
     run_dump_test "test2xcoff32"
     run_dump_test "altivec_xcoff"
     run_dump_test "altivec_xcoff64"
+    run_dump_test "groupnop"
 }
 
 # These tests are currently ELF specific, only because nobody has
@@ -105,6 +106,7 @@ run_dump_test "altivec2"
 run_dump_test "altivec3"
 run_dump_test "broadway"
 run_dump_test "booke"
+run_dump_test "groupnop"
 run_dump_test "e500"
 run_list_test "e500-ill" "-me500"
 run_dump_test "ppc750ps"