aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2018-02-08 10:18:59 +1030
committerAlan Modra <amodra@gmail.com>2018-02-08 13:56:29 +1030
commita9479dc051ab00f311c04cdd5b299a70739f67ed (patch)
tree125d66cdbfce4db95791983657b87e297cc688fc /gas/config/tc-ppc.c
parent02ecce62be3516c03f523b1665c9d151a16a39c6 (diff)
downloadfsf-binutils-gdb-a9479dc051ab00f311c04cdd5b299a70739f67ed.zip
fsf-binutils-gdb-a9479dc051ab00f311c04cdd5b299a70739f67ed.tar.gz
fsf-binutils-gdb-a9479dc051ab00f311c04cdd5b299a70739f67ed.tar.bz2
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.
Diffstat (limited to 'gas/config/tc-ppc.c')
-rw-r--r--gas/config/tc-ppc.c64
1 files changed, 29 insertions, 35 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 35da05c..f63003b 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -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;
- }
- else
- {
- insn_length = 4;
- addr_mod = frag_now_fix () & 3;
+ /* 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);
}
- /* 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