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:
Alan Modra 2018-02-08 10:18:59 +10:30
parent 02ecce62be
commit a9479dc051
8 changed files with 70 additions and 35 deletions

View File

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

View File

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

View File

@ -0,0 +1,2 @@
#as:
#error-output: misalign.l

View File

@ -0,0 +1,2 @@
.*Assembler messages:
.*Error: instruction address is not a multiple of 4

View File

@ -0,0 +1,3 @@
.text
.byte 1
nop

View File

@ -0,0 +1,7 @@
#as:
#nm: -n
#...
0+00001 T odd
0+40001 T odd2
0+40004 T aligned

View File

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

View File

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