diff --git a/gas/ChangeLog b/gas/ChangeLog index 1e9cf0b6b8..1e2962763f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,15 @@ +2019-06-25 Alan Modra + + * 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 PR binutils/24700 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; - 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); } } } 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"