This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: unexpected NOP encodings
- From: Alan Modra <amodra at gmail dot com>
- To: Jan Beulich <JBeulich at suse dot com>
- Cc: binutils at sourceware dot org, Peter Bergner <bergner at vnet dot ibm dot com>
- Date: Tue, 25 Jun 2019 13:06:35 +0930
- Subject: Re: unexpected NOP encodings
- References: <5D10D6A0020000780023AA94@prv1-mh.provo.novell.com>
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