PowerPC nops

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.
This commit is contained in:
Alan Modra 2019-06-25 10:12:58 +09:30
parent 2e7c439dec
commit 22f72c4868
6 changed files with 106 additions and 19 deletions

View 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

View 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;
if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && count != 0 && (count & 1) == 0)
/* 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 (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);
}
}
}

View 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 *);

View File

@ -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

View File

@ -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

View 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"