unexpected NOP encodings

Alan Modra amodra@gmail.com
Tue Jun 25 03:36:00 GMT 2019


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.

diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index d7090102a2..de0f8da948 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -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);
 	}
     }
 }
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 9de5c08441..2b18ecda2f 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -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
index 0000000000..6568cccc1f
--- /dev/null
+++ b/gas/testsuite/gas/ppc/groupnop.d
@@ -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
index 0000000000..ca6a9b4076
--- /dev/null
+++ b/gas/testsuite/gas/ppc/groupnop.s
@@ -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
diff --git a/gas/testsuite/gas/ppc/ppc.exp b/gas/testsuite/gas/ppc/ppc.exp
index 3c7a36caff..d87559e3c9 100644
--- a/gas/testsuite/gas/ppc/ppc.exp
+++ b/gas/testsuite/gas/ppc/ppc.exp
@@ -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"

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list