gcc/ChangeLog: * config/arm/arm-protos.h (arm_modes_tieable_p): New. * config/arm/arm.c (arm_function_section): New. (arm_section_type_flags): New. (TARGET_ASM_FUNCTION_SECTION): Define. (TARGET_SECTION_TYPE_FLAGS): Define. (arm_option_override): Add mexecute-only new option. (thumb1_gen_const_int): New. (thumb1_legitimate_address_p): Disallow constant pool usage for thumb1 for arm_disable_literal_pool. (thumb1_rtx_costs): Update cost for arm_disable_literal_pool. (thumb1_size_rtx_costs): Likewise. (arm_output_mi_thunk): Avoid literal usage for target_execute_only. * config/arm/arm.md (casesi): Disable for target_execute_only. * config/arm/arm.opt (target_execute_only): New option. * config/arm/thumb1.md (define_insn "thumb1_movsi_symbol_ref"): New. (define_insn "*thumb1_movsi_const_int"): New. (define_split for generate integer constant): New. (define_insn "*thumb1_movsi_insn"): Set use_literal_pool attribute so it's enabled/disabled according to arm_disable_literal_pool. (define_expand "tablejump"): Disable for target_execute_only. * doc/invoke.texi (mexecute-only): New.
gcc/testsuite/ChangeLog: * gcc.target/arm/thumb1-execute-only-switch.c: New. * gcc.target/arm/thumb1-execute-only.c: New. * gcc.target/arm/thumb2-execute-only-switch.c: New. * gcc.target/arm/thumb2-execute-only.c: New. This option generate code that don't load no data from text section. --- gcc/config/arm/arm-protos.h | 1 + gcc/config/arm/arm.c | 114 +++++++++++++++++++-- gcc/config/arm/arm.md | 2 +- gcc/config/arm/arm.opt | 4 + gcc/config/arm/thumb1.md | 71 +++++++++++-- gcc/doc/invoke.texi | 7 ++ .../gcc.target/arm/thumb1-execute-only-switch.c | 23 +++++ gcc/testsuite/gcc.target/arm/thumb1-execute-only.c | 69 +++++++++++++ .../gcc.target/arm/thumb2-execute-only-switch.c | 23 +++++ gcc/testsuite/gcc.target/arm/thumb2-execute-only.c | 68 ++++++++++++ 10 files changed, 368 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c create mode 100644 gcc/testsuite/gcc.target/arm/thumb1-execute-only.c create mode 100644 gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c create mode 100644 gcc/testsuite/gcc.target/arm/thumb2-execute-only.c diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 28f2263..e08842e 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -59,6 +59,7 @@ extern bool arm_modes_tieable_p (machine_mode, machine_mode); extern int const_ok_for_arm (HOST_WIDE_INT); extern int const_ok_for_op (HOST_WIDE_INT, enum rtx_code); extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code); +extern void thumb1_gen_const_int (rtx, HOST_WIDE_INT); extern int arm_split_constant (RTX_CODE, machine_mode, rtx, HOST_WIDE_INT, rtx, rtx, int); extern int legitimate_pic_operand_p (rtx); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index f152afa..fe8e018 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -300,6 +300,12 @@ static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void); static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*); + +static section *arm_function_section (tree decl, enum node_frequency freq, + bool startup, bool exit); + +static unsigned int arm_section_type_flags (tree, const char *, int); + /* Table of machine attributes. */ static const struct attribute_spec arm_attribute_table[] = @@ -735,6 +741,12 @@ static const struct attribute_spec arm_attribute_table[] = #undef TARGET_SCHED_FUSION_PRIORITY #define TARGET_SCHED_FUSION_PRIORITY arm_sched_fusion_priority +#undef TARGET_ASM_FUNCTION_SECTION +#define TARGET_ASM_FUNCTION_SECTION arm_function_section + +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS arm_section_type_flags + struct gcc_target targetm = TARGET_INITIALIZER; /* Obstack for minipool constant handling. */ @@ -3428,6 +3440,15 @@ arm_option_override (void) if (target_slow_flash_data) arm_disable_literal_pool = true; + /* We only support -mexecute-only on M-profile targets. */ + if (target_execute_only && (flag_pic || !(!arm_arch_notm || arm_arch7em))) + error ("-mexecute-only only supports non-pic code on M-profile targets"); + + /* In execute-only mode we don't want any memory read into text section and + so we disable literal pool. */ + if (target_execute_only) + arm_disable_literal_pool = true; + /* Disable scheduling fusion by default if it's not armv7 processor or doesn't prefer ldrd/strd. */ if (flag_schedule_fusion == 2 @@ -3969,6 +3990,36 @@ const_ok_for_dimode_op (HOST_WIDE_INT i, enum rtx_code code) } } +/* Emit a sequence of movs/adds/shift to produce a 32-bit constant. + Avoid generating useless code when byte is zero. */ +void +thumb1_gen_const_int (rtx op0, HOST_WIDE_INT op1) +{ + int is_mov_done = 0; + int i; + + /* Emit upper 3 bytes if needed. */ + for (i = 0; i < 3; i++) + { + int byte = (op1 >> (8 * (3 - i))) & 0xff; + + if (byte) + { + emit_set_insn (op0, is_mov_done? + gen_rtx_PLUS (SImode,op0, GEN_INT (byte)): + GEN_INT (byte)); + is_mov_done = 1; + } + if (is_mov_done) + emit_set_insn (op0, gen_rtx_ASHIFT (SImode, op0, GEN_INT (8))); + } + /* Emit lower byte if needed. */ + if (!is_mov_done) + emit_set_insn (op0, GEN_INT (op1&0xff)); + else if (op1&0xff) + emit_set_insn (op0, gen_rtx_PLUS (SImode, op0, GEN_INT (op1&0xff))); +} + /* Emit a sequence of insns to handle a large constant. CODE is the code of the operation required, it can be any of SET, PLUS, IOR, AND, XOR, MINUS; @@ -7621,7 +7672,8 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p) /* This is PC relative data before arm_reorg runs. */ else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x) && GET_CODE (x) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic) + && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic + && !arm_disable_literal_pool) return 1; /* This is PC relative data after arm_reorg runs. */ @@ -7689,6 +7741,7 @@ thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p) && GET_MODE_SIZE (mode) == 4 && GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x) + && !arm_disable_literal_pool && ! (flag_pic && symbol_mentioned_p (get_pool_constant (x)) && ! pcrel_constant_p (get_pool_constant (x)))) @@ -8296,7 +8349,8 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) return 0; if (thumb_shiftable_const (INTVAL (x))) return COSTS_N_INSNS (2); - return COSTS_N_INSNS (3); + return arm_disable_literal_pool ? COSTS_N_INSNS (8) :\ + COSTS_N_INSNS (3); } else if ((outer == PLUS || outer == COMPARE) && INTVAL (x) < 256 && INTVAL (x) > -256) @@ -9058,7 +9112,8 @@ thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) /* See split "TARGET_THUMB1 && satisfies_constraint_K". */ if (thumb_shiftable_const (INTVAL (x))) return COSTS_N_INSNS (2); - return COSTS_N_INSNS (3); + return arm_disable_literal_pool ? COSTS_N_INSNS (8) :\ + COSTS_N_INSNS (3); } else if ((outer == PLUS || outer == COMPARE) && INTVAL (x) < 256 && INTVAL (x) > -256) @@ -26097,14 +26152,36 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, /* push r3 so we can use it as a temporary. */ /* TODO: Omit this save if r3 is not used. */ fputs ("\tpush {r3}\n", file); - fputs ("\tldr\tr3, ", file); + if (target_execute_only) + { + fputs ("\tmovs\tr3, #:upper8_15:#", file); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fputc ('\n', file); + fputs ("\tlsls r3, #8\n", file); + fputs ("\tadds\tr3, #:upper0_7:#", file); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fputc ('\n', file); + fputs ("\tlsls r3, #8\n", file); + fputs ("\tadds\tr3, #:lower8_15:#", file); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fputc ('\n', file); + fputs ("\tlsls r3, #8\n", file); + fputs ("\tadds\tr3, #:lower0_7:#", file); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fputc ('\n', file); + } + else + fputs ("\tldr\tr3, ", file); } else { fputs ("\tldr\tr12, ", file); } - assemble_name (file, label); - fputc ('\n', file); + if (!target_execute_only) + { + assemble_name (file, label); + fputc ('\n', file); + } if (flag_pic) { /* If we are generating PIC, the ldr instruction below loads @@ -30188,4 +30265,29 @@ arm_sched_fusion_priority (rtx_insn *insn, int max_pri, return; } +/* Implement the TARGET_ASM_FUNCTION_SECTION hook. + + Be sure that code compiled with mexecute-only is not moved in a section + name '.text' so SECTION_NOREAD attribute is not removed by assembler. */ +static section * +arm_function_section (tree decl, + enum node_frequency freq, + bool startup, + bool exit) +{ + return target_execute_only ? + get_named_text_section (decl, ".text.noread", NULL): + default_function_section (decl, freq, startup, exit); +} + +/* Implement the TARGET_SECTION_TYPE_FLAGS hook. */ + +static unsigned int +arm_section_type_flags (tree decl, const char *name, int reloc) +{ + unsigned int flags = default_section_type_flags (decl, name, reloc); + + return target_execute_only ? flags|SECTION_NOREAD : flags; +} + #include "gt-arm.h" diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 64873a2..a0ccbc6 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -8179,7 +8179,7 @@ (match_operand:SI 2 "const_int_operand" "") ; total range (match_operand:SI 3 "" "") ; table label (match_operand:SI 4 "" "")] ; Out of range label - "TARGET_32BIT || optimize_size || flag_pic" + "(TARGET_32BIT || optimize_size || flag_pic) && !target_execute_only" " { enum insn_code code; diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt index 0ebe017..b16a51a 100644 --- a/gcc/config/arm/arm.opt +++ b/gcc/config/arm/arm.opt @@ -281,3 +281,7 @@ Assume loading data from flash is slower than fetching instructions. masm-syntax-unified Target Report Var(inline_asm_unified) Init(0) Save Assume unified syntax for inline assembly code. + +mexecute-only +Target Report Var(target_execute_only) Init(0) +Forbid load into text sections. diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md index 072ed4d..b4e0a0a 100644 --- a/gcc/config/arm/thumb1.md +++ b/gcc/config/arm/thumb1.md @@ -41,7 +41,62 @@ ;; differently). In particular there is no Thumb1 armv6-m pattern for ;; sbc or adc. +(define_insn "thumb1_movsi_symbol_ref" + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "general_operand" "")) + ] + "TARGET_THUMB1 + && arm_disable_literal_pool + && GET_CODE (operands[1]) == SYMBOL_REF" + "* + output_asm_insn (\"movs\\t%0, #:upper8_15:%1\", operands); + output_asm_insn (\"lsls\\t%0, #8\", operands); + output_asm_insn (\"adds\\t%0, #:upper0_7:%1\", operands); + output_asm_insn (\"lsls\\t%0, #8\", operands); + output_asm_insn (\"adds\\t%0, #:lower8_15:%1\", operands); + output_asm_insn (\"lsls\\t%0, #8\", operands); + output_asm_insn (\"adds\\t%0, #:lower0_7:%1\", operands); + return \"\"; + " + [(set_attr "length" "14") + (set_attr "conds" "clob")] +) + +(define_insn "*thumb1_movsi_const_int" + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "immediate_operand" "i")) + ] + "TARGET_THUMB1 + && arm_disable_literal_pool + && GET_CODE (operands[1]) == CONST_INT + && !satisfies_constraint_I (operands[1])" + "* + output_asm_insn (\"movs\\t%0, #(%c1>>24)&0xff\", operands); + output_asm_insn (\"lsls\\t%0, #8\", operands); + output_asm_insn (\"adds\\t%0, #(%c1>>16)&0xff\", operands); + output_asm_insn (\"lsls\\t%0, #8\", operands); + output_asm_insn (\"adds\\t%0, #(%c1>>8)&0xff\", operands); + output_asm_insn (\"lsls\\t%0, #8\", operands); + output_asm_insn (\"adds\\t%0, #%c1&0xff\", operands); + return \"\"; + " + [(set_attr "length" "14") + (set_attr "conds" "clob")] +) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "immediate_operand" ""))] + "TARGET_THUMB1 + && arm_disable_literal_pool + && GET_CODE (operands[1]) == CONST_INT + && !satisfies_constraint_I (operands[1])" + [(clobber (const_int 0))] + " + thumb1_gen_const_int (operands[0], INTVAL (operands[1])); + DONE; + " +) (define_insn "*thumb1_adddi3" [(set (match_operand:DI 0 "register_operand" "=l") @@ -632,8 +687,8 @@ ) (define_insn "*thumb1_movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*l*h*k") - (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*l*h*k"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,l, m,*l*h*k") + (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,m,mi,l,*l*h*k"))] "TARGET_THUMB1 && ( register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" @@ -645,12 +700,14 @@ ldmia\\t%1, {%0} stmia\\t%0, {%1} ldr\\t%0, %1 + ldr\\t%0, %1 str\\t%1, %0 mov\\t%0, %1" - [(set_attr "length" "2,2,4,4,2,2,2,2,2") - (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,store1,mov_reg") - (set_attr "pool_range" "*,*,*,*,*,*,1018,*,*") - (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond")]) + [(set_attr "length" "2,2,4,4,2,2,2,2,2,2") + (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,load1,store1,mov_reg") + (set_attr "pool_range" "*,*,*,*,*,*,1018,1018,*,*") + (set_attr "use_literal_pool" "no,no,no,no,no,no,no,yes,no,no") + (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond,nocond")]) ; Split the load of 64-bit constant into two loads for high and low 32-bit parts respectively ; to see if we can load them in fewer instructions or fewer cycles. @@ -1760,7 +1817,7 @@ (define_expand "tablejump" [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "")) (use (label_ref (match_operand 1 "" "")))])] - "TARGET_THUMB1" + "TARGET_THUMB1 && !target_execute_only" " if (flag_pic) { diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ba0b4b2..cb43fdd 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -630,6 +630,7 @@ Objective-C and Objective-C++ Dialects}. -munaligned-access @gol -mneon-for-64bits @gol -mslow-flash-data @gol +-mexecute-only @gol -masm-syntax-unified @gol -mrestrict-it} @@ -14139,6 +14140,12 @@ Therefore literal load is minimized for better performance. This option is only supported when compiling for ARMv7 M-profile and off by default. +@item -mexecute-only +@opindex mexecute-only +Disable read memory access inside code sections. Only code fetching is +allowed. +This option is off by default. + @item -masm-syntax-unified @opindex masm-syntax-unified Assume inline assembler is using unified asm syntax. The default is diff --git a/gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c b/gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c new file mode 100644 index 0000000..f9bba9f --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_cortex_m } */ +/* { dg-require-effective-target arm_thumb1_ok } */ +/* { dg-options "-O2 -march=armv6s-m -mthumb -mexecute-only" } */ + +int +foo (int a) +{ + switch (a) + { + case 0: return 12; + case 1: return 2; + case 2: return 1231; + case 3: return 0xdead; + default: + break; + } + + return -1; +} + +/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */ + diff --git a/gcc/testsuite/gcc.target/arm/thumb1-execute-only.c b/gcc/testsuite/gcc.target/arm/thumb1-execute-only.c new file mode 100644 index 0000000..90b74df --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/thumb1-execute-only.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_cortex_m } */ +/* { dg-require-effective-target arm_thumb1_ok } */ +/* { dg-options "-O2 -march=armv6s-m -mthumb -mexecute-only" } */ + +float sf; +double df; +long long l; +static char *p = "Hello World"; + +float +testsf (float *p) +{ + if (*p > 1.1234f) + return 2.1234f; + else + return 3.1234f; +} + +double +testdf (double *p) +{ + if (*p > 4.1234) + return 2.1234; + else + return 3.1234; +} + +long long +testll (long long *p) +{ + if (*p > 0x123456789ABCDEFll) + return 0x111111111ll; + else + return 0x222222222ll; +} + +char * +testchar () +{ + return p + 4; +} + +int +foo (int a, int b) +{ + int i; + int *labelref = &&label1; + + if (a > b) + { + while (i < b) + { + a += *labelref; + i += 1; + } + goto *labelref; + } + else + b = b + 3; + + a = a * b; + +label1: + return a + b; +} + +/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */ + diff --git a/gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c b/gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c new file mode 100644 index 0000000..2493c28 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_cortex_m } */ +/* { dg-require-effective-target arm_thumb2_ok } */ +/* { dg-options "-O2 -march=armv7-m -mthumb -mexecute-only" } */ + +int +foo (int a) +{ + switch (a) + { + case 0: return 12; + case 1: return 2; + case 2: return 1231; + case 3: return 0xdead; + default: + break; + } + + return -1; +} + +/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */ +/* { dg-final { scan-assembler-not "ldrls\[\t \]+r\[0-9\]+, .L" } } */ diff --git a/gcc/testsuite/gcc.target/arm/thumb2-execute-only.c b/gcc/testsuite/gcc.target/arm/thumb2-execute-only.c new file mode 100644 index 0000000..10b7fd1 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/thumb2-execute-only.c @@ -0,0 +1,68 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_cortex_m } */ +/* { dg-require-effective-target arm_thumb2_ok } */ +/* { dg-options "-O2 -march=armv7-m -mthumb -mexecute-only" } */ + +float sf; +double df; +long long l; +static char *p = "Hello World"; + +float +testsf (float *p) +{ + if (*p > 1.1234f) + return 2.1234f; + else + return 3.1234f; +} + +double +testdf (double *p) +{ + if (*p > 4.1234) + return 2.1234; + else + return 3.1234; +} + +long long +testll (long long *p) +{ + if (*p > 0x123456789ABCDEFll) + return 0x111111111ll; + else + return 0x222222222ll; +} + +char * +testchar () +{ + return p + 4; +} + +int +foo (int a, int b) +{ + int i; + int *labelref = &&label1; + + if (a > b) + { + while (i < b) + { + a += *labelref; + i += 1; + } + goto *labelref; + } + else + b = b + 3; + + a = a * b; + +label1: + return a + b; +} + +/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */ -- 2.7.0.rc3