From 7fc42ccf0f636cd0df97569a262336933a36c0b3 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Thu, 14 Jan 2016 13:01:25 -0800 Subject: Remove -Bsymbolic from the Android link spec. Bug: http://b.android.com/68956 Change-Id: I60bef8715de7920d72ebc9a6bd7f18ceaea05966 --- gcc-4.9/gcc/config/linux-android.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc-4.9/gcc/config/linux-android.h b/gcc-4.9/gcc/config/linux-android.h index 76654c34b..6995785da 100644 --- a/gcc-4.9/gcc/config/linux-android.h +++ b/gcc-4.9/gcc/config/linux-android.h @@ -38,7 +38,7 @@ "%{" NOANDROID "|tno-android-ld:" LINUX_SPEC ";:" ANDROID_SPEC "}" #define ANDROID_LINK_SPEC \ - "%{shared: -Bsymbolic} -z noexecstack -z relro -z now" + "-z noexecstack -z relro -z now" #define ANDROID_CC1_SPEC(ANDROID_PIC_DEFAULT) \ "%{!mglibc:%{!muclibc:%{!mbionic: -mbionic}}} " \ -- cgit v1.2.3 From fe948798823b679925aed6b60efec51b9af7dd09 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Mon, 10 Jul 2017 15:23:24 -0700 Subject: Add an OWNERS file for GCC. Bug: None Test: None Change-Id: I5c573476a7c4e341b6eafa6d1050334f63526585 --- OWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 OWNERS diff --git a/OWNERS b/OWNERS new file mode 100644 index 000000000..88b3a39ef --- /dev/null +++ b/OWNERS @@ -0,0 +1,6 @@ +cmtice@google.com +laszio@google.com +llozano@google.com +manojgupta@google.com +rahulchaudhry@google.com +yunlian@google.com -- cgit v1.2.3 From 0c5a656a1322e137fa4a251f2ccc6c4022918c0a Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Wed, 12 Jul 2017 15:36:32 -0700 Subject: Disable linker PIE support with copy reloc. This feature gets enabled with binutils 2.27 upgrade, but breaks unittests in chromium os: - https://bugs.chromium.org/p/chromium/issues/detail?id=738188 This is because of the upstream gcc bug for which the patches were not backported to 4.9.x branches: - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248 BUG: None TEST: Chromium OS unittests pass again. Change-Id: I9827cbe56378727f979991993d06de0b4c6b5478 --- gcc-4.9/gcc/configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcc-4.9/gcc/configure b/gcc-4.9/gcc/configure index 436278b81..a16ecab61 100755 --- a/gcc-4.9/gcc/configure +++ b/gcc-4.9/gcc/configure @@ -27052,7 +27052,8 @@ EOF esac fi fi - +# Disable gcc linker PIE support with copy reloc +gcc_cv_ld_pie_copyreloc=no cat >>confdefs.h <<_ACEOF #define HAVE_LD_PIE_COPYRELOC `if test x"$gcc_cv_ld_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` _ACEOF -- cgit v1.2.3 From 08875d976f14a5c589c1cfcd17614adad06e43d4 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Mon, 18 Sep 2017 10:37:34 -0700 Subject: update-prebuilts: do not update mips prebuilts. The aosp-gcc builder has stopped building the toolchain for mips. Bug: None Test: None Change-Id: Ia3bf3a41b2d0e098efd6e8c526b81f6ef2b1beb0 --- update-prebuilts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update-prebuilts.py b/update-prebuilts.py index 645b1d574..1a2f405ef 100755 --- a/update-prebuilts.py +++ b/update-prebuilts.py @@ -323,7 +323,7 @@ def main(): try: hosts = ('linux', 'darwin') - arches = ('arm', 'aarch64', 'x86_64', 'mips64') + arches = ('arm', 'aarch64', 'x86_64') for host in hosts: for arch in arches: update_gcc(host, arch, args.build, args.use_current_branch, -- cgit v1.2.3 From dca601e5d2b032ac5cca1df90ac56077ccf5d665 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Mon, 18 Sep 2017 10:45:53 -0700 Subject: update-prebuilts: use fetch_artifact for downloading prebuilts. The old method of constructing a URL and downloading using sso_client has stopped working since the URLs have changed. Using fetch_artifact makes this step more robust against future changes in URL schemes. Bug: 37683243 Test: './update-prebuilts.py 4342532' works. Change-Id: I14053709bb9839990e8cf59418010862daf09236 --- update-prebuilts.py | 52 ++++++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/update-prebuilts.py b/update-prebuilts.py index 1a2f405ef..660dee55c 100755 --- a/update-prebuilts.py +++ b/update-prebuilts.py @@ -62,30 +62,18 @@ class ArgParser(argparse.ArgumentParser): help='Override the git commit message.') -def host_to_build_host(host): - """Gets the build host name for an NDK host tag. +def build_target(host, arch): + """Gets the toolchain build target name for the specified host and arch. - The Windows builds are done from Linux. - """ - return { - 'darwin': 'mac', - 'linux': 'linux', - 'windows': 'linux', - }[host] - - -def build_name(host, arch): - """Gets the release build name for an NDK host tag. + The builds targets are named by combining the host and arch values. - The builds are named by a short identifier like "linux" or "win64". + >>> build_target('darwin', 'arm') + 'arm_mac' - >>> build_name('darwin', 'arm') - 'arm' + >>> build_target('darwin', 'aarch64') + 'arm64_mac' - >>> build_name('darwin', 'aarch64') - 'arm64' - - >>> build_name('linux', 'x86') + >>> build_target('linux', 'x86') 'linux_x86' """ build_arch = arch @@ -93,7 +81,7 @@ def build_name(host, arch): build_arch = 'arm64' if host == 'darwin': - return build_arch + return build_arch + '_mac' return host + '_' + build_arch @@ -134,22 +122,14 @@ def download_build(host, arch, build_number, download_dir, dryrun, cachedir): '{}'.format(pkg_name, cachedir)) return cached_pkg - url_base = 'https://android-build-uber.corp.google.com' - path = 'builds/{branch}-{build_host}-{build_name}/{build_num}'.format( - branch=BRANCH, - build_host=host_to_build_host(host), - build_name=build_name(host, arch), - build_num=build_number) - - url = '{}/{}/{}'.format(url_base, path, pkg_name) - TIMEOUT = '60' # In seconds. out_file_path = os.path.join(download_dir, pkg_name) - with open(out_file_path, 'w') as out_file: - print('Downloading {} to {}'.format(url, out_file_path)) - invoke_cmd(dryrun, - ['sso_client', '--location', - '--request_timeout', TIMEOUT, url], - outfile=out_file) + print('Downloading {} to {}'.format(pkg_name, out_file_path)) + invoke_cmd(dryrun, + ['/google/data/ro/projects/android/fetch_artifact', + '--branch={}'.format(BRANCH), + '--bid={}'.format(build_number), + '--target={}'.format(build_target(host, arch)), + pkg_name, out_file_path]) return out_file_path -- cgit v1.2.3 From deec799746e92ab0487eca489499ade08a2610bf Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Mon, 8 Jan 2018 10:25:12 -0800 Subject: [GCC] Commit retpoline patch code, for fixing security issues. This applies the Intel GCC code patches, to allow compiling with appropriate flags for mitigating the indirect branch variant of the speculative execution security flaw. Bug: None Test: This is already in place in ChromeOS and has been tested on the ChromeOS kernels. Change-Id: Ideffb433b697f1fe7e4ca2c1eaa968160abfcc8b --- gcc-4.9/gcc/config/i386/i386-opts.h | 14 + gcc-4.9/gcc/config/i386/i386-protos.h | 12 +- gcc-4.9/gcc/config/i386/i386.c | 872 +++++++++++++-------- gcc-4.9/gcc/config/i386/i386.h | 71 +- gcc-4.9/gcc/config/i386/i386.md | 34 +- gcc-4.9/gcc/config/i386/i386.opt | 52 +- gcc-4.9/gcc/params.def | 9 - .../testsuite/gcc.target/i386/indirect-thunk-1.c | 19 + .../testsuite/gcc.target/i386/indirect-thunk-2.c | 19 + .../testsuite/gcc.target/i386/indirect-thunk-3.c | 20 + .../testsuite/gcc.target/i386/indirect-thunk-4.c | 20 + .../testsuite/gcc.target/i386/indirect-thunk-7.c | 42 + .../gcc.target/i386/indirect-thunk-attr-1.c | 22 + .../gcc.target/i386/indirect-thunk-attr-2.c | 20 + .../gcc.target/i386/indirect-thunk-attr-3.c | 21 + .../gcc.target/i386/indirect-thunk-attr-4.c | 20 + .../gcc.target/i386/indirect-thunk-attr-5.c | 22 + .../gcc.target/i386/indirect-thunk-attr-6.c | 21 + .../gcc.target/i386/indirect-thunk-attr-7.c | 43 + .../gcc.target/i386/indirect-thunk-attr-8.c | 40 + .../gcc.target/i386/indirect-thunk-extern-1.c | 19 + .../gcc.target/i386/indirect-thunk-extern-2.c | 19 + .../gcc.target/i386/indirect-thunk-extern-3.c | 20 + .../gcc.target/i386/indirect-thunk-extern-4.c | 20 + .../gcc.target/i386/indirect-thunk-extern-7.c | 42 + .../gcc.target/i386/indirect-thunk-inline-1.c | 18 + .../gcc.target/i386/indirect-thunk-inline-2.c | 18 + .../gcc.target/i386/indirect-thunk-inline-3.c | 19 + .../gcc.target/i386/indirect-thunk-inline-4.c | 19 + .../gcc.target/i386/indirect-thunk-inline-7.c | 41 + .../gcc.target/i386/indirect-thunk-loop-1.c | 19 + .../gcc.target/i386/indirect-thunk-loop-2.c | 19 + .../gcc.target/i386/indirect-thunk-loop-3.c | 19 + .../gcc.target/i386/indirect-thunk-loop-4.c | 19 + .../gcc.target/i386/indirect-thunk-loop-5.c | 19 + .../testsuite/gcc.target/i386/patch-functions-1.c | 23 - .../testsuite/gcc.target/i386/patch-functions-2.c | 21 - .../testsuite/gcc.target/i386/patch-functions-3.c | 21 - .../testsuite/gcc.target/i386/patch-functions-4.c | 22 - .../testsuite/gcc.target/i386/patch-functions-5.c | 22 - .../testsuite/gcc.target/i386/patch-functions-6.c | 15 - .../testsuite/gcc.target/i386/patch-functions-7.c | 15 - .../testsuite/gcc.target/i386/patch-functions-8.c | 29 - .../i386/patch-functions-force-no-patching.c | 27 - .../i386/patch-functions-force-patching.c | 20 - .../gcc.target/i386/patch-functions-sibling-call.c | 26 - .../gcc/testsuite/gcc.target/i386/ret-thunk-1.c | 12 + .../gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 22 + .../gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 22 + .../gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 21 + .../gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 21 + .../gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 21 + .../gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 21 + .../gcc/testsuite/gcc.target/i386/ret-thunk-16.c | 18 + .../gcc/testsuite/gcc.target/i386/ret-thunk-2.c | 12 + .../gcc/testsuite/gcc.target/i386/ret-thunk-3.c | 12 + .../gcc/testsuite/gcc.target/i386/ret-thunk-4.c | 12 + .../gcc/testsuite/gcc.target/i386/ret-thunk-5.c | 14 + .../gcc/testsuite/gcc.target/i386/ret-thunk-6.c | 13 + .../gcc/testsuite/gcc.target/i386/ret-thunk-7.c | 13 + .../gcc/testsuite/gcc.target/i386/ret-thunk-8.c | 14 + .../gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 23 + 62 files changed, 1613 insertions(+), 622 deletions(-) create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-1.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-2.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-3.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-4.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-5.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-6.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-7.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-8.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-no-patching.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-patching.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-sibling-call.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c diff --git a/gcc-4.9/gcc/config/i386/i386-opts.h b/gcc-4.9/gcc/config/i386/i386-opts.h index 47a34dbf7..e98cd8c1e 100644 --- a/gcc-4.9/gcc/config/i386/i386-opts.h +++ b/gcc-4.9/gcc/config/i386/i386-opts.h @@ -93,4 +93,18 @@ enum stack_protector_guard { SSP_GLOBAL /* global canary */ }; +enum indirect_branch { + indirect_branch_unset = 0, + indirect_branch_keep, + indirect_branch_thunk, + indirect_branch_thunk_inline, + indirect_branch_thunk_extern +}; + +enum indirect_branch_loop { + indirect_branch_loop_lfence, + indirect_branch_loop_pause, + indirect_branch_loop_nop +}; + #endif diff --git a/gcc-4.9/gcc/config/i386/i386-protos.h b/gcc-4.9/gcc/config/i386/i386-protos.h index fc0eb53f8..e2c462a71 100644 --- a/gcc-4.9/gcc/config/i386/i386-protos.h +++ b/gcc-4.9/gcc/config/i386/i386-protos.h @@ -28,16 +28,6 @@ extern bool ix86_target_stack_probe (void); extern bool ix86_can_use_return_insn_p (void); extern void ix86_setup_frame_addresses (void); -/* Section names for function patch prologue and epilogue section. See - ix86_output_function_nops_prologue_epilogue() in i386.c for details. */ -#define FUNCTION_PATCH_PROLOGUE_SECTION "_function_patch_prologue" -#define FUNCTION_PATCH_EPILOGUE_SECTION "_function_patch_epilogue" - -extern bool ix86_output_function_nops_prologue_epilogue (FILE *, - const char *, - const char *, - int); - extern HOST_WIDE_INT ix86_initial_elimination_offset (int, int); extern void ix86_expand_prologue (void); extern void ix86_maybe_emit_epilogue_vzeroupper (void); @@ -322,6 +312,8 @@ extern enum attr_cpu ix86_schedule; #endif extern const char * ix86_output_call_insn (rtx insn, rtx call_op); +extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p); +extern const char * ix86_output_function_return (bool long_p); extern bool adjacent_mem_locations (rtx mem1, rtx mem2); #ifdef RTX_CODE diff --git a/gcc-4.9/gcc/config/i386/i386.c b/gcc-4.9/gcc/config/i386/i386.c index 614b8db81..ccd2f150b 100644 --- a/gcc-4.9/gcc/config/i386/i386.c +++ b/gcc-4.9/gcc/config/i386/i386.c @@ -2267,53 +2267,6 @@ struct GTY(()) stack_local_entry { struct stack_local_entry *next; }; -/* Structure describing stack frame layout. - Stack grows downward: - - [arguments] - <- ARG_POINTER - saved pc - - saved static chain if ix86_static_chain_on_stack - - saved frame pointer if frame_pointer_needed - <- HARD_FRAME_POINTER - [saved regs] - <- regs_save_offset - [padding0] - - [saved SSE regs] - <- sse_regs_save_offset - [padding1] | - | <- FRAME_POINTER - [va_arg registers] | - | - [frame] | - | - [padding2] | = to_allocate - <- STACK_POINTER - */ -struct ix86_frame -{ - int nsseregs; - int nregs; - int va_arg_size; - int red_zone_size; - int outgoing_arguments_size; - - /* The offsets relative to ARG_POINTER. */ - HOST_WIDE_INT frame_pointer_offset; - HOST_WIDE_INT hard_frame_pointer_offset; - HOST_WIDE_INT stack_pointer_offset; - HOST_WIDE_INT hfp_save_offset; - HOST_WIDE_INT reg_save_offset; - HOST_WIDE_INT sse_reg_save_offset; - - /* When save_regs_using_mov is set, emit prologue using - move instead of push instructions. */ - bool save_regs_using_mov; -}; - /* Which cpu are we scheduling for. */ enum attr_cpu ix86_schedule; @@ -2403,7 +2356,7 @@ static unsigned int ix86_function_arg_boundary (enum machine_mode, const_tree); static rtx ix86_static_chain (const_tree, bool); static int ix86_function_regparm (const_tree, const_tree); -static void ix86_compute_frame_layout (struct ix86_frame *); +static void ix86_compute_frame_layout (void); static bool ix86_expand_vector_init_one_nonzero (bool, enum machine_mode, rtx, rtx, int); static void ix86_add_new_builtins (HOST_WIDE_INT); @@ -2558,12 +2511,19 @@ make_pass_insert_vzeroupper (gcc::context *ctxt) return new pass_insert_vzeroupper (ctxt); } -/* Return true if a red-zone is in use. */ +/* Return true if a red-zone is in use. We can't use red-zone when + there are local indirect jumps, like "indirect_jump" or "tablejump", + which jumps to another place in the function, since "call" in the + indirect thunk pushes the return address onto stack, destroying + red-zone. */ static inline bool ix86_using_red_zone (void) { - return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI; + return (TARGET_RED_ZONE + && !TARGET_64BIT_MS_ABI + && (!cfun->machine->has_local_indirect_jump + || cfun->machine->indirect_branch_type == indirect_branch_keep)); } /* Return a string that documents the current -m options. The caller is @@ -4963,6 +4923,65 @@ ix86_reset_previous_fndecl (void) ix86_previous_fndecl = NULL_TREE; } +/* Set the indirect_branch_type field from the function FNDECL. */ + +static void +ix86_set_indirect_branch_type (tree fndecl) +{ + if (cfun->machine == NULL) + return; + + 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 = ix86_indirect_branch; + } + + if (cfun->machine->function_return_type == indirect_branch_unset) + { + tree attr = lookup_attribute ("function_return", + 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->function_return_type = indirect_branch_keep; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0) + cfun->machine->function_return_type = indirect_branch_thunk; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0) + cfun->machine->function_return_type = indirect_branch_thunk_inline; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0) + cfun->machine->function_return_type = indirect_branch_thunk_extern; + else + gcc_unreachable (); + } + else + cfun->machine->function_return_type = ix86_function_return; + } +} + /* Establish appropriate back-end context for processing the function FNDECL. The argument might be NULL to indicate processing at top level, outside of any function scope. */ @@ -4982,6 +5001,8 @@ ix86_set_current_function (tree fndecl) ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl) : NULL_TREE); + ix86_set_indirect_branch_type (fndecl); + ix86_previous_fndecl = fndecl; if (old_tree == new_tree) ; @@ -9074,7 +9095,6 @@ symbolic_reference_mentioned_p (rtx op) bool ix86_can_use_return_insn_p (void) { - struct ix86_frame frame; if (! reload_completed || frame_pointer_needed) return 0; @@ -9084,7 +9104,8 @@ ix86_can_use_return_insn_p (void) if (crtl->args.pops_args && crtl->args.size >= 32768) return 0; - ix86_compute_frame_layout (&frame); + ix86_compute_frame_layout (); + struct ix86_frame &frame = cfun->machine->frame; return (frame.stack_pointer_offset == UNITS_PER_WORD && (frame.nregs + frame.nsseregs) == 0); } @@ -9147,6 +9168,217 @@ ix86_setup_frame_addresses (void) # endif #endif +static int indirectlabelno; +static bool indirect_thunk_needed = false; + +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, bool ret_p) +{ + if (regno >= 0 && ret_p) + gcc_unreachable (); + + if (USE_HIDDEN_LINKONCE) + { + if (regno >= 0) + { + const char *reg_prefix; + if (!REX_INT_REGNO_P (regno)) + reg_prefix = TARGET_64BIT ? "r" : "e"; + else + reg_prefix = ""; + sprintf (name, "__x86.indirect_thunk.%s%s", + reg_prefix, reg_names[regno]); + } + else + { + const char *ret = ret_p ? "return" : "indirect"; + sprintf (name, "__x86.%s_thunk", ret); + } + } + else + { + if (regno >= 0) + ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno); + else + { + if (ret_p) + ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0); + else + ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0); + } + } +} + +static void +output_indirect_thunk (int regno) +{ + char indirectlabel1[32]; + char indirectlabel2[32]; + + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL, + indirectlabelno++); + + /* Call */ + fputs ("\tcall\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel2); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); + + switch (ix86_indirect_branch_loop) + { + case indirect_branch_loop_lfence: + /* lfence. */ + fprintf (asm_out_file, "\tlfence\n"); + break; + case indirect_branch_loop_pause: + /* pause. */ + fprintf (asm_out_file, "\tpause\n"); + break; + case indirect_branch_loop_nop: + /* nop. */ + fprintf (asm_out_file, "\tnop\n"); + break; + default: + gcc_unreachable (); + } + + /* Jump. */ + fputs ("\tjmp\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel1); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); + + if (regno >= 0) + { + /* MOV. */ + rtx xops[2]; + xops[0] = gen_rtx_MEM (word_mode, stack_pointer_rtx); + xops[1] = gen_rtx_REG (word_mode, regno); + output_asm_insn ("mov\t{%1, %0|%0, %1}", xops); + } + else + { + /* LEA. */ + rtx xops[2]; + xops[0] = stack_pointer_rtx; + xops[1] = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD); + output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops); + } + + fputs ("\tret\n", asm_out_file); +} + +static void +output_indirect_thunk_function (int regno) +{ + char name[32]; + tree decl; + + /* Create __x86.indirect_thunk. */ + indirect_thunk_name (name, regno, false); + 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; + +#if TARGET_MACHO + if (TARGET_MACHO) + { + switch_to_section (darwin_sections[text_coal_section]); + fputs ("\t.weak_definition\t", asm_out_file); + assemble_name (asm_out_file, name); + fputs ("\n\t.private_extern\t", asm_out_file); + assemble_name (asm_out_file, name); + putc ('\n', asm_out_file); + ASM_OUTPUT_LABEL (asm_out_file, name); + DECL_WEAK (decl) = 1; + } + else +#endif + if (USE_HIDDEN_LINKONCE) + { + DECL_COMDAT_GROUP (decl) = 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); + } + else + { + switch_to_section (text_section); + ASM_OUTPUT_LABEL (asm_out_file, name); + } + + if (regno < 0) + { + /* Create alias for __x86.return_thunk. */ + char alias[32]; + + indirect_thunk_name (alias, regno, true); + ASM_OUTPUT_DEF (asm_out_file, alias, name); +#if TARGET_MACHO + if (TARGET_MACHO) + { + fputs ("\t.weak_definition\t", asm_out_file); + assemble_name (asm_out_file, alias); + fputs ("\n\t.private_extern\t", asm_out_file); + assemble_name (asm_out_file, alias); + putc ('\n', asm_out_file); + } +#else + if (USE_HIDDEN_LINKONCE) + { + fputs ("\t.globl\t", asm_out_file); + assemble_name (asm_out_file, alias); + putc ('\n', asm_out_file); + fputs ("\t.hidden\t", asm_out_file); + assemble_name (asm_out_file, alias); + putc ('\n', asm_out_file); + } +#endif + } + + 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 (regno); + + final_end_function (); + init_insn_lengths (); + free_after_compilation (cfun); + set_cfun (NULL); + current_function_decl = NULL; +} + static int pic_labels_used; /* Fills in the label name that should be used for a pc thunk for @@ -9173,11 +9405,24 @@ ix86_code_end (void) rtx xops[2]; int regno; + if (indirect_thunk_needed) + output_indirect_thunk_function (-1); + + for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++) + { + int i = regno - FIRST_REX_INT_REG + SP_REG + 1; + if ((indirect_thunks_used & (1 << i))) + output_indirect_thunk_function (regno); + } + for (regno = AX_REG; regno <= SP_REG; regno++) { char name[32]; tree decl; + if ((indirect_thunks_used & (1 << regno))) + output_indirect_thunk_function (regno); + if (!(pic_labels_used & (1 << regno))) continue; @@ -9479,8 +9724,8 @@ ix86_can_eliminate (const int from, const int to) HOST_WIDE_INT ix86_initial_elimination_offset (int from, int to) { - struct ix86_frame frame; - ix86_compute_frame_layout (&frame); + ix86_compute_frame_layout (); + struct ix86_frame &frame = cfun->machine->frame; if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) return frame.hard_frame_pointer_offset; @@ -9519,8 +9764,9 @@ ix86_builtin_setjmp_frame_value (void) /* Fill structure ix86_frame about frame of currently computed function. */ static void -ix86_compute_frame_layout (struct ix86_frame *frame) +ix86_compute_frame_layout (void) { + struct ix86_frame *frame = &cfun->machine->frame; unsigned HOST_WIDE_INT stack_alignment_needed; HOST_WIDE_INT offset; unsigned HOST_WIDE_INT preferred_alignment; @@ -10736,7 +10982,6 @@ ix86_expand_prologue (void) struct machine_function *m = cfun->machine; rtx insn, t; bool pic_reg_used; - struct ix86_frame frame; HOST_WIDE_INT allocate; bool int_registers_saved; bool sse_registers_saved; @@ -10758,7 +11003,8 @@ ix86_expand_prologue (void) m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET; m->fs.sp_valid = true; - ix86_compute_frame_layout (&frame); + ix86_compute_frame_layout (); + struct ix86_frame &frame = m->frame; if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl)) { @@ -11298,10 +11544,10 @@ static rtx ix86_set_fp_insn () { rtx r, seq; - struct ix86_frame frame; HOST_WIDE_INT offset; - ix86_compute_frame_layout (&frame); + ix86_compute_frame_layout (); + struct ix86_frame &frame = cfun->machine->frame; gcc_assert (frame_pointer_partially_needed); offset = frame.stack_pointer_offset - frame.hard_frame_pointer_offset; @@ -11491,12 +11737,12 @@ ix86_expand_epilogue (int style) { struct machine_function *m = cfun->machine; struct machine_frame_state frame_state_save = m->fs; - struct ix86_frame frame; bool restore_regs_via_mov; bool using_drap; ix86_finalize_stack_realign_flags (); - ix86_compute_frame_layout (&frame); + ix86_compute_frame_layout (); + struct ix86_frame &frame = m->frame; m->fs.sp_valid = (!frame_pointer_needed || (crtl->sp_is_unchanging @@ -11835,11 +12081,6 @@ ix86_expand_epilogue (int style) m->fs = frame_state_save; } - -/* True if the current function should be patched with nops at prologue and - returns. */ -static bool patch_current_function_p = false; - static inline bool has_attribute (const char* attribute_name) { @@ -11847,234 +12088,6 @@ has_attribute (const char* attribute_name) DECL_ATTRIBUTES (current_function_decl)) != NULL; } -/* Return true if we patch the current function. By default a function - is patched if it has loops or if the number of insns is greater than - patch_functions_min_instructions (number of insns roughly translates - to number of instructions). */ - -static bool -check_should_patch_current_function (void) -{ - int num_insns = 0; - rtx insn; - const char *func_name = NULL; - struct loops *loops; - int num_loops = 0; - int min_functions_instructions; - - /* If a function has an attribute forcing patching on or off, do as it - indicates. */ - if (has_attribute ("always_patch_for_instrumentation")) - return true; - else if (has_attribute ("never_patch_for_instrumentation")) - return false; - - /* Patch the function if it has at least a loop. */ - if (!patch_functions_ignore_loops) - { - if (DECL_STRUCT_FUNCTION (current_function_decl)->cfg) - { - loops = flow_loops_find (NULL); - num_loops = loops->larray->length(); - /* FIXME - Deallocating the loop causes a seg-fault. */ -#if 0 - flow_loops_free (loops); -#endif - /* We are not concerned with the function body as a loop. */ - if (num_loops > 1) - return true; - } - } - - /* Else, check if function has more than patch_functions_min_instrctions. */ - - /* Borrowed this code from rest_of_handle_final() in final.c. */ - func_name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - if (!patch_functions_dont_always_patch_main && - func_name && - strcmp("main", func_name) == 0) - return true; - - min_functions_instructions = - PARAM_VALUE (PARAM_FUNCTION_PATCH_MIN_INSTRUCTIONS); - if (min_functions_instructions > 0) - { - /* Calculate the number of instructions in this function and only emit - function patch for instrumentation if it is greater than - patch_functions_min_instructions. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (NONDEBUG_INSN_P (insn)) - ++num_insns; - } - if (num_insns < min_functions_instructions) - return false; - } - - return true; -} - -/* Emit the 11-byte patch space for the function prologue for functions that - qualify. */ - -static void -ix86_output_function_prologue (FILE *file, - HOST_WIDE_INT size ATTRIBUTE_UNUSED) -{ - /* Only for 64-bit target. */ - if (TARGET_64BIT && patch_functions_for_instrumentation) - { - patch_current_function_p = check_should_patch_current_function(); - /* Emit the instruction 'jmp 09' followed by 9 bytes to make it 11-bytes - of nop. */ - ix86_output_function_nops_prologue_epilogue ( - file, - FUNCTION_PATCH_PROLOGUE_SECTION, - ASM_BYTE"0xeb,0x09", - 9); - } -} - -/* Emit the nop bytes at function prologue or return (including tail call - jumps). The number of nop bytes generated is at least 8. - Also emits a section named SECTION_NAME, which is a backpointer section - holding the addresses of the nop bytes in the text section. - SECTION_NAME is either '_function_patch_prologue' or - '_function_patch_epilogue'. The backpointer section can be used to navigate - through all the function entry and exit points which are patched with nops. - PRE_INSTRUCTIONS are the instructions, if any, at the start of the nop byte - sequence. NUM_REMAINING_NOPS are the number of nop bytes to fill, - excluding the number of bytes in PRE_INSTRUCTIONS. - Returns true if the function was patched, false otherwise. */ - -bool -ix86_output_function_nops_prologue_epilogue (FILE *file, - const char *section_name, - const char *pre_instructions, - int num_remaining_nops) -{ - static int labelno = 0; - char label[32], section_label[32]; - section *section = NULL; - int num_actual_nops = num_remaining_nops - sizeof(void *); - unsigned int section_flags = SECTION_RELRO; - char *section_name_comdat = NULL; - const char *decl_section_name = NULL; - const char *func_name = NULL; - char *section_name_function_sections = NULL; - size_t len; - - gcc_assert (num_remaining_nops >= 0); - - if (!patch_current_function_p) - return false; - - ASM_GENERATE_INTERNAL_LABEL (label, "LFPEL", labelno); - ASM_GENERATE_INTERNAL_LABEL (section_label, "LFPESL", labelno++); - - /* Align the start of nops to 2-byte boundary so that the 2-byte jump - instruction can be patched atomically at run time. */ - ASM_OUTPUT_ALIGN (file, 1); - - /* Emit nop bytes. They look like the following: - $LFPEL0: - - 0x90 (repeated num_actual_nops times) - .quad $LFPESL0 - . - followed by section 'section_name' which contains the address - of instruction at 'label'. - */ - ASM_OUTPUT_INTERNAL_LABEL (file, label); - if (pre_instructions) - fprintf (file, "%s\n", pre_instructions); - - while (num_actual_nops-- > 0) - asm_fprintf (file, ASM_BYTE"0x90\n"); - - fprintf (file, ASM_QUAD); - /* Output "section_label - ." for the relative address of the entry in - the section 'section_name'. */ - assemble_name_raw (file, section_label); - fprintf (file, " - ."); - fprintf (file, "\n"); - - /* Emit the backpointer section. For functions belonging to comdat group, - we emit a different section named '.foo' where 'foo' is - the name of the comdat section. This section is later renamed to - '' by ix86_elf_asm_named_section(). - We emit a unique section name for the back pointer section for comdat - functions because otherwise the 'get_section' call may return an existing - non-comdat section with the same name, leading to references from - non-comdat section to comdat functions. - */ - if (current_function_decl != NULL_TREE && - DECL_ONE_ONLY (current_function_decl) && - HAVE_COMDAT_GROUP) - { - decl_section_name = - TREE_STRING_POINTER (DECL_SECTION_NAME (current_function_decl)); - len = strlen (decl_section_name) + strlen (section_name) + 2; - section_name_comdat = (char *) alloca (len); - sprintf (section_name_comdat, "%s.%s", section_name, decl_section_name); - section_name = section_name_comdat; - section_flags |= SECTION_LINKONCE; - } - else if (flag_function_sections) - { - func_name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - if (func_name) - { - len = strlen (func_name) + strlen (section_name) + 2; - section_name_function_sections = (char *) alloca (len); - sprintf (section_name_function_sections, "%s.%s", section_name, - func_name); - section_name = section_name_function_sections; - } - } - section = get_section (section_name, section_flags, current_function_decl); - switch_to_section (section); - /* Align the section to 8-byte boundary. */ - ASM_OUTPUT_ALIGN (file, 3); - - /* Emit address of the start of nop bytes in the section: - $LFPESP0: - .quad $LFPEL0 - */ - ASM_OUTPUT_INTERNAL_LABEL (file, section_label); - fprintf(file, ASM_QUAD); - assemble_name_raw (file, label); - fprintf (file, "\n"); - - /* Switching back to text section. */ - switch_to_section (current_function_section ()); - return true; -} - -/* Strips the characters after '_function_patch_prologue' or - '_function_patch_epilogue' and emits the section. */ - -static void -ix86_elf_asm_named_section (const char *name, unsigned int flags, - tree decl) -{ - const char *section_name = name; - if (!flag_function_sections && HAVE_COMDAT_GROUP && flags & SECTION_LINKONCE) - { - const int prologue_section_name_length = - sizeof(FUNCTION_PATCH_PROLOGUE_SECTION) - 1; - const int epilogue_section_name_length = - sizeof(FUNCTION_PATCH_EPILOGUE_SECTION) - 1; - - if (strncmp (name, FUNCTION_PATCH_PROLOGUE_SECTION, - prologue_section_name_length) == 0) - section_name = FUNCTION_PATCH_PROLOGUE_SECTION; - else if (strncmp (name, FUNCTION_PATCH_EPILOGUE_SECTION, - epilogue_section_name_length) == 0) - section_name = FUNCTION_PATCH_EPILOGUE_SECTION; - } - default_elf_asm_named_section (section_name, flags, decl); -} - /* Reset from the function's potential modifications. */ static void @@ -12196,7 +12209,6 @@ static GTY(()) rtx split_stack_fn_large; void ix86_expand_split_stack_prologue (void) { - struct ix86_frame frame; HOST_WIDE_INT allocate; unsigned HOST_WIDE_INT args_size; rtx label, limit, current, jump_insn, allocate_rtx, call_insn, call_fusage; @@ -12207,7 +12219,8 @@ ix86_expand_split_stack_prologue (void) gcc_assert (flag_split_stack && reload_completed); ix86_finalize_stack_realign_flags (); - ix86_compute_frame_layout (&frame); + ix86_compute_frame_layout (); + struct ix86_frame &frame = cfun->machine->frame; allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET; /* This is the label we will branch to if we have enough stack @@ -14918,6 +14931,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, bool reverse, If CODE is 'h', pretend the reg is the 'high' byte register. If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. If CODE is 'd', duplicate the operand for AVX instruction. + If CODE is 'V', print naked register name without %. */ void @@ -14927,7 +14941,7 @@ print_reg (rtx x, int code, FILE *file) unsigned int regno; bool duplicated = code == 'd' && TARGET_AVX; - if (ASSEMBLER_DIALECT == ASM_ATT) + if (ASSEMBLER_DIALECT == ASM_ATT && code != 'V') putc ('%', file); if (x == pc_rtx) @@ -15128,6 +15142,7 @@ get_some_local_dynamic_name (void) & -- print some in-use local-dynamic symbol name. H -- print a memory address offset by 8; used for sse high-parts Y -- print condition for XOP pcom* instruction. + V -- print naked register name without %. + -- print a branch hint as 'cs' or 'ds' prefix ; -- print a semicolon (after prefixes due to bug in older gas). ~ -- print "i" if TARGET_AVX2, "f" otherwise. @@ -15353,6 +15368,7 @@ ix86_print_operand (FILE *file, rtx x, int code) case 'X': case 'P': case 'p': + case 'V': break; case 's': @@ -25288,6 +25304,145 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, return call; } +static void +ix86_output_indirect_branch (rtx call_op, const char *xasm, + bool sibcall_p) +{ + char thunk_name_buf[32]; + char *thunk_name; + char push_buf[64]; + int regno; + + if (REG_P (call_op)) + regno = REGNO (call_op); + else + regno = -1; + + if (cfun->machine->indirect_branch_type + != indirect_branch_thunk_inline) + { + if (cfun->machine->indirect_branch_type == indirect_branch_thunk) + { + if (regno >= 0) + { + int i = regno; + if (i >= FIRST_REX_INT_REG) + i -= (FIRST_REX_INT_REG - SP_REG - 1); + indirect_thunks_used |= 1 << i; + } + else + indirect_thunk_needed = true; + } + indirect_thunk_name (thunk_name_buf, regno, false); + thunk_name = thunk_name_buf; + } + else + thunk_name = NULL; + + snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s", + TARGET_64BIT ? 'q' : 'l', xasm); + + if (sibcall_p) + { + if (regno < 0) + output_asm_insn (push_buf, &call_op); + if (thunk_name != NULL) + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); + else + output_indirect_thunk (regno); + } + else + { + if (regno >= 0 && thunk_name != NULL) + { + fprintf (asm_out_file, "\tcall\t%s\n", thunk_name); + return; + } + + char indirectlabel1[32]; + char indirectlabel2[32]; + + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, + INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, + INDIRECT_LABEL, + indirectlabelno++); + + /* Jump. */ + fputs ("\tjmp\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel2); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); + + if (MEM_P (call_op)) + { + struct ix86_address parts; + rtx addr = XEXP (call_op, 0); + if (ix86_decompose_address (addr, &parts) + && parts.base == stack_pointer_rtx) + { + /* Since call will adjust stack by -UNITS_PER_WORD, + we must convert "disp(stack, index, scale)" to + "disp+UNITS_PER_WORD(stack, index, scale)". */ + if (parts.index) + { + addr = gen_rtx_MULT (Pmode, parts.index, + GEN_INT (parts.scale)); + addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, + addr); + } + else + addr = stack_pointer_rtx; + + rtx disp; + if (parts.disp != NULL_RTX) + disp = plus_constant (Pmode, parts.disp, + UNITS_PER_WORD); + else + disp = GEN_INT (UNITS_PER_WORD); + + addr = gen_rtx_PLUS (Pmode, addr, disp); + call_op = gen_rtx_MEM (GET_MODE (call_op), addr); + } + } + + if (regno < 0) + output_asm_insn (push_buf, &call_op); + + if (thunk_name != NULL) + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); + else + output_indirect_thunk (regno); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); + + /* Call. */ + fputs ("\tcall\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel1); + fputc ('\n', asm_out_file); + } +} + +const char * +ix86_output_indirect_jmp (rtx call_op, bool ret_p) +{ + if (cfun->machine->indirect_branch_type != indirect_branch_keep) + { + /* We can't have red-zone if this isn't a function return since + "call" in the indirect thunk pushes the return address onto + stack, destroying red-zone. */ + if (!ret_p && ix86_red_zone_size != 0) + gcc_unreachable (); + + ix86_output_indirect_branch (call_op, "%0", true); + return ""; + } + else + return "jmp\t%A0"; +} + /* Return true if the function being called was marked with attribute "noplt" or using -fno-plt and we are compiling for non-PIC and x86_64. We need to handle the non-PIC case in the backend because there is no easy interface @@ -25313,12 +25468,43 @@ ix86_nopic_noplt_attribute_p (rtx call_op) return false; } +const char * +ix86_output_function_return (bool long_p) +{ + if (cfun->machine->function_return_type != indirect_branch_keep) + { + char thunk_name[32]; + + if (cfun->machine->function_return_type + != indirect_branch_thunk_inline) + { + bool need_thunk = (cfun->machine->function_return_type + == indirect_branch_thunk); + indirect_thunk_name (thunk_name, -1, true); + indirect_thunk_needed |= need_thunk; + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); + } + else + output_indirect_thunk (-1); + + return ""; + } + + if (!long_p) + return "ret"; + + return "rep%; ret"; +} + /* Output the assembly for a call instruction. */ const char * ix86_output_call_insn (rtx insn, rtx call_op) { bool direct_p = constant_call_address_operand (call_op, VOIDmode); + bool output_indirect_p + = (!TARGET_SEH + && cfun->machine->indirect_branch_type != indirect_branch_keep); bool seh_nop_p = false; const char *xasm; @@ -25333,18 +25519,17 @@ ix86_output_call_insn (rtx insn, rtx call_op) else if (TARGET_SEH) xasm = "rex.W jmp %A0"; else - xasm = "jmp\t%A0"; - - /* Just before the sibling call, add 11-bytes of nops to patch function - exit: 2 bytes for 'jmp 09' and remaining 9 bytes. */ - if (TARGET_64BIT && patch_functions_for_instrumentation) - ix86_output_function_nops_prologue_epilogue ( - asm_out_file, - FUNCTION_PATCH_EPILOGUE_SECTION, - ASM_BYTE"0xeb, 0x09", - 9); - - output_asm_insn (xasm, &call_op); + { + if (output_indirect_p) + xasm = "%0"; + else + xasm = "jmp\t%A0"; + } + + if (output_indirect_p && !direct_p) + ix86_output_indirect_branch (call_op, xasm, true); + else + output_asm_insn (xasm, &call_op); return ""; } @@ -25383,9 +25568,17 @@ ix86_output_call_insn (rtx insn, rtx call_op) else if (direct_p) xasm = "call\t%P0"; else - xasm = "call\t%A0"; + { + if (output_indirect_p) + xasm = "%0"; + else + xasm = "call\t%A0"; + } - output_asm_insn (xasm, &call_op); + if (output_indirect_p && !direct_p) + ix86_output_indirect_branch (call_op, xasm, false); + else + output_asm_insn (xasm, &call_op); if (seh_nop_p) return "nop"; @@ -38956,7 +39149,7 @@ ix86_handle_struct_attribute (tree *node, tree name, static tree ix86_handle_fndecl_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, + tree args, int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) != FUNCTION_DECL) @@ -38965,6 +39158,51 @@ ix86_handle_fndecl_attribute (tree *node, tree name, 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; + } + } + + if (is_attribute_p ("function_return", 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; } @@ -42660,6 +42898,10 @@ static const struct attribute_spec ix86_attribute_table[] = false }, { "callee_pop_aggregate_return", 1, 1, false, true, true, ix86_handle_callee_pop_aggregate_return, true }, + { "indirect_branch", 1, 1, true, false, false, + ix86_handle_fndecl_attribute, false }, + { "function_return", 1, 1, true, false, false, + ix86_handle_fndecl_attribute, false }, /* End element. */ { NULL, 0, 0, false, false, false, NULL, false } }; @@ -47385,15 +47627,9 @@ adjacent_mem_locations (rtx mem1, rtx mem2) #undef TARGET_BUILTIN_RECIPROCAL #define TARGET_BUILTIN_RECIPROCAL ix86_builtin_reciprocal -#undef TARGET_ASM_FUNCTION_PROLOGUE -#define TARGET_ASM_FUNCTION_PROLOGUE ix86_output_function_prologue - #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue -#undef TARGET_ASM_NAMED_SECTION -#define TARGET_ASM_NAMED_SECTION ix86_elf_asm_named_section - #undef TARGET_ENCODE_SECTION_INFO #ifndef SUBTARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO ix86_encode_section_info diff --git a/gcc-4.9/gcc/config/i386/i386.h b/gcc-4.9/gcc/config/i386/i386.h index f6b169c24..7e439a1e1 100644 --- a/gcc-4.9/gcc/config/i386/i386.h +++ b/gcc-4.9/gcc/config/i386/i386.h @@ -536,7 +536,7 @@ extern tree x86_mfence; #define TARGET_SUBTARGET64_DEFAULT 0 #define TARGET_SUBTARGET64_ISA_DEFAULT 0 -/* Replace MACH-O, ifdefs by in-line tests, where possible. +/* Replace MACH-O, ifdefs by in-line tests, where possible. (a) Macros defined in config/i386/darwin.h */ #define TARGET_MACHO 0 #define TARGET_MACHO_BRANCH_ISLANDS 0 @@ -1541,11 +1541,11 @@ enum reg_class /* If defined, the maximum amount of space required for outgoing arguments will be computed and placed into the variable `crtl->outgoing_args_size'. No space will be pushed onto the stack for each call; instead, the - function prologue should increase the stack frame size by this amount. + function prologue should increase the stack frame size by this amount. In 32bit mode enabling argument accumulation results in about 5% code size growth becuase move instructions are less compact than push. In 64bit - mode the difference is less drastic but visible. + mode the difference is less drastic but visible. FIXME: Unlike earlier implementations, the size of unwind info seems to actually grow with accumulation. Is that because accumulated args @@ -2204,7 +2204,7 @@ do { \ #define DEFAULT_LARGE_SECTION_THRESHOLD 65536 /* Which processor to tune code generation for. These must be in sync - with processor_target_table in i386.c. */ + with processor_target_table in i386.c. */ enum processor_type { @@ -2369,9 +2369,56 @@ enum avx_u128_state #define FASTCALL_PREFIX '@' +#ifndef USED_FOR_TARGET +/* Structure describing stack frame layout. + Stack grows downward: + + [arguments] + <- ARG_POINTER + saved pc + + saved static chain if ix86_static_chain_on_stack + + saved frame pointer if frame_pointer_needed + <- HARD_FRAME_POINTER + [saved regs] + <- regs_save_offset + [padding0] + + [saved SSE regs] + <- sse_regs_save_offset + [padding1] | + | <- FRAME_POINTER + [va_arg registers] | + | + [frame] | + | + [padding2] | = to_allocate + <- STACK_POINTER + */ +struct GTY(()) ix86_frame +{ + int nsseregs; + int nregs; + int va_arg_size; + int red_zone_size; + int outgoing_arguments_size; + + /* The offsets relative to ARG_POINTER. */ + HOST_WIDE_INT frame_pointer_offset; + HOST_WIDE_INT hard_frame_pointer_offset; + HOST_WIDE_INT stack_pointer_offset; + HOST_WIDE_INT hfp_save_offset; + HOST_WIDE_INT reg_save_offset; + HOST_WIDE_INT sse_reg_save_offset; + + /* When save_regs_using_mov is set, emit prologue using + move instead of push instructions. */ + bool save_regs_using_mov; +}; + /* Machine specific frame tracking during prologue/epilogue generation. */ -#ifndef USED_FOR_TARGET struct GTY(()) machine_frame_state { /* This pair tracks the currently active CFA as reg+offset. When reg @@ -2417,6 +2464,9 @@ struct GTY(()) machine_function { int varargs_fpr_size; int optimize_mode_switching[MAX_386_ENTITIES]; + /* Cached initial frame layout for the current function. */ + struct ix86_frame frame; + /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE has been computed for. */ int use_fast_prologue_epilogue_nregs; @@ -2460,6 +2510,16 @@ struct GTY(()) machine_function { /* If true, it is safe to not save/restore DRAP register. */ BOOL_BITFIELD no_drap_save_restore : 1; + /* How to generate indirec branch. */ + ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3; + + /* If true, the current function has local indirect jumps, like + "indirect_jump" or "tablejump". */ + BOOL_BITFIELD has_local_indirect_jump : 1; + + /* How to generate function return. */ + ENUM_BITFIELD(indirect_branch) function_return_type : 3; + /* During prologue/epilogue generation, the current frame state. Otherwise, the frame state at the end of the prologue. */ struct machine_frame_state fs; @@ -2484,6 +2544,7 @@ struct GTY(()) machine_function { #define ix86_current_function_calls_tls_descriptor \ (ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG)) #define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack) +#define ix86_red_zone_size (cfun->machine->frame.red_zone_size) /* Control behavior of x86_file_start. */ #define X86_FILE_START_VERSION_DIRECTIVE false diff --git a/gcc-4.9/gcc/config/i386/i386.md b/gcc-4.9/gcc/config/i386/i386.md index 2369e4b40..e32ba52a6 100644 --- a/gcc-4.9/gcc/config/i386/i386.md +++ b/gcc-4.9/gcc/config/i386/i386.md @@ -11142,12 +11142,13 @@ { if (TARGET_X32) operands[0] = convert_memory_address (word_mode, operands[0]); + cfun->machine->has_local_indirect_jump = true; }) (define_insn "*indirect_jump" [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))] "" - "jmp\t%A0" + "* return ix86_output_indirect_jmp (operands[0], false);" [(set_attr "type" "ibr") (set_attr "length_immediate" "0")]) @@ -11190,13 +11191,14 @@ if (TARGET_X32) operands[0] = convert_memory_address (word_mode, operands[0]); + cfun->machine->has_local_indirect_jump = true; }) (define_insn "*tablejump_1" [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw")) (use (label_ref (match_operand 1)))] "" - "jmp\t%A0" + "* return ix86_output_indirect_jmp (operands[0], false);" [(set_attr "type" "ibr") (set_attr "length_immediate" "0")]) @@ -11583,18 +11585,7 @@ (define_insn "simple_return_internal" [(simple_return)] "reload_completed" -{ - if (TARGET_64BIT && patch_functions_for_instrumentation) - { - /* Emit 10 nop bytes after ret. */ - if (ix86_output_function_nops_prologue_epilogue (asm_out_file, - FUNCTION_PATCH_EPILOGUE_SECTION, - "\tret", - 10)) - return ""; - } - return "ret"; -} + "* return ix86_output_function_return (false);" [(set_attr "length" "1") (set_attr "atom_unit" "jeu") (set_attr "length_immediate" "0") @@ -11607,18 +11598,7 @@ [(simple_return) (unspec [(const_int 0)] UNSPEC_REP)] "reload_completed" -{ - if (TARGET_64BIT && patch_functions_for_instrumentation) - { - /* Emit 9 nop bytes after rep;ret. */ - if (ix86_output_function_nops_prologue_epilogue (asm_out_file, - FUNCTION_PATCH_EPILOGUE_SECTION, - "\trep\;ret", - 9)) - return ""; - } - return "rep\;ret"; -} + "* return ix86_output_function_return (true);" [(set_attr "length" "2") (set_attr "atom_unit" "jeu") (set_attr "length_immediate" "0") @@ -11639,7 +11619,7 @@ [(simple_return) (use (match_operand:SI 0 "register_operand" "r"))] "reload_completed" - "jmp\t%A0" + "* return ix86_output_indirect_jmp (operands[0], true);" [(set_attr "type" "ibr") (set_attr "length_immediate" "0")]) diff --git a/gcc-4.9/gcc/config/i386/i386.opt b/gcc-4.9/gcc/config/i386/i386.opt index f64a9e1eb..3b4a86066 100644 --- a/gcc-4.9/gcc/config/i386/i386.opt +++ b/gcc-4.9/gcc/config/i386/i386.opt @@ -781,18 +781,6 @@ mrtm Target Report Mask(ISA_RTM) Var(ix86_isa_flags) Save Support RTM built-in functions and code generation -mpatch-functions-for-instrumentation -Target RejectNegative Report Var(patch_functions_for_instrumentation) Save -Patch function prologue and epilogue with custom NOPs for dynamic instrumentation. By default, functions with loops (controlled by -mpatch-functions-without-loop) or functions having instructions more than -mpatch-functions-min-instructions are patched. - -mpatch-functions-ignore-loops -Target RejectNegative Report Var(patch_functions_ignore_loops) Save -Ignore loops when deciding whether to patch a function for instrumentation (for use with -mpatch-functions-for-instrumentation). - -mno-patch-functions-main-always -Target Report RejectNegative Var(patch_functions_dont_always_patch_main) Save -Treat 'main' as any other function and only patch it if it meets the criteria for loops and minimum number of instructions (for use with -mpatch-functions-for-instrumentation). - mstack-protector-guard= Target RejectNegative Joined Enum(stack_protector_guard) Var(ix86_stack_protector_guard) Init(SSP_TLS) Use given stack-protector guard @@ -806,3 +794,43 @@ Enum(stack_protector_guard) String(tls) Value(SSP_TLS) EnumValue Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL) + +mindirect-branch= +Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep) +Update indirect call and jump. + +mfunction-return= +Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep) +Update function return. + +Enum +Name(indirect_branch) Type(enum indirect_branch) +Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= 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) + +mindirect-branch-loop= +Target Report RejectNegative Joined Enum(indirect_branch_loop) Var(ix86_indirect_branch_loop) Undocumented Init(indirect_branch_loop_lfence) + +Enum +Name(indirect_branch_loop) Type(enum indirect_branch_loop) +Known loop choices (for use with the -mindirect-branch-loop= option): + +EnumValue +Enum(indirect_branch_loop) String(lfence) Value(indirect_branch_loop_lfence) + +EnumValue +Enum(indirect_branch_loop) String(pause) Value(indirect_branch_loop_pause) + +EnumValue +Enum(indirect_branch_loop) String(nop) Value(indirect_branch_loop_nop) diff --git a/gcc-4.9/gcc/params.def b/gcc-4.9/gcc/params.def index 518d379ed..31bd13d4e 100644 --- a/gcc-4.9/gcc/params.def +++ b/gcc-4.9/gcc/params.def @@ -1338,15 +1338,6 @@ DEFPARAM (PARAM_MAX_SLSR_CANDIDATE_SCAN, "strength reduction", 50, 1, 999999) -/* Parameters to be used with -mpatch-functions-for-instrumentation. - See config/i386/i386.opt */ -DEFPARAM (PARAM_FUNCTION_PATCH_MIN_INSTRUCTIONS, - "function-patch-min-instructions", - "Minimum number of instructions in the function without loop before " - "the function is qualified for patching for instrumentation (for use " - "with -mpatch-functions-for-instrumentation)", - 200, 0, 0) - DEFPARAM (PARAM_ASAN_STACK, "asan-stack", "Enable asan stack protection", diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c new file mode 100644 index 000000000..46ae8329b --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c new file mode 100644 index 000000000..7c8100822 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ + /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c new file mode 100644 index 000000000..46685d9a6 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c new file mode 100644 index 000000000..8f701775c --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c new file mode 100644 index 000000000..008ccac3a --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ + +void func0 (void); +void func1 (void); +void func2 (void); +void func3 (void); +void func4 (void); +void func5 (void); + +void +bar (int i) +{ + switch (i) + { + default: + func0 (); + break; + case 1: + func1 (); + break; + case 2: + func2 (); + break; + case 3: + func3 (); + break; + case 4: + func4 (); + break; + case 5: + func5 (); + break; + } +} + +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c new file mode 100644 index 000000000..88c87c10d --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c new file mode 100644 index 000000000..80f370564 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c new file mode 100644 index 000000000..7f56725e6 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c new file mode 100644 index 000000000..fd4ab1dba --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c new file mode 100644 index 000000000..1ffbf3b11 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c new file mode 100644 index 000000000..155907291 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c new file mode 100644 index 000000000..58347f315 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ + +void func0 (void); +void func1 (void); +void func2 (void); +void func3 (void); +void func4 (void); +void func5 (void); + +__attribute__ ((indirect_branch("thunk-extern"))) +void +bar (int i) +{ + switch (i) + { + default: + func0 (); + break; + case 1: + func1 (); + break; + case 2: + func2 (); + break; + case 3: + func3 (); + break; + case 4: + func4 (); + break; + case 5: + func5 (); + break; + } +} + +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c new file mode 100644 index 000000000..3a7cbf03f --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ + +void func0 (void); +void func1 (void); +void func2 (void); +void func3 (void); +void func4 (void); +void func5 (void); + +__attribute__ ((indirect_branch("keep"))) +void +bar (int i) +{ + switch (i) + { + default: + func0 (); + break; + case 1: + func1 (); + break; + case 2: + func2 (); + break; + case 3: + func3 (); + break; + case 4: + func4 (); + break; + case 5: + func5 (); + break; + } +} + +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c new file mode 100644 index 000000000..03a4bd0aa --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c new file mode 100644 index 000000000..216b60a5e --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ + /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c new file mode 100644 index 000000000..153723941 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c new file mode 100644 index 000000000..c82e53068 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c new file mode 100644 index 000000000..a2614e56c --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ + +void func0 (void); +void func1 (void); +void func2 (void); +void func3 (void); +void func4 (void); +void func5 (void); + +void +bar (int i) +{ + switch (i) + { + default: + func0 (); + break; + case 1: + func1 (); + break; + case 2: + func2 (); + break; + case 3: + func3 (); + break; + case 4: + func4 (); + break; + case 5: + func5 (); + break; + } +} + +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c new file mode 100644 index 000000000..58f2de923 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c new file mode 100644 index 000000000..cfccefd24 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c new file mode 100644 index 000000000..6fe5ce71a --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c new file mode 100644 index 000000000..65cd997a3 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -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 "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c new file mode 100644 index 000000000..3482bfeda --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ + +void func0 (void); +void func1 (void); +void func2 (void); +void func3 (void); +void func4 (void); +void func5 (void); + +void +bar (int i) +{ + switch (i) + { + default: + func0 (); + break; + case 1: + func1 (); + break; + case 2: + func2 (); + break; + case 3: + func3 (); + break; + case 4: + func4 (); + break; + case 5: + func5 (); + break; + } +} + +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c new file mode 100644 index 000000000..fefeaece8 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=pause -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } * +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c new file mode 100644 index 000000000..8975cf35c --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=nop -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tnop} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c new file mode 100644 index 000000000..d103c4d6a --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=lfence -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c new file mode 100644 index 000000000..4c75a0a3a --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-loop=pause -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c new file mode 100644 index 000000000..081f51250 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-loop=pause -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause|nop)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-1.c deleted file mode 100644 index aa1f424c8..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-1.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Verify -mpatch-functions-for-instrumentation works. */ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation" } */ - -/* Check nop-bytes at beginning. */ -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* Check nop-bytes at end. */ -/* { dg-final { scan-assembler "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((noinline)) -void foo() -{ - /* Dummy loop. */ - int x = 0; - while (++x); -} - -int main() -{ - foo(); - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-2.c deleted file mode 100644 index 78de86763..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-2.c +++ /dev/null @@ -1,21 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation -mno-patch-functions-main-always" } */ - -/* Function is small to be instrumented with default values. Check there - aren't any nop-bytes at beginning or end of function. */ - -/* { dg-final { scan-assembler-not ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler-not "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((noinline)) -void foo() -{ - int x = 0; -} - -int main() -{ - foo(); - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-3.c deleted file mode 100644 index 9e8eb52ae..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-3.c +++ /dev/null @@ -1,21 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation --param function-patch-min-instructions=0" } */ - -/* Function should have nop-bytes with -mpatch-function-min-instructions=0. - Check there are nop-bytes at beginning and end of function. */ - -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((noinline)) -void foo() -{ - int x = 0; -} - -int main() -{ - foo(); - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-4.c deleted file mode 100644 index 7a031d796..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-4.c +++ /dev/null @@ -1,22 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation -mpatch-functions-ignore-loops -mno-patch-functions-main-always" } */ - -/* Function is too small to be patched when ignoring the loop. - Check there aren't any nop-bytes at beginning and end of function. */ - -/* { dg-final { scan-assembler-not ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler-not "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((noinline)) -void foo() -{ - int x = 0; - while (++x); -} - -int main() -{ - foo(); - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-5.c deleted file mode 100644 index cd6a014cd..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-5.c +++ /dev/null @@ -1,22 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation -mpatch-functions-ignore-loops --param function-patch-min-instructions=0" } */ - -/* Function should be patched with nop bytes with given options. - Check there are nop-bytes at beginning and end of function. */ - -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((noinline)) -void foo() -{ - int x = 0; - while (++x); -} - -int main() -{ - foo(); - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-6.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-6.c deleted file mode 100644 index c1d644686..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-6.c +++ /dev/null @@ -1,15 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation" } */ - -/* 'main' function should always be patched, irrespective of how small it is. - Check there are nop-bytes at beginning and end of main. */ - -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -int main() -{ - int x = 0; - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-7.c deleted file mode 100644 index f625298d6..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-7.c +++ /dev/null @@ -1,15 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation -mno-patch-functions-main-always" } */ - -/* 'main' shouldn't be patched with the option -mno-patch-functions-main-always. - Check there aren't any nop-bytes at beginning and end of main. */ - -/* { dg-final { scan-assembler-not ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler-not "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -int main() -{ - int x = 0; - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-8.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-8.c deleted file mode 100644 index 436379cb2..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-8.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Verify -mpatch-functions-for-instrumentation works. */ -/* { dg-do run } */ -/* { dg-require-effective-target lp64 } */ - -/* -O2 forces a sibling call for foo from bar. */ -/* { dg-options "-O2 -mpatch-functions-for-instrumentation --param function-patch-min-instructions=0" } */ - -__attribute__ ((noinline)) -int foo() -{ - /* Dummy loop. */ - int x = 10; - int y = 100; - while (--x) - ++y; - return y; -} - -__attribute__ ((noinline)) -int bar() -{ - return foo(); -} - -int main() -{ - bar(); - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-no-patching.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-no-patching.c deleted file mode 100644 index cad6f2da6..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-no-patching.c +++ /dev/null @@ -1,27 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-mpatch-functions-for-instrumentation -mno-patch-functions-main-always" } */ - -/* Even complicated functions shouldn't get patched if they have the - never_patch_for_instrumentation attribute. */ - -/* { dg-final { scan-assembler-not ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler-not "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((never_patch_for_instrumentation)) -int foo () { - volatile unsigned x = 0; - volatile unsigned y = 1; - x += y; - x *= y; - while (++x) - foo (); - return y; -} - - -int main () -{ - int x = 0; - return 0; -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-patching.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-patching.c deleted file mode 100644 index 86ad1594c..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-force-patching.c +++ /dev/null @@ -1,20 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* { dg-options "-O3 -mpatch-functions-for-instrumentation -mno-patch-functions-main-always" } */ - -/* Functions which have the always_patch attribute should be patched no matter - what. Check that there are nop-bytes at the beginning and end of the - function. We add -O3 so that the compiler will try to inline foo (but it - will be blocked by the attribute). */ - -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ -/* { dg-final { scan-assembler "ret(.*).byte\t0x90(.*).byte\t0x90" } } */ - -__attribute__ ((always_patch_for_instrumentation)) -static int foo () { - return 3; -} - -int main () { - volatile int x = foo (); -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-sibling-call.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-sibling-call.c deleted file mode 100644 index 847a95ce6..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/patch-functions-sibling-call.c +++ /dev/null @@ -1,26 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target lp64 } */ -/* -O2 forces a sibling call. */ -/* { dg-options "-O2 -mpatch-functions-for-instrumentation" } */ - -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90" } } */ - -/* Checks correct nop-bytes are generated just before a sibling call. */ -/* { dg-final { scan-assembler ".byte\t0xeb,0x09(.*).byte\t0x90(.*)jmp" } } */ - -/* Not instrumented as function has no loop and is small. */ -__attribute__ ((noinline)) -int foo(int n) -{ - int x = 0; - return n + 10; -} - -__attribute__ ((noinline)) -int bar(int n) -{ - /* Dummy loop. */ - while (--n) - n = n * 2; - return foo(n); -} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c new file mode 100644 index 000000000..406956f48 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c new file mode 100644 index 000000000..aecea4224 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */ + +extern void (*bar) (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tlfence} 2 } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk:" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk\.(r|e)ax:" { target { x32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c new file mode 100644 index 000000000..fee860922 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */ + +extern void (*bar) (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk:" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk\.(r|e)ax:" { target { x3 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c new file mode 100644 index 000000000..851115ac5 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ + +extern void (*bar) (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk:" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk\.(r|e)ax:" { target { x32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c new file mode 100644 index 000000000..7acb6fa5e --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ + +extern void (*bar) (void); +extern int foo (void) __attribute__ ((function_return("thunk"))); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tlfence} 2 } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 3 } } */ +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 3 } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c new file mode 100644 index 000000000..bf340fac7 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ + +extern void (*bar) (void); + +__attribute__ ((function_return("thunk-inline"))) +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c new file mode 100644 index 000000000..735f8648c --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */ + +extern void (*bar) (void); + +__attribute__ ((function_return("thunk-extern"), indirect_branch("thunk"))) +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c new file mode 100644 index 000000000..cf3920563 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk-extern -fno-pic" } */ + +extern void (*bar) (void); + +__attribute__ ((function_return("keep"), indirect_branch("keep"))) +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c new file mode 100644 index 000000000..190947cc2 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk-inline" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c new file mode 100644 index 000000000..d71de3ac5 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk-extern" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c new file mode 100644 index 000000000..68c22122f --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c new file mode 100644 index 000000000..28c576e22 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep" } */ + +extern void foo (void) __attribute__ ((function_return("thunk"))); + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c new file mode 100644 index 000000000..10ad40b9c --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep" } */ + +__attribute__ ((function_return("thunk-inline"))) +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c new file mode 100644 index 000000000..7ac0beaa7 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=keep" } */ + +__attribute__ ((function_return("thunk-extern"))) +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c new file mode 100644 index 000000000..777ab7c80 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk-inline" } */ + +extern void foo (void) __attribute__ ((function_return("keep"))); + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c new file mode 100644 index 000000000..0b285caa2 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic"} */ + +extern void (*bar) (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not "__x86.return_thunk:" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "__x86.indirect_thunk:" } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times {\tlfence} 2 { target { x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ -- cgit v1.2.3 From 46936205f991de051a9555a03f856683475a2be5 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Fri, 19 Jan 2018 11:35:09 -0800 Subject: [libgcc] Fix emutls.c to not leak pthread keys. Bug:b/71814577 Test:Built toolchain w/change and successfully tested building both platform and kernel images with new toolchain for marlin (pixel) device. Change-Id: Ia0c6944ce1d78b5bd57d65f705a3f7a59c944202 --- gcc-4.9/libgcc/emutls.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gcc-4.9/libgcc/emutls.c b/gcc-4.9/libgcc/emutls.c index fd6d86ed9..77550e057 100644 --- a/gcc-4.9/libgcc/emutls.c +++ b/gcc-4.9/libgcc/emutls.c @@ -60,6 +60,7 @@ static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT; static __gthread_mutex_t emutls_mutex; #endif static __gthread_key_t emutls_key; +static int emutls_key_created = 0; static pointer emutls_size; static void @@ -86,9 +87,18 @@ emutls_init (void) #endif if (__gthread_key_create (&emutls_key, emutls_destroy) != 0) abort (); + emutls_key_created = 1; } #endif +__attribute__((destructor)) +static void +unregister_emutls_key (void) +{ + if (emutls_key_created) + __gthread_key_delete (emutls_key); +} + static void * emutls_alloc (struct __emutls_object *obj) { -- cgit v1.2.3 From d64d815b3af9d2653d924ea2e1ebb21ee8b043b7 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Mon, 29 Jan 2018 13:36:52 -0800 Subject: [GCC] Update with latest retpoline fixes from Intel. Intel has updated their retpoline patches since we created our original patch. This CL updates our retpoline changes to match the latest from Intel. Bug: None Test: Tested extensively in ChromeOS. Built x86 platform & kernel images in Android. Change-Id: Id1a18cb1f1f4461832a017cb5c5d59e5400d9d08 --- gcc-4.9/gcc/config/i386/constraints.md | 3 +- gcc-4.9/gcc/config/i386/i386-opts.h | 11 +- gcc-4.9/gcc/config/i386/i386.c | 269 ++++++++++++++++----- gcc-4.9/gcc/config/i386/i386.md | 22 +- gcc-4.9/gcc/config/i386/i386.opt | 22 +- gcc-4.9/gcc/config/i386/predicates.md | 6 +- gcc-4.9/gcc/doc/extend.texi | 19 ++ gcc-4.9/gcc/doc/invoke.texi | 39 ++- .../testsuite/gcc.target/i386/indirect-thunk-1.c | 9 +- .../testsuite/gcc.target/i386/indirect-thunk-10.c | 7 + .../testsuite/gcc.target/i386/indirect-thunk-2.c | 11 +- .../testsuite/gcc.target/i386/indirect-thunk-3.c | 9 +- .../testsuite/gcc.target/i386/indirect-thunk-4.c | 9 +- .../testsuite/gcc.target/i386/indirect-thunk-7.c | 10 +- .../testsuite/gcc.target/i386/indirect-thunk-8.c | 7 + .../testsuite/gcc.target/i386/indirect-thunk-9.c | 7 + .../gcc.target/i386/indirect-thunk-attr-1.c | 9 +- .../gcc.target/i386/indirect-thunk-attr-10.c | 9 + .../gcc.target/i386/indirect-thunk-attr-11.c | 9 + .../gcc.target/i386/indirect-thunk-attr-2.c | 9 +- .../gcc.target/i386/indirect-thunk-attr-3.c | 8 +- .../gcc.target/i386/indirect-thunk-attr-4.c | 8 +- .../gcc.target/i386/indirect-thunk-attr-5.c | 8 +- .../gcc.target/i386/indirect-thunk-attr-6.c | 8 +- .../gcc.target/i386/indirect-thunk-attr-7.c | 9 +- .../gcc.target/i386/indirect-thunk-attr-8.c | 4 +- .../gcc.target/i386/indirect-thunk-attr-9.c | 9 + .../gcc.target/i386/indirect-thunk-extern-1.c | 8 +- .../gcc.target/i386/indirect-thunk-extern-2.c | 10 +- .../gcc.target/i386/indirect-thunk-extern-3.c | 8 +- .../gcc.target/i386/indirect-thunk-extern-4.c | 8 +- .../gcc.target/i386/indirect-thunk-extern-7.c | 9 +- .../gcc.target/i386/indirect-thunk-inline-1.c | 8 +- .../gcc.target/i386/indirect-thunk-inline-2.c | 8 +- .../gcc.target/i386/indirect-thunk-inline-3.c | 8 +- .../gcc.target/i386/indirect-thunk-inline-4.c | 8 +- .../gcc.target/i386/indirect-thunk-inline-7.c | 9 +- .../gcc.target/i386/indirect-thunk-loop-1.c | 19 -- .../gcc.target/i386/indirect-thunk-loop-2.c | 19 -- .../gcc.target/i386/indirect-thunk-loop-3.c | 19 -- .../gcc.target/i386/indirect-thunk-loop-4.c | 19 -- .../gcc.target/i386/indirect-thunk-loop-5.c | 19 -- .../gcc.target/i386/indirect-thunk-register-1.c | 21 ++ .../gcc.target/i386/indirect-thunk-register-2.c | 20 ++ .../gcc.target/i386/indirect-thunk-register-3.c | 19 ++ .../gcc.target/i386/indirect-thunk-register-4.c | 13 + .../gcc/testsuite/gcc.target/i386/ret-thunk-1.c | 3 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 15 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 15 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 13 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 11 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 11 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 11 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-16.c | 6 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-17.c | 7 + .../gcc/testsuite/gcc.target/i386/ret-thunk-18.c | 8 + .../gcc/testsuite/gcc.target/i386/ret-thunk-19.c | 8 + .../gcc/testsuite/gcc.target/i386/ret-thunk-2.c | 3 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-20.c | 9 + .../gcc/testsuite/gcc.target/i386/ret-thunk-21.c | 9 + .../gcc/testsuite/gcc.target/i386/ret-thunk-3.c | 4 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-4.c | 4 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-5.c | 3 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-6.c | 3 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-7.c | 4 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-8.c | 4 +- .../gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 15 +- 67 files changed, 643 insertions(+), 325 deletions(-) create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c delete mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-17.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-18.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-19.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-20.c create mode 100644 gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-21.c diff --git a/gcc-4.9/gcc/config/i386/constraints.md b/gcc-4.9/gcc/config/i386/constraints.md index 567e70564..ce1481122 100644 --- a/gcc-4.9/gcc/config/i386/constraints.md +++ b/gcc-4.9/gcc/config/i386/constraints.md @@ -153,7 +153,8 @@ (define_constraint "w" "@internal Call memory operand." - (and (not (match_test "TARGET_X32")) + (and (not (match_test "ix86_indirect_branch_register")) + (not (match_test "TARGET_X32")) (match_operand 0 "memory_operand"))) ;; Integer constant constraints. diff --git a/gcc-4.9/gcc/config/i386/i386-opts.h b/gcc-4.9/gcc/config/i386/i386-opts.h index e98cd8c1e..f44620781 100644 --- a/gcc-4.9/gcc/config/i386/i386-opts.h +++ b/gcc-4.9/gcc/config/i386/i386-opts.h @@ -93,6 +93,11 @@ enum stack_protector_guard { SSP_GLOBAL /* global canary */ }; +/* This is used to mitigate variant #2 of the speculative execution + vulnerabilities on x86 processors identified by CVE-2017-5715, aka + Spectre. They convert indirect branches and function returns to + call and return thunks to avoid speculative execution via indirect + call, jmp and ret. */ enum indirect_branch { indirect_branch_unset = 0, indirect_branch_keep, @@ -101,10 +106,4 @@ enum indirect_branch { indirect_branch_thunk_extern }; -enum indirect_branch_loop { - indirect_branch_loop_lfence, - indirect_branch_loop_pause, - indirect_branch_loop_nop -}; - #endif diff --git a/gcc-4.9/gcc/config/i386/i386.c b/gcc-4.9/gcc/config/i386/i386.c index ccd2f150b..975a84dea 100644 --- a/gcc-4.9/gcc/config/i386/i386.c +++ b/gcc-4.9/gcc/config/i386/i386.c @@ -2515,7 +2515,11 @@ make_pass_insert_vzeroupper (gcc::context *ctxt) there are local indirect jumps, like "indirect_jump" or "tablejump", which jumps to another place in the function, since "call" in the indirect thunk pushes the return address onto stack, destroying - red-zone. */ + red-zone. + + TODO: If we can reserve the first 2 WORDs, for PUSH and, another + for CALL, in red-zone, we can allow local indirect jumps with + indirect thunk. */ static inline bool ix86_using_red_zone (void) @@ -4954,6 +4958,19 @@ ix86_set_indirect_branch_type (tree fndecl) } else cfun->machine->indirect_branch_type = ix86_indirect_branch; + + /* -mcmodel=large is not compatible with -mindirect-branch=thunk + nor -mindirect-branch=thunk-extern. */ + if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC) + && ((cfun->machine->indirect_branch_type + == indirect_branch_thunk_extern) + || (cfun->machine->indirect_branch_type + == indirect_branch_thunk))) + error ("%<-mindirect-branch=%s%> and %<-mcmodel=large%> are not " + "compatible", + ((cfun->machine->indirect_branch_type + == indirect_branch_thunk_extern) + ? "thunk-extern" : "thunk")); } if (cfun->machine->function_return_type == indirect_branch_unset) @@ -4979,6 +4996,19 @@ ix86_set_indirect_branch_type (tree fndecl) } else cfun->machine->function_return_type = ix86_function_return; + + /* -mcmodel=large is not compatible with -mfunction-return=thunk + nor -mfunction-return=thunk-extern. */ + if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC) + && ((cfun->machine->function_return_type + == indirect_branch_thunk_extern) + || (cfun->machine->function_return_type + == indirect_branch_thunk))) + error ("%<-mfunction-return=%s%> and %<-mcmodel=large%> are not " + "compatible", + ((cfun->machine->function_return_type + == indirect_branch_thunk_extern) + ? "thunk-extern" : "thunk")); } } @@ -9168,9 +9198,15 @@ ix86_setup_frame_addresses (void) # endif #endif +/* Label count for call and return thunks. It is used to make unique + labels in call and return thunks. */ static int indirectlabelno; + +/* True if call and return thunk functions are needed. */ static bool indirect_thunk_needed = false; +/* Bit masks of integer registers, which contain branch target, used + by call and return thunks functions. */ static int indirect_thunks_used; #ifndef INDIRECT_LABEL @@ -9194,13 +9230,13 @@ indirect_thunk_name (char name[32], int regno, bool ret_p) reg_prefix = TARGET_64BIT ? "r" : "e"; else reg_prefix = ""; - sprintf (name, "__x86.indirect_thunk.%s%s", + sprintf (name, "__x86_indirect_thunk_%s%s", reg_prefix, reg_names[regno]); } else { const char *ret = ret_p ? "return" : "indirect"; - sprintf (name, "__x86.%s_thunk", ret); + sprintf (name, "__x86_%s_thunk", ret); } } else @@ -9217,6 +9253,30 @@ indirect_thunk_name (char name[32], int regno, bool ret_p) } } +/* Output a call and return thunk for indirect branch. If REGNO != -1, + the function address is in REGNO and the call and return thunk looks + like: + + call L2 + L1: + pause + jmp L1 + L2: + mov %REG, (%sp) + ret + + Otherwise, the function address is on the top of stack and the + call and return thunk looks like: + + call L2 + L1: + pause + jmp L1 + L2: + lea WORD_SIZE(%sp), %sp + ret + */ + static void output_indirect_thunk (int regno) { @@ -9235,23 +9295,8 @@ output_indirect_thunk (int regno) ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); - switch (ix86_indirect_branch_loop) - { - case indirect_branch_loop_lfence: - /* lfence. */ - fprintf (asm_out_file, "\tlfence\n"); - break; - case indirect_branch_loop_pause: - /* pause. */ - fprintf (asm_out_file, "\tpause\n"); - break; - case indirect_branch_loop_nop: - /* nop. */ - fprintf (asm_out_file, "\tnop\n"); - break; - default: - gcc_unreachable (); - } + /* Pause + lfence. */ + fprintf (asm_out_file, "\tpause\n\tlfence\n"); /* Jump. */ fputs ("\tjmp\t", asm_out_file); @@ -9280,13 +9325,17 @@ output_indirect_thunk (int regno) fputs ("\tret\n", asm_out_file); } +/* Output a funtion with a call and return thunk for indirect branch. + If REGNO != -1, the function address is in REGNO. Otherwise, the + function address is on the top of stack. */ + static void output_indirect_thunk_function (int regno) { char name[32]; tree decl; - /* Create __x86.indirect_thunk. */ + /* Create __x86_indirect_thunk. */ indirect_thunk_name (name, regno, false); decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier (name), @@ -9332,11 +9381,10 @@ output_indirect_thunk_function (int regno) if (regno < 0) { - /* Create alias for __x86.return_thunk. */ + /* Create alias for __x86_return_thunk. */ char alias[32]; indirect_thunk_name (alias, regno, true); - ASM_OUTPUT_DEF (asm_out_file, alias, name); #if TARGET_MACHO if (TARGET_MACHO) { @@ -9345,8 +9393,10 @@ output_indirect_thunk_function (int regno) fputs ("\n\t.private_extern\t", asm_out_file); assemble_name (asm_out_file, alias); putc ('\n', asm_out_file); + ASM_OUTPUT_LABEL (asm_out_file, alias); } #else + ASM_OUTPUT_DEF (asm_out_file, alias, name); if (USE_HIDDEN_LINKONCE) { fputs ("\t.globl\t", asm_out_file); @@ -10981,6 +11031,7 @@ ix86_expand_prologue (void) { struct machine_function *m = cfun->machine; rtx insn, t; + struct ix86_frame frame; bool pic_reg_used; HOST_WIDE_INT allocate; bool int_registers_saved; @@ -11004,7 +11055,7 @@ ix86_expand_prologue (void) m->fs.sp_valid = true; ix86_compute_frame_layout (); - struct ix86_frame &frame = m->frame; + frame = m->frame; if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl)) { @@ -11737,12 +11788,13 @@ ix86_expand_epilogue (int style) { struct machine_function *m = cfun->machine; struct machine_frame_state frame_state_save = m->fs; + struct ix86_frame frame; bool restore_regs_via_mov; bool using_drap; ix86_finalize_stack_realign_flags (); ix86_compute_frame_layout (); - struct ix86_frame &frame = m->frame; + frame = m->frame; m->fs.sp_valid = (!frame_pointer_needed || (crtl->sp_is_unchanging @@ -14931,7 +14983,7 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, bool reverse, If CODE is 'h', pretend the reg is the 'high' byte register. If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. If CODE is 'd', duplicate the operand for AVX instruction. - If CODE is 'V', print naked register name without %. + If CODE is 'V', print naked full integer register name without %. */ void @@ -14976,6 +15028,13 @@ print_reg (rtx x, int code, FILE *file) code = 32; else if (code == 'g') code = 64; + else if (code == 'V') + { + if (GENERAL_REGNO_P (regno)) + code = GET_MODE_SIZE (word_mode); + else + error ("'V' modifier on non-integer register"); + } else code = GET_MODE_SIZE (GET_MODE (x)); @@ -15142,7 +15201,7 @@ get_some_local_dynamic_name (void) & -- print some in-use local-dynamic symbol name. H -- print a memory address offset by 8; used for sse high-parts Y -- print condition for XOP pcom* instruction. - V -- print naked register name without %. + V -- print naked full integer register name without %. + -- print a branch hint as 'cs' or 'ds' prefix ; -- print a semicolon (after prefixes due to bug in older gas). ~ -- print "i" if TARGET_AVX2, "f" otherwise. @@ -25304,48 +25363,131 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, return call; } +/* Output indirect branch via a call and return thunk. CALL_OP is a + register which contains the branch target. XASM is the assembly + template for CALL_OP. Branch is a tail call if SIBCALL_P is true. + A normal call is converted to: + + call __x86_indirect_thunk_reg + + and a tail call is converted to: + + jmp __x86_indirect_thunk_reg + */ + static void -ix86_output_indirect_branch (rtx call_op, const char *xasm, - bool sibcall_p) +ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) { char thunk_name_buf[32]; char *thunk_name; - char push_buf[64]; - int regno; - - if (REG_P (call_op)) - regno = REGNO (call_op); - else - regno = -1; + int regno = REGNO (call_op); if (cfun->machine->indirect_branch_type != indirect_branch_thunk_inline) { if (cfun->machine->indirect_branch_type == indirect_branch_thunk) - { - if (regno >= 0) - { - int i = regno; - if (i >= FIRST_REX_INT_REG) - i -= (FIRST_REX_INT_REG - SP_REG - 1); - indirect_thunks_used |= 1 << i; - } - else - indirect_thunk_needed = true; - } + { + int i = regno; + if (i >= FIRST_REX_INT_REG) + i -= (FIRST_REX_INT_REG - SP_REG - 1); + indirect_thunks_used |= 1 << i; + } indirect_thunk_name (thunk_name_buf, regno, false); thunk_name = thunk_name_buf; } else thunk_name = NULL; + if (sibcall_p) + { + if (thunk_name != NULL) + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); + else + output_indirect_thunk (regno); + } + else + { + if (thunk_name != NULL) + { + fprintf (asm_out_file, "\tcall\t%s\n", thunk_name); + return; + } + + char indirectlabel1[32]; + char indirectlabel2[32]; + + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, + INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, + INDIRECT_LABEL, + indirectlabelno++); + + /* Jump. */ + fputs ("\tjmp\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel2); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); + + if (thunk_name != NULL) + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); + else + output_indirect_thunk (regno); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); + + /* Call. */ + fputs ("\tcall\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel1); + fputc ('\n', asm_out_file); + } +} + +/* Output indirect branch via a call and return thunk. CALL_OP is + the branch target. XASM is the assembly template for CALL_OP. + Branch is a tail call if SIBCALL_P is true. A normal call is + converted to: + + jmp L2 + L1: + push CALL_OP + jmp __x86_indirect_thunk + L2: + call L1 + + and a tail call is converted to: + + push CALL_OP + jmp __x86_indirect_thunk + */ + +static void +ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm, + bool sibcall_p) +{ + char thunk_name_buf[32]; + char *thunk_name; + char push_buf[64]; + int regno = -1; + + if (cfun->machine->indirect_branch_type + != indirect_branch_thunk_inline) + { + if (cfun->machine->indirect_branch_type == indirect_branch_thunk) + indirect_thunk_needed = true; + indirect_thunk_name (thunk_name_buf, regno, false); + thunk_name = thunk_name_buf; + } + else + thunk_name = NULL; + snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s", TARGET_64BIT ? 'q' : 'l', xasm); if (sibcall_p) { - if (regno < 0) - output_asm_insn (push_buf, &call_op); + output_asm_insn (push_buf, &call_op); if (thunk_name != NULL) fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); else @@ -25353,12 +25495,6 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm, } else { - if (regno >= 0 && thunk_name != NULL) - { - fprintf (asm_out_file, "\tcall\t%s\n", thunk_name); - return; - } - char indirectlabel1[32]; char indirectlabel2[32]; @@ -25376,6 +25512,7 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm, ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); + /* An external function may be called via GOT, instead of PLT. */ if (MEM_P (call_op)) { struct ix86_address parts; @@ -25408,8 +25545,7 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm, } } - if (regno < 0) - output_asm_insn (push_buf, &call_op); + output_asm_insn (push_buf, &call_op); if (thunk_name != NULL) fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name); @@ -25425,6 +25561,22 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm, } } +/* Output indirect branch via a call and return thunk. CALL_OP is + the branch target. XASM is the assembly template for CALL_OP. + Branch is a tail call if SIBCALL_P is true. */ + +static void +ix86_output_indirect_branch (rtx call_op, const char *xasm, + bool sibcall_p) +{ + if (REG_P (call_op)) + ix86_output_indirect_branch_via_reg (call_op, sibcall_p); + else + ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p); +} +/* Output indirect jump. CALL_OP is the jump target. Jump is a + function return if RET_P is true. */ + const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p) { @@ -25468,6 +25620,9 @@ ix86_nopic_noplt_attribute_p (rtx call_op) return false; } +/* Output function return. CALL_OP is the jump target. Add a REP + prefix to RET if LONG_P is true and function return is kept. */ + const char * ix86_output_function_return (bool long_p) { diff --git a/gcc-4.9/gcc/config/i386/i386.md b/gcc-4.9/gcc/config/i386/i386.md index e32ba52a6..f5eff3d90 100644 --- a/gcc-4.9/gcc/config/i386/i386.md +++ b/gcc-4.9/gcc/config/i386/i386.md @@ -11140,7 +11140,7 @@ [(set (pc) (match_operand 0 "indirect_branch_operand"))] "" { - if (TARGET_X32) + if (TARGET_X32 || ix86_indirect_branch_register) operands[0] = convert_memory_address (word_mode, operands[0]); cfun->machine->has_local_indirect_jump = true; }) @@ -11149,7 +11149,11 @@ [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))] "" "* return ix86_output_indirect_jmp (operands[0], false);" - [(set_attr "type" "ibr") + [(set (attr "type") + (if_then_else (match_test "(cfun->machine->indirect_branch_type + != indirect_branch_keep)") + (const_string "multi") + (const_string "ibr"))) (set_attr "length_immediate" "0")]) (define_expand "tablejump" @@ -11189,7 +11193,7 @@ OPTAB_DIRECT); } - if (TARGET_X32) + if (TARGET_X32 || ix86_indirect_branch_register) operands[0] = convert_memory_address (word_mode, operands[0]); cfun->machine->has_local_indirect_jump = true; }) @@ -11199,7 +11203,11 @@ (use (label_ref (match_operand 1)))] "" "* return ix86_output_indirect_jmp (operands[0], false);" - [(set_attr "type" "ibr") + [(set (attr "type") + (if_then_else (match_test "(cfun->machine->indirect_branch_type + != indirect_branch_keep)") + (const_string "multi") + (const_string "ibr"))) (set_attr "length_immediate" "0")]) ;; Convert setcc + movzbl to xor + setcc if operands don't overlap. @@ -11620,7 +11628,11 @@ (use (match_operand:SI 0 "register_operand" "r"))] "reload_completed" "* return ix86_output_indirect_jmp (operands[0], true);" - [(set_attr "type" "ibr") + [(set (attr "type") + (if_then_else (match_test "(cfun->machine->indirect_branch_type + != indirect_branch_keep)") + (const_string "multi") + (const_string "ibr"))) (set_attr "length_immediate" "0")]) (define_insn "nop" diff --git a/gcc-4.9/gcc/config/i386/i386.opt b/gcc-4.9/gcc/config/i386/i386.opt index 3b4a86066..502037b68 100644 --- a/gcc-4.9/gcc/config/i386/i386.opt +++ b/gcc-4.9/gcc/config/i386/i386.opt @@ -797,11 +797,11 @@ Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL) mindirect-branch= Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep) -Update indirect call and jump. +Convert indirect call and jump to call and return thunks. mfunction-return= Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep) -Update function return. +Convert function return to call and return thunk. Enum Name(indirect_branch) Type(enum indirect_branch) @@ -819,18 +819,6 @@ Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline) EnumValue Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern) -mindirect-branch-loop= -Target Report RejectNegative Joined Enum(indirect_branch_loop) Var(ix86_indirect_branch_loop) Undocumented Init(indirect_branch_loop_lfence) - -Enum -Name(indirect_branch_loop) Type(enum indirect_branch_loop) -Known loop choices (for use with the -mindirect-branch-loop= option): - -EnumValue -Enum(indirect_branch_loop) String(lfence) Value(indirect_branch_loop_lfence) - -EnumValue -Enum(indirect_branch_loop) String(pause) Value(indirect_branch_loop_pause) - -EnumValue -Enum(indirect_branch_loop) String(nop) Value(indirect_branch_loop_nop) +mindirect-branch-register +Target Report Var(ix86_indirect_branch_register) Init(0) +Force indirect call and jump via register. diff --git a/gcc-4.9/gcc/config/i386/predicates.md b/gcc-4.9/gcc/config/i386/predicates.md index 8266f3eaf..10afa385c 100644 --- a/gcc-4.9/gcc/config/i386/predicates.md +++ b/gcc-4.9/gcc/config/i386/predicates.md @@ -584,7 +584,8 @@ ;; Test for a valid operand for indirect branch. (define_predicate "indirect_branch_operand" (ior (match_operand 0 "register_operand") - (and (not (match_test "TARGET_X32")) + (and (not (match_test "ix86_indirect_branch_register")) + (not (match_test "TARGET_X32")) (match_operand 0 "memory_operand")))) ;; Test for a valid operand for a call instruction. @@ -593,7 +594,8 @@ (ior (match_test "constant_call_address_operand (op, mode == VOIDmode ? mode : Pmode)") (match_operand 0 "call_register_no_elim_operand") - (and (not (match_test "TARGET_X32")) + (and (not (match_test "ix86_indirect_branch_register")) + (not (match_test "TARGET_X32")) (match_operand 0 "memory_operand")))) ;; Similarly, but for tail calls, in which we cannot allow memory references. diff --git a/gcc-4.9/gcc/doc/extend.texi b/gcc-4.9/gcc/doc/extend.texi index 4c0914a35..dfef30042 100644 --- a/gcc-4.9/gcc/doc/extend.texi +++ b/gcc-4.9/gcc/doc/extend.texi @@ -4088,6 +4088,25 @@ Specify which floating-point unit to use. The @code{target("fpmath=sse,387")} option must be specified as @code{target("fpmath=sse+387")} because the comma would separate different options. + +@item indirect_branch("@var{choice}") +@cindex @code{indirect_branch} function attribute, x86 +On x86 targets, the @code{indirect_branch} attribute causes the compiler +to convert indirect call and jump with @var{choice}. @samp{keep} +keeps indirect call and jump unmodified. @samp{thunk} converts indirect +call and jump to call and return thunk. @samp{thunk-inline} converts +indirect call and jump to inlined call and return thunk. +@samp{thunk-extern} converts indirect call and jump to external call +and return thunk provided in a separate object file. + +@item function_return("@var{choice}") +@cindex @code{function_return} function attribute, x86 +On x86 targets, the @code{function_return} attribute causes the compiler +to convert function return with @var{choice}. @samp{keep} keeps function +return unmodified. @samp{thunk} converts function return to call and +return thunk. @samp{thunk-inline} converts function return to inlined +call and return thunk. @samp{thunk-extern} converts function return to +external call and return thunk provided in a separate object file. @end table On the PowerPC, the following options are allowed: diff --git a/gcc-4.9/gcc/doc/invoke.texi b/gcc-4.9/gcc/doc/invoke.texi index 698ecd659..297657a39 100644 --- a/gcc-4.9/gcc/doc/invoke.texi +++ b/gcc-4.9/gcc/doc/invoke.texi @@ -694,7 +694,8 @@ Objective-C and Objective-C++ Dialects}. -m32 -m64 -mx32 -m16 -mlarge-data-threshold=@var{num} @gol -msse2avx -mfentry -m8bit-idiv @gol -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol --mstack-protector-guard=@var{guard}} +-mstack-protector-guard=@var{guard} -mindirect-branch=@var{choice} @gol +-mfunction-return=@var{choice} -mindirect-branch-register} @emph{i386 and x86-64 Windows Options} @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol @@ -16021,6 +16022,42 @@ locations are @samp{global} for global canary or @samp{tls} for per-thread canary in the TLS block (the default). This option has effect only when @option{-fstack-protector} or @option{-fstack-protector-all} is specified. +@item -mindirect-branch=@var{choice} +@opindex -mindirect-branch +Convert indirect call and jump with @var{choice}. The default is +@samp{keep}, which keeps indirect call and jump unmodified. +@samp{thunk} converts indirect call and jump to call and return thunk. +@samp{thunk-inline} converts indirect call and jump to inlined call +and return thunk. @samp{thunk-extern} converts indirect call and jump +to external call and return thunk provided in a separate object file. +You can control this behavior for a specific function by using the +function attribute @code{indirect_branch}. @xref{Function Attributes}. + +Note that @option{-mcmodel=large} is incompatible with +@option{-mindirect-branch=thunk} nor +@option{-mindirect-branch=thunk-extern} since the thunk function may +not be reachable in large code model. + +@item -mfunction-return=@var{choice} +@opindex -mfunction-return +Convert function return with @var{choice}. The default is @samp{keep}, +which keeps function return unmodified. @samp{thunk} converts function +return to call and return thunk. @samp{thunk-inline} converts function +return to inlined call and return thunk. @samp{thunk-extern} converts +function return to external call and return thunk provided in a separate +object file. You can control this behavior for a specific function by +using the function attribute @code{function_return}. +@xref{Function Attributes}. + +Note that @option{-mcmodel=large} is incompatible with +@option{-mfunction-return=thunk} nor +@option{-mfunction-return=thunk-extern} since the thunk function may +not be reachable in large code model. + +@item -mindirect-branch-register +@opindex -mindirect-branch-register +Force indirect call and jump via register. + @end table These @samp{-m} switches are supported in addition to the above diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c index 46ae8329b..555d6656b 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -11,9 +11,10 @@ male_indirect_jump (long offset) dispatch(offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c new file mode 100644 index 000000000..a0674bd23 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -mfunction-return=keep -mcmodel=large" } */ + +void +bar (void) +{ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c index 7c8100822..009732cb9 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -11,9 +11,10 @@ male_indirect_jump (long offset) dispatch[offset](offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ - /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c index 46685d9a6..dab7ac2ef 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,9 +12,10 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c index 8f701775c..44cc5f52f 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,9 +12,10 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c index 008ccac3a..17c2d0faf 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c @@ -1,11 +1,12 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ void func0 (void); void func1 (void); void func2 (void); void func3 (void); void func4 (void); +void func4 (void); void func5 (void); void @@ -34,9 +35,10 @@ bar (int i) } } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c new file mode 100644 index 000000000..7a80a8986 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mindirect-branch=thunk -mfunction-return=keep -mcmodel=large" } */ + +void +bar (void) +{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c new file mode 100644 index 000000000..d4d45c511 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mfunction-return=keep -mcmodel=large" } */ + +void +bar (void) +{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c index 88c87c10d..a3c7e0071 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -14,9 +14,10 @@ male_indirect_jump (long offset) dispatch(offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c new file mode 100644 index 000000000..3a2aeaddb --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +__attribute__ ((indirect_branch("thunk-extern"))) +void +bar (void) +{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c new file mode 100644 index 000000000..8e52f032b --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +__attribute__ ((indirect_branch("thunk-inline"))) +void +bar (void) +{ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c index 80f370564..a8ca60ec6 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,9 +12,10 @@ male_indirect_jump (long offset) dispatch[offset](offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c index 7f56725e6..4aeec1833 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -14,8 +14,10 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c index fd4ab1dba..ac0e5999f 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -13,8 +13,10 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c index 1ffbf3b11..573cf1ef0 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -14,9 +14,9 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c index 155907291..b2b37fc6e 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -13,9 +13,9 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c index 58347f315..4a43e1999 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c @@ -1,11 +1,12 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */ void func0 (void); void func1 (void); void func2 (void); void func3 (void); void func4 (void); +void func4 (void); void func5 (void); __attribute__ ((indirect_branch("thunk-extern"))) @@ -35,9 +36,9 @@ bar (int i) } } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c index 3a7cbf03f..d730d31bd 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c @@ -6,6 +6,7 @@ void func1 (void); void func2 (void); void func3 (void); void func4 (void); +void func4 (void); void func5 (void); __attribute__ ((indirect_branch("keep"))) @@ -35,6 +36,7 @@ bar (int i) } } -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c new file mode 100644 index 000000000..bdaa4f691 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +__attribute__ ((indirect_branch("thunk"))) +void +bar (void) +{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c index 03a4bd0aa..be19d7219 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -11,9 +11,9 @@ male_indirect_jump (long offset) dispatch(offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c index 216b60a5e..7e761bc46 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -11,9 +11,9 @@ male_indirect_jump (long offset) dispatch[offset](offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ - /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c index 153723941..d9964c25b 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,9 +12,9 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c index c82e53068..d4dca4dc5 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,9 +12,9 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c index a2614e56c..aece93836 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c @@ -1,11 +1,12 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ void func0 (void); void func1 (void); void func2 (void); void func3 (void); void func4 (void); +void func4 (void); void func5 (void); void @@ -34,9 +35,9 @@ bar (int i) } } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c index 58f2de923..a2d16771b 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -11,8 +11,10 @@ male_indirect_jump (long offset) dispatch(offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c index cfccefd24..1b93e8469 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -11,8 +11,10 @@ male_indirect_jump (long offset) dispatch[offset](offset); } -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c index 6fe5ce71a..2eef6f35a 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,8 +12,10 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c index 65cd997a3..e825a10f1 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ typedef void (*dispatch_t)(long offset); @@ -12,8 +12,10 @@ male_indirect_jump (long offset) return 0; } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c index 3482bfeda..c67066cf1 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c @@ -1,11 +1,12 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ void func0 (void); void func1 (void); void func2 (void); void func3 (void); void func4 (void); +void func4 (void); void func5 (void); void @@ -34,8 +35,10 @@ bar (int i) } } -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c deleted file mode 100644 index fefeaece8..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-1.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=pause -fno-pic" } */ - -typedef void (*dispatch_t)(long offset); - -dispatch_t dispatch; - -void -male_indirect_jump (long offset) -{ - dispatch(offset); -} - -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } * -/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler {\tpause} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c deleted file mode 100644 index 8975cf35c..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-2.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=nop -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 "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler {\tnop} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c deleted file mode 100644 index d103c4d6a..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-3.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-loop=lfence -fno-pic" } */ - -typedef void (*dispatch_t)(long offset); - -dispatch_t dispatch; - -void -male_indirect_jump (long offset) -{ - dispatch(offset); -} - -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c deleted file mode 100644 index 4c75a0a3a..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-4.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-loop=pause -fno-pic" } */ - -typedef void (*dispatch_t)(long offset); - -dispatch_t dispatch; - -void -male_indirect_jump (long offset) -{ - dispatch(offset); -} - -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler {\tpause} } } */ -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ -/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c deleted file mode 100644 index 081f51250..000000000 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-loop-5.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-loop=pause -fno-pic" } */ - -typedef void (*dispatch_t)(long offset); - -dispatch_t dispatch; - -void -male_indirect_jump (long offset) -{ - dispatch(offset); -} - -/* { dg-final { scan-assembler "(push|mov)(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ -/* { dg-final { scan-assembler-not {\t(lfence|pause|nop)} } } */ -/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c new file mode 100644 index 000000000..0cf8daeb5 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-register -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk\n" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c new file mode 100644 index 000000000..e7e616bb2 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-register -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c new file mode 100644 index 000000000..5320e923b --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-register -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */ +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */ +/* { dg-final { scan-assembler-not {\t(pause|pause|nop)} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c new file mode 100644 index 000000000..f0cd9b75b --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=keep -fno-pic" } */ + +extern void (*func_p) (void); + +void +foo (void) +{ + asm("call __x86_indirect_thunk_%V0" : : "a" (func_p)); +} + +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_eax" { target ia32 } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_rax" { target { ! ia32 } } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c index 406956f48..7223f67ba 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-1.c @@ -6,7 +6,8 @@ foo (void) { } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c index aecea4224..6de9b8c9f 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-10.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */ extern void (*bar) (void); @@ -12,11 +12,12 @@ foo (void) /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tpause} 2 } } */ /* { dg-final { scan-assembler-times {\tlfence} 2 } } */ -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk:" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk\.(r|e)ax:" { target { x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c index fee860922..365980375 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-11.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */ extern void (*bar) (void); @@ -10,13 +10,14 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ /* { dg-final { scan-assembler-times {\tlfence} 1 } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk:" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk\.(r|e)ax:" { target { x3 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c index 851115ac5..5fb1a4de7 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-12.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */ extern void (*bar) (void); @@ -10,12 +10,13 @@ foo (void) return 0; } -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ /* { dg-final { scan-assembler-times {\tlfence} 1 } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk:" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk\.(r|e)ax:" { target { x32 } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c index 7acb6fa5e..fd5b41fdd 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-13.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */ extern void (*bar) (void); extern int foo (void) __attribute__ ((function_return("thunk"))); @@ -11,11 +11,12 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-times {\tpause} 2 } } */ /* { dg-final { scan-assembler-times {\tlfence} 2 } } */ -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */ /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 3 } } */ /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 3 } } */ -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.indirect_thunk" } } */ -/* { dg-final { scan-assembler-not "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c index bf340fac7..d606373ea 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-14.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */ extern void (*bar) (void); @@ -11,11 +11,12 @@ foo (void) return 0; } +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ /* { dg-final { scan-assembler-times {\tlfence} 1 } } */ -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c index 735f8648c..2038644aa 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-15.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */ extern void (*bar) (void); @@ -11,11 +11,12 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 } } */ /* { dg-final { scan-assembler-times {\tlfence} 1 } } */ -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target x32 } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c index cf3920563..a16cad16a 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-16.c @@ -11,8 +11,8 @@ foo (void) return 0; } -/* { dg-final { scan-assembler-not "__x86.indirect_thunk" } } */ -/* { dg-final { scan-assembler-not "__x86.return_thunk" } } */ -/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */ +/* { dg-final { scan-assembler-not "__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-17.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-17.c new file mode 100644 index 000000000..0605e2c65 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-17.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=keep -mcmodel=large" } */ + +void +bar (void) +{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-18.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-18.c new file mode 100644 index 000000000..307019dc2 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-18.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=keep -mcmodel=large" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +void +bar (void) +{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-19.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-19.c new file mode 100644 index 000000000..772617f40 --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-19.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */ + +__attribute__ ((function_return("thunk"))) +void +bar (void) +{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c index 190947cc2..c6659e3ad 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-2.c @@ -8,5 +8,6 @@ foo (void) /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-20.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-20.c new file mode 100644 index 000000000..1e9f9bd5a --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-20.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +__attribute__ ((function_return("thunk-extern"))) +void +bar (void) +{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-21.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-21.c new file mode 100644 index 000000000..eea07f7ab --- /dev/null +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-21.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target { lp64 } } } */ +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +__attribute__ ((function_return("thunk-inline"))) +void +bar (void) +{ +} diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c index d71de3ac5..0f7f388f4 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-3.c @@ -6,7 +6,7 @@ foo (void) { } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ -/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c index 68c22122f..9ae37e835 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-4.c @@ -6,7 +6,7 @@ foo (void) { } -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ -/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c index 28c576e22..4bd0d2a27 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-5.c @@ -8,7 +8,8 @@ foo (void) { } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c index 10ad40b9c..053841f6f 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-6.c @@ -9,5 +9,6 @@ foo (void) /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ +/* { dg-final { scan-assembler {\tpause} } } */ /* { dg-final { scan-assembler {\tlfence} } } */ -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c index 7ac0beaa7..262e67801 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-7.c @@ -7,7 +7,7 @@ foo (void) { } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ -/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c index 777ab7c80..c1658e966 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-8.c @@ -8,7 +8,7 @@ foo (void) { } -/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86.return_thunk" } } */ -/* { dg-final { scan-assembler-not {\tlfence} } } */ +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */ +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */ /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */ diff --git a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c index 0b285caa2..d34dd4e6d 100644 --- a/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c +++ b/gcc-4.9/gcc/testsuite/gcc.target/i386/ret-thunk-9.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic"} */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */ extern void (*bar) (void); @@ -10,14 +10,15 @@ foo (void) return 0; } -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.return_thunk" } } */ -/* { dg-final { scan-assembler-not "__x86.return_thunk:" } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */ /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */ /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */ -/* { dg-final { scan-assembler "__x86.indirect_thunk:" } } */ +/* { dg-final { scan-assembler "__x86_indirect_thunk:" } } */ +/* { dg-final { scan-assembler-times {\tpause} 1 { target { ! x32 } } } } */ /* { dg-final { scan-assembler-times {\tlfence} 1 { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */ -/* { dg-final { scan-assembler "jmp\[ \t\]*__x86.indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler-times {\tpause} 2 { target { x32 } } } } */ /* { dg-final { scan-assembler-times {\tlfence} 2 { target { x32 } } } } */ -/* { dg-final { scan-assembler "call\[ \t\]*__x86.indirect_thunk\.(r|e)ax" { target { x32 } } } } */ +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */ /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */ -- cgit v1.2.3 From 2cdcfd30c27f0d836cc477f2ae9f456287fd6b1b Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Mon, 5 Feb 2018 08:43:33 -0800 Subject: [GCC] Fix #endif problem in libgcc/emutls.c Currently in emutls.c 'emutls_key_created' is defined within part of an ifdef, but is accessed outside the ifdef, which can cause issues in builds where the ifdef is not taken. This CL moves the #endif to include the new function that accesses 'emutls_key_created' so that all references to it are within the defining if-def. Bug: b/72942688 Test: Fix tested in ChromeOS. Change-Id: Ic1d6760d116b63abaef18f95e38de42af30952e4 --- gcc-4.9/libgcc/emutls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc-4.9/libgcc/emutls.c b/gcc-4.9/libgcc/emutls.c index 77550e057..cba9c3b03 100644 --- a/gcc-4.9/libgcc/emutls.c +++ b/gcc-4.9/libgcc/emutls.c @@ -89,7 +89,6 @@ emutls_init (void) abort (); emutls_key_created = 1; } -#endif __attribute__((destructor)) static void @@ -98,6 +97,7 @@ unregister_emutls_key (void) if (emutls_key_created) __gthread_key_delete (emutls_key); } +#endif static void * emutls_alloc (struct __emutls_object *obj) -- cgit v1.2.3 From e46354e85363dbd7ea85492f70af89273881709f Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Mon, 26 Feb 2018 21:33:27 -0800 Subject: Fix gcc 4.8.3 makeinfo build failure /usr/local/google/home/rprichard/android/mingw/toolchain/gcc/gcc-4.8.3/gcc/doc/gcc.texi:88: warning: @tex should only appear at the beginning of a line /usr/local/google/home/rprichard/android/mingw/toolchain/gcc/gcc-4.8.3/gcc/doc/gcc.texi:208: no matching `@end tex' /usr/local/google/home/rprichard/android/mingw/toolchain/gcc/gcc-4.8.3/gcc/doc/gcc.texi:208: no matching `@end multitable' /usr/local/google/home/rprichard/android/mingw/toolchain/gcc/gcc-4.8.3/gcc/doc/gcc.texi:208: no matching `@end titlepage' Makefile:4353: recipe for target 'doc/gcc.info' failed Even though it says "warning", the command exits unsuccessfully and fails the build. Adopt part of a patch from: https://gcc.gnu.org/ml/gcc-patches/2013-09/msg02100.html This change is already in our gcc-4.9 directory. For reference, here's the makeinfo version on my machine: $ makeinfo --version texi2any (GNU texinfo) 6.4.90 Test: ./toolchain/mingw/build.sh (in AOSP mingw branch) Change-Id: Ib740c39d127ac8a127c929465fdf89477698a5e4 --- gcc-4.8.3/gcc/doc/gcc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gcc-4.8.3/gcc/doc/gcc.texi b/gcc-4.8.3/gcc/doc/gcc.texi index 02b81cf86..84123f6b1 100644 --- a/gcc-4.8.3/gcc/doc/gcc.texi +++ b/gcc-4.8.3/gcc/doc/gcc.texi @@ -85,9 +85,9 @@ Published by: @item GNU Press @tab Website: www.gnupress.org @item a division of the -@tab General: @tex press@@gnu.org @end tex +@tab General: @email{press@@gnu.org} @item Free Software Foundation -@tab Orders: @tex sales@@gnu.org @end tex +@tab Orders: @email{sales@@gnu.org} @item 51 Franklin Street, Fifth Floor @tab Tel 617-542-5942 @item Boston, MA 02110-1301 USA -- cgit v1.2.3 From 5669c9914b411b5094532856815b2c4712be4d10 Mon Sep 17 00:00:00 2001 From: Yunlian Jiang Date: Tue, 24 Apr 2018 14:24:57 -0700 Subject: gcc: backport an upstream patch to make it work with newer glibc. Newer glibc removes 'struct' tag from ucontext_t. Because of this, gcc failed to bootstrap with newer glibc. This patch from upstream fixes that. BUG=chromium:834385 TEST=sudo emerge sys-devel/gcc passes with newer glibc installed. commit 14c2f22a1877f6b60a2f7c2f83ffb032759456a6 Author: jsm28 Date: Tue Jul 4 10:22:56 2017 +0000 Use ucontext_t not struct ucontext in linux-unwind.h files. Current glibc no longer gives the ucontext_t type the tag struct ucontext, to conform with POSIX namespace rules. This requires various linux-unwind.h files in libgcc, that were previously using struct ucontext, to be fixed to use ucontext_t instead. This is similar to the removal of the struct siginfo tag from siginfo_t some years ago. This patch changes those files to use ucontext_t instead. As the standard name that should be unconditionally safe, so this is not restricted to architectures supported by glibc, or conditioned on the glibc version. Tested compilation together with current glibc with glibc's build-many-glibcs.py. Change-Id: I433dd983b8d18c538d96486f7362b953ece3bfb8 --- gcc-4.9/libgcc/config/aarch64/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/alpha/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/bfin/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/i386/linux-unwind.h | 4 ++-- gcc-4.9/libgcc/config/m68k/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/nios2/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/pa/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/sh/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/tilepro/linux-unwind.h | 2 +- gcc-4.9/libgcc/config/xtensa/linux-unwind.h | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gcc-4.9/libgcc/config/aarch64/linux-unwind.h b/gcc-4.9/libgcc/config/aarch64/linux-unwind.h index 6b5b3cd1d..d13dc3482 100644 --- a/gcc-4.9/libgcc/config/aarch64/linux-unwind.h +++ b/gcc-4.9/libgcc/config/aarch64/linux-unwind.h @@ -52,7 +52,7 @@ aarch64_fallback_frame_state (struct _Unwind_Context *context, struct rt_sigframe { siginfo_t info; - struct ucontext uc; + ucontext_t uc; }; struct rt_sigframe *rt_; diff --git a/gcc-4.9/libgcc/config/alpha/linux-unwind.h b/gcc-4.9/libgcc/config/alpha/linux-unwind.h index b5bfd1c91..166d3d2cf 100644 --- a/gcc-4.9/libgcc/config/alpha/linux-unwind.h +++ b/gcc-4.9/libgcc/config/alpha/linux-unwind.h @@ -51,7 +51,7 @@ alpha_fallback_frame_state (struct _Unwind_Context *context, { struct rt_sigframe { siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *rt_ = context->cfa; sc = &rt_->uc.uc_mcontext; } diff --git a/gcc-4.9/libgcc/config/bfin/linux-unwind.h b/gcc-4.9/libgcc/config/bfin/linux-unwind.h index dc58f0a81..8b94568bb 100644 --- a/gcc-4.9/libgcc/config/bfin/linux-unwind.h +++ b/gcc-4.9/libgcc/config/bfin/linux-unwind.h @@ -52,7 +52,7 @@ bfin_fallback_frame_state (struct _Unwind_Context *context, void *puc; char retcode[8]; siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. diff --git a/gcc-4.9/libgcc/config/i386/linux-unwind.h b/gcc-4.9/libgcc/config/i386/linux-unwind.h index 7986928cf..a9d621c31 100644 --- a/gcc-4.9/libgcc/config/i386/linux-unwind.h +++ b/gcc-4.9/libgcc/config/i386/linux-unwind.h @@ -58,7 +58,7 @@ x86_64_fallback_frame_state (struct _Unwind_Context *context, if (*(unsigned char *)(pc+0) == 0x48 && *(unsigned long long *)(pc+1) == RT_SIGRETURN_SYSCALL) { - struct ucontext *uc_ = context->cfa; + ucontext_t *uc_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. The aliasing warning is correct, but should not be a problem because it does not alias anything. */ @@ -138,7 +138,7 @@ x86_fallback_frame_state (struct _Unwind_Context *context, siginfo_t *pinfo; void *puc; siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. The aliasing warning is correct, but should not be a problem diff --git a/gcc-4.9/libgcc/config/m68k/linux-unwind.h b/gcc-4.9/libgcc/config/m68k/linux-unwind.h index 1ba2a0c43..d67767e33 100644 --- a/gcc-4.9/libgcc/config/m68k/linux-unwind.h +++ b/gcc-4.9/libgcc/config/m68k/linux-unwind.h @@ -33,7 +33,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* is unfortunately broken right now. */ struct uw_ucontext { unsigned long uc_flags; - struct ucontext *uc_link; + ucontext_t *uc_link; stack_t uc_stack; mcontext_t uc_mcontext; unsigned long uc_filler[80]; diff --git a/gcc-4.9/libgcc/config/nios2/linux-unwind.h b/gcc-4.9/libgcc/config/nios2/linux-unwind.h index ba4bd801d..897886852 100644 --- a/gcc-4.9/libgcc/config/nios2/linux-unwind.h +++ b/gcc-4.9/libgcc/config/nios2/linux-unwind.h @@ -38,7 +38,7 @@ struct nios2_mcontext { struct nios2_ucontext { unsigned long uc_flags; - struct ucontext *uc_link; + ucontext_t *uc_link; stack_t uc_stack; struct nios2_mcontext uc_mcontext; sigset_t uc_sigmask; /* mask last for extensibility */ diff --git a/gcc-4.9/libgcc/config/pa/linux-unwind.h b/gcc-4.9/libgcc/config/pa/linux-unwind.h index 4a3cfffd1..d2ac437a4 100644 --- a/gcc-4.9/libgcc/config/pa/linux-unwind.h +++ b/gcc-4.9/libgcc/config/pa/linux-unwind.h @@ -80,7 +80,7 @@ pa32_fallback_frame_state (struct _Unwind_Context *context, struct sigcontext *sc; struct rt_sigframe { siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *frame; /* rt_sigreturn trampoline: diff --git a/gcc-4.9/libgcc/config/sh/linux-unwind.h b/gcc-4.9/libgcc/config/sh/linux-unwind.h index 4875706d4..671bde715 100644 --- a/gcc-4.9/libgcc/config/sh/linux-unwind.h +++ b/gcc-4.9/libgcc/config/sh/linux-unwind.h @@ -180,7 +180,7 @@ sh_fallback_frame_state (struct _Unwind_Context *context, { struct rt_sigframe { siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. The aliasing warning is correct, but should not be a problem diff --git a/gcc-4.9/libgcc/config/tilepro/linux-unwind.h b/gcc-4.9/libgcc/config/tilepro/linux-unwind.h index 27481cfcd..c24d58c94 100644 --- a/gcc-4.9/libgcc/config/tilepro/linux-unwind.h +++ b/gcc-4.9/libgcc/config/tilepro/linux-unwind.h @@ -61,7 +61,7 @@ tile_fallback_frame_state (struct _Unwind_Context *context, struct rt_sigframe { unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *rt_; /* Return if this is not a signal handler. */ diff --git a/gcc-4.9/libgcc/config/xtensa/linux-unwind.h b/gcc-4.9/libgcc/config/xtensa/linux-unwind.h index 6832d0b48..cb15b4c71 100644 --- a/gcc-4.9/libgcc/config/xtensa/linux-unwind.h +++ b/gcc-4.9/libgcc/config/xtensa/linux-unwind.h @@ -63,7 +63,7 @@ xtensa_fallback_frame_state (struct _Unwind_Context *context, struct rt_sigframe { siginfo_t info; - struct ucontext uc; + ucontext_t uc; } *rt_; /* movi a2, __NR_rt_sigreturn; syscall */ -- cgit v1.2.3 From 71959ce8f47f676a26bb21da7117101d9d73867e Mon Sep 17 00:00:00 2001 From: Yunlian Jiang Date: Tue, 24 Apr 2018 22:15:37 -0700 Subject: gcc: backport patch to support vrnd<*>_f64 aarch64 intrinsics. This backports upstream patch to add support of vrdn<*>_f64 intrinisics for aarch64. This is needed because glibc 2.27 uses some of them. Author: mshawcroft Date: Tue Apr 22 08:39:48 2014 +0000 [AArch64] vrnd<*>_f64 patch This patch adds vrnd<*>_f64 aarch64 intrinsics. A testcase for those intrinsics is added. Run a complete LE and BE regression run with no regressions. BUG=chromium:834385 TEST=./setup_board --board kevin --nousepkg cross-aarch64-cros-linux-gnu-glibc builds for glibc 2.27 Change-Id: Iaf9508a433e35d3304e44ac4b6c93071ff6c5ec0 --- gcc-4.9/gcc/config/aarch64/aarch64-builtins.c | 2 + .../gcc/config/aarch64/aarch64-simd-builtins.def | 2 +- gcc-4.9/gcc/config/aarch64/aarch64-simd.md | 2 +- gcc-4.9/gcc/config/aarch64/aarch64.md | 2 +- gcc-4.9/gcc/config/aarch64/arm_neon.h | 43 ++++++++++++++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/gcc-4.9/gcc/config/aarch64/aarch64-builtins.c b/gcc-4.9/gcc/config/aarch64/aarch64-builtins.c index a5af874bf..eea05cdb2 100644 --- a/gcc-4.9/gcc/config/aarch64/aarch64-builtins.c +++ b/gcc-4.9/gcc/config/aarch64/aarch64-builtins.c @@ -311,6 +311,8 @@ aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS] VAR7 (T, N, MAP, v8qi, v16qi, v4hi, v8hi, v2si, v4si, v2di) #define BUILTIN_VDQF(T, N, MAP) \ VAR3 (T, N, MAP, v2sf, v4sf, v2df) +#define BUILTIN_VDQF_DF(T, N, MAP) \ + VAR4 (T, N, MAP, v2sf, v4sf, v2df, df) #define BUILTIN_VDQH(T, N, MAP) \ VAR2 (T, N, MAP, v4hi, v8hi) #define BUILTIN_VDQHS(T, N, MAP) \ diff --git a/gcc-4.9/gcc/config/aarch64/aarch64-simd-builtins.def b/gcc-4.9/gcc/config/aarch64/aarch64-simd-builtins.def index c9b7570e5..c5e3b3e9f 100644 --- a/gcc-4.9/gcc/config/aarch64/aarch64-simd-builtins.def +++ b/gcc-4.9/gcc/config/aarch64/aarch64-simd-builtins.def @@ -265,7 +265,7 @@ BUILTIN_VDQF (UNOP, nearbyint, 2) BUILTIN_VDQF (UNOP, rint, 2) BUILTIN_VDQF (UNOP, round, 2) - BUILTIN_VDQF (UNOP, frintn, 2) + BUILTIN_VDQF_DF (UNOP, frintn, 2) /* Implemented by l2. */ VAR1 (UNOP, lbtruncv2sf, 2, v2si) diff --git a/gcc-4.9/gcc/config/aarch64/aarch64-simd.md b/gcc-4.9/gcc/config/aarch64/aarch64-simd.md index 7626ed31f..9ccf484c7 100644 --- a/gcc-4.9/gcc/config/aarch64/aarch64-simd.md +++ b/gcc-4.9/gcc/config/aarch64/aarch64-simd.md @@ -1576,7 +1576,7 @@ ) ;; Vector versions of the floating-point frint patterns. -;; Expands to btrunc, ceil, floor, nearbyint, rint, round. +;; Expands to btrunc, ceil, floor, nearbyint, rint, round, frintn. (define_insn "2" [(set (match_operand:VDQF 0 "register_operand" "=w") (unspec:VDQF [(match_operand:VDQF 1 "register_operand" "w")] diff --git a/gcc-4.9/gcc/config/aarch64/aarch64.md b/gcc-4.9/gcc/config/aarch64/aarch64.md index fe68bfea1..cab3dfc0f 100644 --- a/gcc-4.9/gcc/config/aarch64/aarch64.md +++ b/gcc-4.9/gcc/config/aarch64/aarch64.md @@ -3229,7 +3229,7 @@ ;; ------------------------------------------------------------------- ;; frint floating-point round to integral standard patterns. -;; Expands to btrunc, ceil, floor, nearbyint, rint, round. +;; Expands to btrunc, ceil, floor, nearbyint, rint, round, frintn. (define_insn "2" [(set (match_operand:GPF 0 "register_operand" "=w") diff --git a/gcc-4.9/gcc/config/aarch64/arm_neon.h b/gcc-4.9/gcc/config/aarch64/arm_neon.h index ae0ae9c1b..03addc955 100644 --- a/gcc-4.9/gcc/config/aarch64/arm_neon.h +++ b/gcc-4.9/gcc/config/aarch64/arm_neon.h @@ -22469,6 +22469,12 @@ vrnd_f32 (float32x2_t __a) return __builtin_aarch64_btruncv2sf (__a); } +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrnd_f64 (float64x1_t __a) +{ + return vset_lane_f64 (__builtin_trunc (vget_lane_f64 (__a, 0)), __a, 0); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndq_f32 (float32x4_t __a) { @@ -22489,6 +22495,12 @@ vrnda_f32 (float32x2_t __a) return __builtin_aarch64_roundv2sf (__a); } +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrnda_f64 (float64x1_t __a) +{ + return vset_lane_f64 (__builtin_round (vget_lane_f64 (__a, 0)), __a, 0); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndaq_f32 (float32x4_t __a) { @@ -22509,6 +22521,12 @@ vrndi_f32 (float32x2_t __a) return __builtin_aarch64_nearbyintv2sf (__a); } +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrndi_f64 (float64x1_t __a) +{ + return vset_lane_f64 (__builtin_nearbyint (vget_lane_f64 (__a, 0)), __a, 0); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndiq_f32 (float32x4_t __a) { @@ -22529,6 +22547,12 @@ vrndm_f32 (float32x2_t __a) return __builtin_aarch64_floorv2sf (__a); } +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrndm_f64 (float64x1_t __a) +{ + return vset_lane_f64 (__builtin_floor (vget_lane_f64 (__a, 0)), __a, 0); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndmq_f32 (float32x4_t __a) { @@ -22548,6 +22572,13 @@ vrndn_f32 (float32x2_t __a) { return __builtin_aarch64_frintnv2sf (__a); } + +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrndn_f64 (float64x1_t __a) +{ + return __builtin_aarch64_frintndf (__a); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndnq_f32 (float32x4_t __a) { @@ -22568,6 +22599,12 @@ vrndp_f32 (float32x2_t __a) return __builtin_aarch64_ceilv2sf (__a); } +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrndp_f64 (float64x1_t __a) +{ + return vset_lane_f64 (__builtin_ceil (vget_lane_f64 (__a, 0)), __a, 0); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndpq_f32 (float32x4_t __a) { @@ -22588,6 +22625,12 @@ vrndx_f32 (float32x2_t __a) return __builtin_aarch64_rintv2sf (__a); } +__extension__ static __inline float64x1_t __attribute__ ((__always_inline__)) +vrndx_f64 (float64x1_t __a) +{ + return vset_lane_f64 (__builtin_rint (vget_lane_f64 (__a, 0)), __a, 0); +} + __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vrndxq_f32 (float32x4_t __a) { -- cgit v1.2.3 From 81788f3d99d2c5952fa9a6d673e8d6a53b76d511 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 9 May 2018 15:37:24 -0700 Subject: Delay emutls deallocation for one round With Android/Bionic, delay deallocation to round 2 of 4. It must run after C++ thread_local destructors have been called, but before the final 2 rounds, because emutls calls free, and jemalloc then needs another 2 rounds to free its thread-specific data. Bug: https://github.com/android-ndk/ndk/issues/687 Bug: b/78022094 Test: manual Test: ./run_tests.py --rebuild --filter emutls-dealloc Change-Id: I01bd634d97b7d22161b5cc8ca71b3cb94064a03e --- gcc-4.9/libgcc/emutls.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/gcc-4.9/libgcc/emutls.c b/gcc-4.9/libgcc/emutls.c index cba9c3b03..525db2839 100644 --- a/gcc-4.9/libgcc/emutls.c +++ b/gcc-4.9/libgcc/emutls.c @@ -30,6 +30,22 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "libgcc_tm.h" #include "gthr.h" +#ifdef __BIONIC__ +/* There are 4 pthread key cleanup rounds on Bionic. Delay emutls deallocation + to round 2. We need to delay deallocation because: + - Android versions older than M lack __cxa_thread_atexit_impl, so apps + use a pthread key destructor to call C++ destructors. + - Apps might use __thread/thread_local variables in pthread destructors. + We can't wait until the final two rounds, because jemalloc needs two rounds + after the final malloc/free call to free its thread-specific data (see + https://reviews.llvm.org/D46978#1107507). Bugs: + - https://github.com/android-ndk/ndk/issues/687. + - http://b/16847284, http://b/78022094. */ +#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS 1 +#else +#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS 0 +#endif + typedef unsigned int word __attribute__((mode(word))); typedef unsigned int pointer __attribute__((mode(pointer))); @@ -46,6 +62,7 @@ struct __emutls_object struct __emutls_array { + pointer skip_destructor_rounds; pointer size; void **data[]; }; @@ -67,16 +84,30 @@ static void emutls_destroy (void *ptr) { struct __emutls_array *arr = ptr; - pointer size = arr->size; - pointer i; - for (i = 0; i < size; ++i) + /* emutls is deallocated using a pthread key destructor. These destructors + are called in several rounds to accommodate destructor functions that + (re)initialize key values with pthread_setspecific. Delay the emutls + deallocation to accommodate other end-of-thread cleanup tasks like + calling thread_local destructors. */ + if (arr->skip_destructor_rounds > 0) { - if (arr->data[i]) - free (arr->data[i][-1]); + arr->skip_destructor_rounds--; + __gthread_setspecific (emutls_key, (void *) arr); } + else + { + pointer size = arr->size; + pointer i; - free (ptr); + for (i = 0; i < size; ++i) + { + if (arr->data[i]) + free (arr->data[i][-1]); + } + + free (ptr); + } } static void @@ -163,12 +194,14 @@ __emutls_get_address (struct __emutls_object *obj) } struct __emutls_array *arr = __gthread_getspecific (emutls_key); + const pointer hdr_size = sizeof (struct __emutls_array) / sizeof (void *); if (__builtin_expect (arr == NULL, 0)) { pointer size = offset + 32; - arr = calloc (size + 1, sizeof (void *)); + arr = calloc (size + hdr_size, sizeof (void *)); if (arr == NULL) abort (); + arr->skip_destructor_rounds = EMUTLS_SKIP_DESTRUCTOR_ROUNDS; arr->size = size; __gthread_setspecific (emutls_key, (void *) arr); } @@ -178,7 +211,7 @@ __emutls_get_address (struct __emutls_object *obj) pointer size = orig_size * 2; if (offset > size) size = offset + 32; - arr = realloc (arr, (size + 1) * sizeof (void *)); + arr = realloc (arr, (size + hdr_size) * sizeof (void *)); if (arr == NULL) abort (); arr->size = size; -- cgit v1.2.3 From 89b2029895df0a3f3587eeba0a519091c3f7a1b5 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Mon, 4 Jun 2018 14:35:57 -0700 Subject: Add __emutls_unregister_key function Replace the existing __attribute__((destructor)) function, unregister_emutls_key, with a function that something else must call explicitly. We don't want the pthread key deleted at program exit, because it's unnecessary and because it may delete the key before other tls-using cleanup code runs. Exposing __emutls_unregister_key allows limiting the cleanup to dlclose (e.g. by calling it only from crtbegin_so.c). Reset emutls_key_created so multiple calls to __emutls_unregister_key are safe. Bug: b/80453944 Test: manual Change-Id: I82d13614ae8042d0501fd2ca64f0ef6189669905 --- gcc-4.9/libgcc/emutls.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gcc-4.9/libgcc/emutls.c b/gcc-4.9/libgcc/emutls.c index 525db2839..93c3c0788 100644 --- a/gcc-4.9/libgcc/emutls.c +++ b/gcc-4.9/libgcc/emutls.c @@ -121,12 +121,15 @@ emutls_init (void) emutls_key_created = 1; } -__attribute__((destructor)) -static void -unregister_emutls_key (void) +__attribute__((visibility("hidden"))) +void +__emutls_unregister_key (void) { if (emutls_key_created) - __gthread_key_delete (emutls_key); + { + emutls_key_created = 0; + __gthread_key_delete (emutls_key); + } } #endif -- cgit v1.2.3 From 4089f56e6c7438eb98cb86c249cf0c01e22219c5 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 27 Jun 2018 17:21:50 -0700 Subject: libgcc: work around old Bionic loader bug dl_iterate_phdr returns a 0 load_base for a PIE executable when it should return the address where the executable was loaded (e.g. the load base or load bias). Recalculate the load base when it is zero. This recalculation should work on any ELF file with a PT_PHDR segment -- it will calculate 0 for a non-PIE executable. The load base is added to an ELF virtual address to produce a run-time address. Recalculate it by subtracting the PT_PHDR's virtual address from its run-time address. Bug: https://github.com/android-ndk/ndk/issues/505 Test: manual Test: run NDK tests (./checkbuild.py && ./run_tests.py) Change-Id: I7de46c07a8b04e794b59f07b4d554238cfd6d5d9 --- gcc-4.9/libgcc/unwind-dw2-fde-dip.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/gcc-4.9/libgcc/unwind-dw2-fde-dip.c b/gcc-4.9/libgcc/unwind-dw2-fde-dip.c index d6c052165..db98b5961 100644 --- a/gcc-4.9/libgcc/unwind-dw2-fde-dip.c +++ b/gcc-4.9/libgcc/unwind-dw2-fde-dip.c @@ -183,6 +183,30 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) p_eh_frame_hdr = NULL; p_dynamic = NULL; +#if defined(__BIONIC__) && defined(__i386__) + if (load_base == 0) + { + /* A load_base of 0 normally indicates a non-PIE executable. There was a + bug in Android's dynamic loader prior to API 18, though, where + dl_iterate_phdr incorrectly passed a load_base of 0 for a PIE + executable. Work around the bug by recalculating load_base using + the PT_PHDR segment. This code path isn't needed for arm32, because + arm32 didn't have dl_iterate_phdr until API 21. + https://github.com/android-ndk/ndk/issues/505. */ + size_t i; + for (i = 0; i < info->dlpi_phnum; ++i) + { + const ElfW(Phdr) *fix_phdr = &info->dlpi_phdr[i]; + if (fix_phdr->p_type == PT_PHDR) + { + load_base = (_Unwind_Ptr) info->dlpi_phdr - + (_Unwind_Ptr) fix_phdr->p_vaddr; + break; + } + } + } +#endif + struct frame_hdr_cache_element *prev_cache_entry = NULL, *last_cache_entry = NULL; -- cgit v1.2.3