From bf7279d5358c47b90b89c4b6b5f8be9960120be2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 9 Apr 2014 07:03:53 +0930 Subject: [PATCH] ppc476 gas warn on data in code sections * config/tc-ppc.c (warn_476, last_insn, last_seg, last_subseg): New static vars. (md_longopts, md_parse_option, md_show_usage): Add --ppc476-workaround. (ppc_elf_cons_fix_check): New function. (md_assemble): Set last_insn, last_seg, last_subseg. (ppc_byte, md_apply_fix): Handle warn_476. * config/tc-ppc.h (TC_CONS_FIX_CHECK): Define. (ppc_elf_cons_fix_check): Declare. * read.c (cons_worker): Invoke TC_CONS_FIX_CHECK. --- gas/ChangeLog | 12 +++++++++ gas/config/tc-ppc.c | 63 ++++++++++++++++++++++++++++++++++++++++++++- gas/config/tc-ppc.h | 4 +++ gas/read.c | 9 +++++++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 36242a88aff..b6e2b843a9c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,15 @@ +2014-04-09 Alan Modra + + * config/tc-ppc.c (warn_476, last_insn, last_seg, last_subseg): + New static vars. + (md_longopts, md_parse_option, md_show_usage): Add --ppc476-workaround. + (ppc_elf_cons_fix_check): New function. + (md_assemble): Set last_insn, last_seg, last_subseg. + (ppc_byte, md_apply_fix): Handle warn_476. + * config/tc-ppc.h (TC_CONS_FIX_CHECK): Define. + (ppc_elf_cons_fix_check): Declare. + * read.c (cons_worker): Invoke TC_CONS_FIX_CHECK. + 2014-04-09 Alan Modra * gas/config/tc-alpha.h (TC_CONS_FIX_NEW): Add RELOC parameter. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 5cfe1db19a4..2c8ce6af4ba 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -211,6 +211,12 @@ enum { has_large_toc_reloc = 1, has_small_toc_reloc = 2 } toc_reloc_types; + +/* Warn on emitting data to code sections. */ +int warn_476; +unsigned long last_insn; +segT last_seg; +subsegT last_subseg; /* The target specific pseudo-ops which we support. */ @@ -1065,6 +1071,8 @@ const char *const md_shortopts = "um:"; #define OPTION_NOPS (OPTION_MD_BASE + 0) const struct option md_longopts[] = { {"nops", required_argument, NULL, OPTION_NOPS}, + {"ppc476-workaround", no_argument, &warn_476, 1}, + {"no-ppc476-workaround", no_argument, &warn_476, 0}, {NULL, no_argument, NULL, 0} }; const size_t md_longopts_size = sizeof (md_longopts); @@ -1243,6 +1251,9 @@ md_parse_option (int c, char *arg) } break; + case 0: + break; + default: return 0; } @@ -1316,7 +1327,8 @@ PowerPC options:\n\ -Qy, -Qn ignored\n")); #endif fprintf (stream, _("\ --nops=count when aligning, more than COUNT nops uses a branch\n")); +-nops=count when aligning, more than COUNT nops uses a branch\n\ +-ppc476-workaround warn if emitting data to code sections\n")); } /* Set ppc_cpu if it is not already set. */ @@ -2056,6 +2068,37 @@ ppc_elf_parse_cons (expressionS *exp, unsigned int nbytes) return BFD_RELOC_NONE; } +/* Warn when emitting data to code sections, unless we are emitting + a relocation that ld --ppc476-workaround uses to recognise data + *and* there was an unconditional branch prior to the data. */ + +void +ppc_elf_cons_fix_check (expressionS *exp ATTRIBUTE_UNUSED, + unsigned int nbytes, fixS *fix) +{ + if (warn_476 + && (now_seg->flags & SEC_CODE) != 0 + && (nbytes != 4 + || fix == NULL + || !(fix->fx_r_type == BFD_RELOC_32 + || fix->fx_r_type == BFD_RELOC_CTOR + || fix->fx_r_type == BFD_RELOC_32_PCREL) + || !(last_seg == now_seg && last_subseg == now_subseg) + || !((last_insn & (0x3f << 26)) == (18u << 26) + || ((last_insn & (0x3f << 26)) == (16u << 26) + && (last_insn & (0x14 << 21)) == (0x14 << 21)) + || ((last_insn & (0x3f << 26)) == (19u << 26) + && (last_insn & (0x3ff << 1)) == (16u << 1) + && (last_insn & (0x14 << 21)) == (0x14 << 21))))) + { + /* Flag that we've warned. */ + if (fix != NULL) + fix->fx_tcbit = 1; + + as_warn (_("data in executable section")); + } +} + /* Solaris pseduo op to change to the .rodata section. */ static void ppc_elf_rdata (int xxx) @@ -3345,6 +3388,9 @@ md_assemble (char *str) frag_now->insn_addr = addr_mod; frag_now->has_code = 1; md_number_to_chars (f, insn, insn_length); + last_insn = insn; + last_seg = now_seg; + last_subseg = now_subseg; #ifdef OBJ_ELF dwarf2_emit_insn (insn_length); @@ -3502,6 +3548,8 @@ ppc_section_flags (flagword flags, bfd_vma attr ATTRIBUTE_UNUSED, int type) static void ppc_byte (int ignore ATTRIBUTE_UNUSED) { + int count = 0; + if (*input_line_pointer != '\"') { cons (1); @@ -3525,8 +3573,11 @@ ppc_byte (int ignore ATTRIBUTE_UNUSED) } FRAG_APPEND_1_CHAR (c); + ++count; } + if (warn_476 && count != 0 && (now_seg->flags & SEC_CODE) != 0) + as_warn (_("data in executable section")); demand_empty_rest_of_line (); } @@ -6924,6 +6975,16 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) if (fixP->fx_size && APPLY_RELOC) md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, fieldval, fixP->fx_size); + if (warn_476 + && (seg->flags & SEC_CODE) != 0 + && fixP->fx_size == 4 + && fixP->fx_done + && !fixP->fx_tcbit + && (fixP->fx_r_type == BFD_RELOC_32 + || fixP->fx_r_type == BFD_RELOC_CTOR + || fixP->fx_r_type == BFD_RELOC_32_PCREL)) + as_warn_where (fixP->fx_file, fixP->fx_line, + _("data in executable section")); } /* We are only able to convert some relocs to pc-relative. */ diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h index a5e69ca7b95..3cd9bf16c78 100644 --- a/gas/config/tc-ppc.h +++ b/gas/config/tc-ppc.h @@ -235,6 +235,10 @@ extern int ppc_fix_adjustable (struct fix *); ppc_elf_parse_cons (EXP, NBYTES) extern bfd_reloc_code_real_type ppc_elf_parse_cons (expressionS *, unsigned int); +#define TC_CONS_FIX_CHECK(EXP, NBYTES, FIX) \ + ppc_elf_cons_fix_check (EXP, NBYTES, FIX) +extern void ppc_elf_cons_fix_check (expressionS *, unsigned int, struct fix *); + #define tc_frob_file_before_adjust ppc_frob_file_before_adjust extern void ppc_frob_file_before_adjust (void); diff --git a/gas/read.c b/gas/read.c index 306f7eca57e..066783cb04d 100644 --- a/gas/read.c +++ b/gas/read.c @@ -3918,6 +3918,12 @@ cons_worker (int nbytes, /* 1=.byte, 2=.word, 4=.long. */ do { TC_PARSE_CONS_RETURN_TYPE ret = TC_PARSE_CONS_RETURN_NONE; +#ifdef TC_CONS_FIX_CHECK + fixS **cur_fix = &frchain_now->fix_tail; + + if (*cur_fix != NULL) + cur_fix = &(*cur_fix)->fx_next; +#endif #ifdef TC_M68K if (flag_m68k_mri) @@ -3942,6 +3948,9 @@ cons_worker (int nbytes, /* 1=.byte, 2=.word, 4=.long. */ as_fatal (_("rva without symbol")); } emit_expr_with_reloc (&exp, (unsigned int) nbytes, ret); +#ifdef TC_CONS_FIX_CHECK + TC_CONS_FIX_CHECK (&exp, nbytes, *cur_fix); +#endif ++c; } while (*input_line_pointer++ == ','); -- 2.30.2