From d10b48c9527fe0bcd5f35cb4086712fdb74056d4 Mon Sep 17 00:00:00 2001 From: Christoph Muellner Date: Fri, 2 Mar 2018 17:09:19 +0100 Subject: aarch64: Retpoline (Spectre-V2 mitigation) for aarch64. The compiler option -mindirect-branch= converts indirect branch-and-link-register and branch-register instructions according to . The default is ``keep``, which keeps indirect branch-and-link-register and branch-register instructions unmodified. ``thunk`` converts indirect branch-and-link-register/branch-register instructions to a branch-and-link/branch to a function containing a retpoline (to stop speculative execution) followed by a branch-register to the target. ``thunk-inline`` is similar to ``thunk``, but inlines the retpoline before the branch-and-link-register/branch-register instruction. ``thunk-extern`` is also similar to ``thunk``, but does not insert the functions containing the retpoline. When using this option, these functions need to be provided in a separate object file. The retpoline functions exist for each register and are named ``__aarch64_indirect_thunk_xN`` (N being the register number). It is also possible to override the indirect-branch setting for individual fuctions using the function attribute ``indirect_branch``. The actual retpoline instruction sequence, which prevents speculative indirect branches looks like this:: str x30, [sp, #-16]! bl 101f 100: //speculation trap wfe b 100b 101: //do ROP adrp x30, 102f add x30, x30, :lo12:102f ret 102: //non-spec code ldr x30, [sp], #16 This patch has been tested with the included testcases and various other source bases (benchmarks, retpoline-patched arm64 kernel, etc.). Signed-off-by: Christoph Muellner --- gcc/config/aarch64/aarch64-opts.h | 9 + gcc/config/aarch64/aarch64-protos.h | 2 + gcc/config/aarch64/aarch64.c | 310 ++++++++++++++++++++- gcc/config/aarch64/aarch64.h | 4 + gcc/config/aarch64/aarch64.md | 10 +- gcc/config/aarch64/aarch64.opt | 20 ++ gcc/doc/invoke.texi | 20 +- .../gcc.target/aarch64/indirect-thunk-1.c | 26 ++ .../gcc.target/aarch64/indirect-thunk-2.c | 27 ++ .../gcc.target/aarch64/indirect-thunk-3.c | 27 ++ .../gcc.target/aarch64/indirect-thunk-4.c | 28 ++ .../gcc.target/aarch64/indirect-thunk-5.c | 26 ++ .../gcc.target/aarch64/indirect-thunk-6.c | 27 ++ .../gcc.target/aarch64/indirect-thunk-attr-1.c | 29 ++ .../gcc.target/aarch64/indirect-thunk-attr-2.c | 28 ++ .../gcc.target/aarch64/indirect-thunk-attr-3.c | 30 ++ .../gcc.target/aarch64/indirect-thunk-attr-4.c | 29 ++ .../gcc.target/aarch64/indirect-thunk-attr-5.c | 25 ++ .../gcc.target/aarch64/indirect-thunk-attr-6.c | 25 ++ .../gcc.target/aarch64/indirect-thunk-extern-1.c | 22 ++ .../gcc.target/aarch64/indirect-thunk-extern-2.c | 23 ++ .../gcc.target/aarch64/indirect-thunk-extern-3.c | 23 ++ .../gcc.target/aarch64/indirect-thunk-extern-4.c | 24 ++ .../gcc.target/aarch64/indirect-thunk-extern-5.c | 20 ++ .../gcc.target/aarch64/indirect-thunk-extern-6.c | 21 ++ .../gcc.target/aarch64/indirect-thunk-inline-1.c | 26 ++ .../gcc.target/aarch64/indirect-thunk-inline-2.c | 27 ++ .../gcc.target/aarch64/indirect-thunk-inline-3.c | 27 ++ .../gcc.target/aarch64/indirect-thunk-inline-4.c | 28 ++ .../gcc.target/aarch64/indirect-thunk-inline-5.c | 24 ++ .../gcc.target/aarch64/indirect-thunk-inline-6.c | 25 ++ 31 files changed, 985 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h index ba5d052e9b69..14d9372e561e 100644 --- a/gcc/config/aarch64/aarch64-opts.h +++ b/gcc/config/aarch64/aarch64-opts.h @@ -81,4 +81,13 @@ enum aarch64_function_type { AARCH64_FUNCTION_ALL }; +/* Values for -mindirect-branch option. */ +enum indirect_branch { + indirect_branch_unset = 0, + indirect_branch_keep, + indirect_branch_thunk, + indirect_branch_thunk_inline, + indirect_branch_thunk_extern +}; + #endif diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 9543f8c9f297..8fb61013ce90 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -332,6 +332,8 @@ bool aarch64_mov_operand_p (rtx, machine_mode); int aarch64_simd_attr_length_rglist (enum machine_mode); rtx aarch64_reverse_mask (enum machine_mode); bool aarch64_offset_7bit_signed_scaled_p (machine_mode, HOST_WIDE_INT); +const char *aarch64_output_branch_register (rtx); +const char *aarch64_output_branch_and_link_register (rtx); char *aarch64_output_scalar_simd_mov_immediate (rtx, machine_mode); char *aarch64_output_simd_mov_immediate (rtx, machine_mode, unsigned); bool aarch64_pad_arg_upward (machine_mode, const_tree); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 436091af9342..95570c229d7b 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -37,6 +37,7 @@ #include "regs.h" #include "emit-rtl.h" #include "recog.h" +#include "cgraph.h" #include "diagnostic.h" #include "insn-attr.h" #include "alias.h" @@ -9095,6 +9096,35 @@ aarch64_save_restore_target_globals (tree new_tree) TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts (); } +static void +aarch64_set_indirect_branch_type (tree fndecl) +{ + if (cfun->machine->indirect_branch_type == indirect_branch_unset) + { + tree attr = lookup_attribute ("indirect_branch", + DECL_ATTRIBUTES (fndecl)); + if (attr != NULL) + { + tree args = TREE_VALUE (attr); + if (args == NULL) + gcc_unreachable (); + tree cst = TREE_VALUE (args); + if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0) + cfun->machine->indirect_branch_type = indirect_branch_keep; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0) + cfun->machine->indirect_branch_type = indirect_branch_thunk; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0) + cfun->machine->indirect_branch_type = indirect_branch_thunk_inline; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0) + cfun->machine->indirect_branch_type = indirect_branch_thunk_extern; + else + gcc_unreachable (); + } + else + cfun->machine->indirect_branch_type = aarch64_indirect_branch; + } +} + /* Implement TARGET_SET_CURRENT_FUNCTION. Unpack the codegen decisions like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET of the function, if such exists. This function may be called multiple @@ -9105,7 +9135,18 @@ static void aarch64_set_current_function (tree fndecl) { if (!fndecl || fndecl == aarch64_previous_fndecl) - return; + { + if (fndecl != NULL_TREE) + { + aarch64_set_indirect_branch_type (fndecl); + } + return; + } + + if (fndecl != NULL_TREE) + { + aarch64_set_indirect_branch_type (fndecl); + } tree old_tree = (aarch64_previous_fndecl ? DECL_FUNCTION_SPECIFIC_TARGET (aarch64_previous_fndecl) @@ -9275,6 +9316,42 @@ aarch64_handle_attr_tune (const char *str, const char *pragma_or_attr) return false; } +static tree +aarch64_handle_fndecl_attribute (tree *node, tree name, tree args, int, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + } + + if (is_attribute_p ("indirect_branch", name)) + { + tree cst = TREE_VALUE (args); + if (TREE_CODE (cst) != STRING_CST) + { + warning (OPT_Wattributes, + "%qE attribute requires a string constant argument", + name); + *no_add_attrs = true; + } + else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0 + && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0 + && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0 + && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0) + { + warning (OPT_Wattributes, + "argument to %qE attribute is not " + "(keep|thunk|thunk-inline|thunk-extern)", name); + *no_add_attrs = true; + } + } + + return NULL_TREE; +} + /* Parse an architecture extensions target attribute string specified in STR. For example "+fp+nosimd". Show any errors if needed. Return TRUE if successful. Update aarch64_isa_flags to reflect the ISA features @@ -12603,6 +12680,219 @@ aarch64_output_scalar_simd_mov_immediate (rtx immediate, return aarch64_output_simd_mov_immediate (v_op, vmode, 64); } +/* Label count for call and return thunks. It is used to make unique + labels in call and return thunks. */ +static int indirectlabelno; + +/* Bit masks of integer registers, which contain branch target, used + by call and return thunks functions. */ +static int indirect_thunks_used; + +#ifndef INDIRECT_LABEL +# define INDIRECT_LABEL "LIND" +#endif + +/* Fills in the label name that should be used for the indirect thunk. */ + +static void +indirect_thunk_name (char name[32], int regno) +{ + sprintf (name, "__aarch64_indirect_thunk_%s", + reg_names[regno]); +} + +/* Output a retpoline thunk for aarch64: + + push lr + bl L2 +L1: wfe + dsb sy + b L1 +L2: mov lr, &L3 + ret +L3: pop lr + */ + +static void +output_indirect_thunk (bool save_lr) +{ + char indirectlabel1[32]; + char indirectlabel2[32]; + char indirectlabel3[32]; + + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel3, INDIRECT_LABEL, + indirectlabelno++); + + if (save_lr) + { + /* push lr */ + fputs ("\tstr\tx30, [sp, #-16]!\n", asm_out_file); + } + + /* bl L2 */ + fputs ("\tbl\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel2); + fputc ('\n', asm_out_file); + + /* L1: wfe/dsb loop */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); + fprintf (asm_out_file, "\twfe\n"); + fputs ("\tb\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel1); + fputc ('\n', asm_out_file); + + /* L2: lr=&L3; ret */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); + fputs ("\tadrp\tx30, ", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel3); + fputc ('\n', asm_out_file); + fputs ("\tadd\tx30, x30, :lo12:", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel3); + fputc ('\n', asm_out_file); + fputs ("\tret\n", asm_out_file); + + /* L3: */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel3); + + if (save_lr) + { + /* pop lr */ + fputs ("\tldr\tx30, [sp], #16\n", asm_out_file); + } +} + +static void +output_indirect_thunk_function(int regno) +{ + char name[32]; + tree decl; + + /* Create __aarch64_indirect_thunk */ + indirect_thunk_name (name, regno); + decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + get_identifier (name), + build_function_type_list (void_type_node, NULL_TREE)); + DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL, + NULL_TREE, void_type_node); + TREE_PUBLIC (decl) = 1; + TREE_STATIC (decl) = 1; + DECL_IGNORED_P (decl) = 1; + + cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl)); + + targetm.asm_out.unique_section (decl, 0); + switch_to_section (get_named_section (decl, NULL, 0)); + + targetm.asm_out.globalize_label (asm_out_file, name); + fputs ("\t.hidden\t", asm_out_file); + assemble_name (asm_out_file, name); + putc ('\n', asm_out_file); + ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl); + + DECL_INITIAL (decl) = make_node (BLOCK); + current_function_decl = decl; + allocate_struct_function (decl, false); + init_function_start (decl); + /* We're about to hide the function body from callees of final_* by + emitting it directly; tell them we're a thunk, if they care. */ + cfun->is_thunk = true; + first_function_block_is_cold = false; + /* Make sure unwind info is emitted for the thunk if needed. */ + final_start_function (emit_barrier (), asm_out_file, 1); + + output_indirect_thunk (true); + rtx xop = gen_rtx_REG(word_mode, regno); + output_asm_insn("br\t%0", &xop); + + final_end_function (); + init_insn_lengths (); + free_after_compilation (cfun); + set_cfun (NULL); + current_function_decl = NULL; +} + +const char * +aarch64_output_branch_register (rtx call_op) +{ + char thunk_name_buf[32]; + char *thunk_name; + int regno = REGNO (call_op); + + if (cfun->machine->indirect_branch_type == indirect_branch_thunk_inline) + { + output_indirect_thunk (true); + output_asm_insn ("br\t%0", &call_op); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk) + { + indirect_thunks_used |= 1 << regno; + + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tb\t%s\n", thunk_name); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk_extern) + { + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tb\t%s\n", thunk_name); + } + else + { + output_asm_insn ("br\t%0", &call_op); + } + return ""; +} + +const char * +aarch64_output_branch_and_link_register (rtx call_op) +{ + char thunk_name_buf[32]; + char *thunk_name; + int regno = REGNO (call_op); + + if (cfun->machine->indirect_branch_type == indirect_branch_thunk_inline) + { + output_indirect_thunk (true); + output_asm_insn ("blr\t%0", &call_op); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk) + { + indirect_thunks_used |= 1 << regno; + + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tbl\t%s\n", thunk_name); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk_extern) + { + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tbl\t%s\n", thunk_name); + } + else + { + output_asm_insn ("blr\t%0", &call_op); + } + return ""; +} + +static void +aarch64_code_end (void) +{ + int regno; + + for (regno = R0_REGNUM; regno <= SP_REGNUM; regno++) + { + if (indirect_thunks_used & (1 << regno)) + output_indirect_thunk_function(regno); + } +} + /* Split operands into moves from op[1] + op[2] into op[0]. */ void @@ -14708,6 +14998,15 @@ aarch64_sched_can_speculate_insn (rtx_insn *insn) } } +/* Table of valid machine attributes. */ +static const struct attribute_spec aarch64_attribute_table[] = +{ + { "indirect_branch", 1, 1, true, false, false, + aarch64_handle_fndecl_attribute, false }, + /* End element. */ + { NULL, 0, 0, false, false, false, NULL, false } +}; + /* Target-specific selftests. */ #if CHECKING_P @@ -14777,6 +15076,9 @@ aarch64_run_selftests (void) #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ hook_bool_const_tree_hwi_hwi_const_tree_true +#undef TARGET_ASM_CODE_END +#define TARGET_ASM_CODE_END aarch64_code_end + #undef TARGET_ASM_FILE_START #define TARGET_ASM_FILE_START aarch64_start_file @@ -14789,6 +15091,12 @@ aarch64_run_selftests (void) #undef TARGET_ASM_TRAMPOLINE_TEMPLATE #define TARGET_ASM_TRAMPOLINE_TEMPLATE aarch64_asm_trampoline_template +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table + +#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_const_tree_true + #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST aarch64_build_builtin_va_list diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 52d6414cbf46..fc8250f9290e 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -601,6 +601,10 @@ typedef struct GTY (()) machine_function struct aarch64_frame frame; /* One entry for each hard register. */ bool reg_is_wrapped_separately[LAST_SAVED_REGNUM]; + + /* How to generate indirec branch. */ + ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3; + } machine_function; #endif diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 51368e29f2d1..45c27cd84e9d 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -234,7 +234,7 @@ (define_insn "indirect_jump" [(set (pc) (match_operand:DI 0 "register_operand" "r"))] "" - "br\\t%0" + "* return aarch64_output_branch_register (operands[0]);" [(set_attr "type" "branch")] ) @@ -755,7 +755,7 @@ (use (match_operand 2 "" "")) (clobber (reg:DI LR_REGNUM))] "" - "blr\\t%0" + "* return aarch64_output_branch_and_link_register (operands[0]);" [(set_attr "type" "call")] ) @@ -817,7 +817,7 @@ (use (match_operand 3 "" "")) (clobber (reg:DI LR_REGNUM))] "" - "blr\\t%1" + "* return aarch64_output_branch_and_link_register (operands[1]);" [(set_attr "type" "call")] ) @@ -903,7 +903,7 @@ (use (match_operand 2 "" ""))] "SIBLING_CALL_P (insn)" "@ - br\\t%0 + * return aarch64_output_branch_register (operands[0]); b\\t%a0" [(set_attr "type" "branch, branch")] ) @@ -917,7 +917,7 @@ (use (match_operand 3 "" ""))] "SIBLING_CALL_P (insn)" "@ - br\\t%1 + * return aarch64_output_branch_register (operands[1]); b\\t%a1" [(set_attr "type" "branch, branch")] ) diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 942a7d558f26..65c6d03fb2bf 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -188,3 +188,23 @@ single precision and to 32 bits for double precision. mverbose-cost-dump Common Undocumented Var(flag_aarch64_verbose_cost) Enables verbose cost model dumping in the debug dump files. + +mindirect-branch= +Target Report RejectNegative Joined Enum(indirect_branch) Var(aarch64_indirect_branch) Init(indirect_branch_keep) +Convert indirect branch-and-link and branch to branch-and-link and return thunks. + +Enum +Name(indirect_branch) Type(enum indirect_branch) +Known indirect branch choices (for use with the -mindirect-branch= options): + +EnumValue +Enum(indirect_branch) String(keep) Value(indirect_branch_keep) + +EnumValue +Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk) + +EnumValue +Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline) + +EnumValue +Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6f3c344476c6..629f2c5e530a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -588,7 +588,8 @@ Objective-C and Objective-C++ Dialects}. -mlow-precision-recip-sqrt -mno-low-precision-recip-sqrt@gol -mlow-precision-sqrt -mno-low-precision-sqrt@gol -mlow-precision-div -mno-low-precision-div @gol --march=@var{name} -mcpu=@var{name} -mtune=@var{name}} +-march=@var{name} -mcpu=@var{name} -mtune=@var{name} +-mindirect-branch=@var{choice}} @emph{Adapteva Epiphany Options} @gccoptlist{-mhalf-reg-file -mprefer-short-insn-regs @gol @@ -14050,6 +14051,23 @@ Permissible values are @samp{none}, which disables return address signing, functions, and @samp{all}, which enables pointer signing for all functions. The default value is @samp{none}. +@item -mindirect-branch=@var{choice} +@opindex -mindirect-branch +Convert indirect branch-and-link-register and branch-register with @var{choice}. +The default is @samp{keep}, which keeps indirect branch-and-link-register and +branch-register instructions unmodified. +@samp{thunk} converts indirect branch-and-link-register/branch-register +instructions to a branch-and-link/branch to a function containing a retpoline +(to stop speculative execution) followed by a branch-register to the target. +@samp{thunk-inline} similar to @samp{thunk}, but inlines the retpoline +before the branch-and-link-register/branch-register instruction. +@samp{thunk-extern} similar to @samp{thunk}, but does not insert the functions +containing the retpoline. When using this option, these functions need to be +provided in a separate object file. The retpoline functions exist for each +register and are named __aarch64_indirect_thunk_xN (N being the register number). +You can control this behavior for a specific function by using the +function attribute @code{indirect_branch}. @xref{Function Attributes}. + @end table @subsubsection @option{-march} and @option{-mcpu} Feature Modifiers diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c new file mode 100644 index 000000000000..256aee2e1a2a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c new file mode 100644 index 000000000000..8e6dc31171ad --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c new file mode 100644 index 000000000000..2c9938244b99 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c new file mode 100644 index 000000000000..d09c37d8045e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c new file mode 100644 index 000000000000..d93217554ec1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x0" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x0" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c new file mode 100644 index 000000000000..e54fc0d272a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x0" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x0" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c new file mode 100644 index 000000000000..a2ae84af6c23 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +extern void male_indirect_jump (long) + __attribute__ ((indirect_branch("thunk"))); + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c new file mode 100644 index 000000000000..0f3b4d55afc7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +__attribute__ ((indirect_branch("thunk"))) +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c new file mode 100644 index 000000000000..7ff66e8d0fc0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; +extern int male_indirect_jump (long) + __attribute__ ((indirect_branch("thunk-inline"))); + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ + diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c new file mode 100644 index 000000000000..0734295ae89b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +__attribute__ ((indirect_branch("thunk-inline"))) +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c new file mode 100644 index 000000000000..916288421cfc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; +extern int male_indirect_jump (long) + __attribute__ ((indirect_branch("thunk-extern"))); + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c new file mode 100644 index 000000000000..34649e213705 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +__attribute__ ((indirect_branch("thunk-extern"))) +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c new file mode 100644 index 000000000000..da4936d7b99c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c new file mode 100644 index 000000000000..b7a6a693ebea --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c new file mode 100644 index 000000000000..d4143b173612 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c new file mode 100644 index 000000000000..f488a719f2a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c new file mode 100644 index 000000000000..d20a668121a0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x0" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c new file mode 100644 index 000000000000..635b53b35b90 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x0" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c new file mode 100644 index 000000000000..b70f07131202 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c new file mode 100644 index 000000000000..e58e4ad32c73 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c new file mode 100644 index 000000000000..a253fa20acea --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:dispatch\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c new file mode 100644 index 000000000000..7061da768a82 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, dispatch" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:dispatch" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c new file mode 100644 index 000000000000..7945fd184802 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x0" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c new file mode 100644 index 000000000000..556aa58be559 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x0" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ -- cgit v1.2.3