PR22819, powerpc gas "instruction address is not a multiple of 4"
Checks for insn alignment were hopelessly confused when misaligned data starts a new frag. The real-world testcase happened to run out of frag space in the middle of emitting a trace-back table via something like: .byte 0 /* VERSION=0 */ .byte 9 /* LANG=C++ */ .byte 34 /* Bits on: has_tboff, fp_present */ .byte 64 /* Bits on: name_present */ .byte 128 /* Bits on: stores_bc, FP_SAVED=0 */ .byte 0 /* Bits on: GP_SAVED=0 */ .byte 2 /* FIXEDPARMS=2 */ .byte 1 /* FLOATPARMS=0, parmsonstk */ .long 0 .long 768 /* tb_offset: 0x300 */ .hword 45 /* Function name length: 45 */ .long 0x334e5a5f .long 0x31766f70 .long 0x65744932 .long 0x69746172 .long 0x7a5f6e6f .long 0x64504533 .long 0x5f534e50 .long 0x72463431 .long 0x61746361 .long 0x74535f6c .long 0x74637572 .byte 0x45 .byte 0 The trigger being those misaligned .long's output for the function name. A most horrible way to output a string, especially considering endian issues.. PR 22819 * config/tc-ppc.c (md_assemble): Rewrite insn alignment checking. (ppc_frag_check): Likewise. * testsuite/gas/ppc/misalign.d, * testsuite/gas/ppc/misalign.l, * testsuite/gas/ppc/misalign.s: New test. * testsuite/gas/ppc/misalign2.d, * testsuite/gas/ppc/misalign2.s: New test. * testsuite/gas/ppc/ppc.exp: Run them.
This commit is contained in:
parent
02ecce62be
commit
a9479dc051
|
@ -1,3 +1,15 @@
|
|||
2018-02-08 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR 22819
|
||||
* config/tc-ppc.c (md_assemble): Rewrite insn alignment checking.
|
||||
(ppc_frag_check): Likewise.
|
||||
* testsuite/gas/ppc/misalign.d,
|
||||
* testsuite/gas/ppc/misalign.l,
|
||||
* testsuite/gas/ppc/misalign.s: New test.
|
||||
* testsuite/gas/ppc/misalign2.d,
|
||||
* testsuite/gas/ppc/misalign2.s: New test.
|
||||
* testsuite/gas/ppc/ppc.exp: Run them.
|
||||
|
||||
2018-02-05 Maciej W. Rozycki <macro@mips.com>
|
||||
|
||||
* config/tc-riscv.c (riscv_handle_implicit_zero_offset): Rename
|
||||
|
|
|
@ -2747,7 +2747,7 @@ md_assemble (char *str)
|
|||
struct ppc_fixup fixups[MAX_INSN_FIXUPS];
|
||||
int fc;
|
||||
char *f;
|
||||
int addr_mod;
|
||||
int addr_mask;
|
||||
int i;
|
||||
unsigned int insn_length;
|
||||
|
||||
|
@ -3520,31 +3520,34 @@ md_assemble (char *str)
|
|||
#endif
|
||||
|
||||
/* Write out the instruction. */
|
||||
/* Differentiate between two and four byte insns. */
|
||||
|
||||
addr_mask = 3;
|
||||
if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
|
||||
/* All instructions can start on a 2 byte boundary for VLE. */
|
||||
addr_mask = 1;
|
||||
|
||||
if (frag_now->insn_addr != addr_mask)
|
||||
{
|
||||
if (PPC_OP_SE_VLE (insn))
|
||||
insn_length = 2;
|
||||
else
|
||||
insn_length = 4;
|
||||
addr_mod = frag_now_fix () & 1;
|
||||
/* Don't emit instructions to a frag started for data, or for a
|
||||
CPU differing in VLE mode. Data is allowed to be misaligned,
|
||||
and it's possible to start a new frag in the middle of
|
||||
misaligned data. */
|
||||
frag_wane (frag_now);
|
||||
frag_new (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
insn_length = 4;
|
||||
addr_mod = frag_now_fix () & 3;
|
||||
}
|
||||
/* All instructions can start on a 2 byte boundary for VLE. */
|
||||
|
||||
/* Check that insns within the frag are aligned. ppc_frag_check
|
||||
will ensure that the frag start address is aligned. */
|
||||
if ((frag_now_fix () & addr_mask) != 0)
|
||||
as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1);
|
||||
|
||||
/* Differentiate between two and four byte insns. */
|
||||
insn_length = 4;
|
||||
if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn))
|
||||
insn_length = 2;
|
||||
|
||||
f = frag_more (insn_length);
|
||||
if (frag_now->has_code && frag_now->insn_addr != addr_mod)
|
||||
{
|
||||
if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
|
||||
as_bad (_("instruction address is not a multiple of 2"));
|
||||
else
|
||||
as_bad (_("instruction address is not a multiple of 4"));
|
||||
}
|
||||
frag_now->insn_addr = addr_mod;
|
||||
frag_now->has_code = 1;
|
||||
frag_now->insn_addr = addr_mask;
|
||||
md_number_to_chars (f, insn, insn_length);
|
||||
last_insn = insn;
|
||||
last_seg = now_seg;
|
||||
|
@ -6491,19 +6494,10 @@ ppc_fix_adjustable (fixS *fix)
|
|||
void
|
||||
ppc_frag_check (struct frag *fragP)
|
||||
{
|
||||
if (!fragP->has_code)
|
||||
return;
|
||||
|
||||
if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
|
||||
{
|
||||
if (((fragP->fr_address + fragP->insn_addr) & 1) != 0)
|
||||
as_bad (_("instruction address is not a multiple of 2"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((fragP->fr_address + fragP->insn_addr) & 3) != 0)
|
||||
as_bad (_("instruction address is not a multiple of 4"));
|
||||
}
|
||||
if ((fragP->fr_address & fragP->insn_addr) != 0)
|
||||
as_bad_where (fragP->fr_file, fragP->fr_line,
|
||||
_("instruction address is not a multiple of %d"),
|
||||
fragP->insn_addr + 1);
|
||||
}
|
||||
|
||||
/* Implement HANDLE_ALIGN. This writes the NOP pattern into an
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#as:
|
||||
#error-output: misalign.l
|
|
@ -0,0 +1,2 @@
|
|||
.*Assembler messages:
|
||||
.*Error: instruction address is not a multiple of 4
|
|
@ -0,0 +1,3 @@
|
|||
.text
|
||||
.byte 1
|
||||
nop
|
|
@ -0,0 +1,7 @@
|
|||
#as:
|
||||
#nm: -n
|
||||
|
||||
#...
|
||||
0+00001 T odd
|
||||
0+40001 T odd2
|
||||
0+40004 T aligned
|
|
@ -0,0 +1,13 @@
|
|||
.text
|
||||
.global odd, odd2, aligned
|
||||
.dc.b 1
|
||||
odd:
|
||||
.rept 65536
|
||||
.dc.l 0
|
||||
.endr
|
||||
odd2:
|
||||
.dc.b 2,3,4
|
||||
aligned:
|
||||
.rept 65536
|
||||
nop
|
||||
.endr
|
|
@ -45,6 +45,8 @@ if { [istarget powerpc64*-*-*] || [istarget *-*-elf64*]} then {
|
|||
|
||||
if { [istarget powerpc*-*-*] } then {
|
||||
run_dump_test "regnames"
|
||||
run_dump_test "misalign"
|
||||
run_dump_test "misalign2"
|
||||
if { [is_elf_format] } then {
|
||||
run_dump_test "machine"
|
||||
run_dump_test "common"
|
||||
|
|
Loading…
Reference in New Issue