x86: Add -mindirect-branch=
authorH.J. Lu <hongjiu.lu@intel.com>
Sun, 14 Jan 2018 14:35:19 +0000 (14:35 +0000)
committerH.J. Lu <hjl@gcc.gnu.org>
Sun, 14 Jan 2018 14:35:19 +0000 (06:35 -0800)
commitda99fd4a3ca06b43b08ba8d96dab84e83ac90aa7
tree8fdb3330633e4c8d2e0399ebd851bee095f1ae05
parent3f05a4f0727bac6f4456fbbecdc1315cc8bd59cf
x86: Add -mindirect-branch=

Add -mindirect-branch= option to convert indirect call and jump to call
and return thunks.  The default is 'keep', which keeps indirect call and
jump unmodified.  'thunk' converts indirect call and jump to call and
return thunk.  'thunk-inline' converts indirect call and jump to inlined
call and return thunk.  '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 indirect_branch.

2 kinds of thunks are geneated.  Memory thunk where the function address
is at the top of the stack:

__x86_indirect_thunk:
call L2
L1:
pause
lfence
jmp L1
L2:
lea 8(%rsp), %rsp|lea 4(%esp), %esp
ret

Indirect jmp via memory, "jmp mem", is converted to

push memory
jmp __x86_indirect_thunk

Indirect call via memory, "call mem", is converted to

jmp L2
L1:
push [mem]
jmp __x86_indirect_thunk
L2:
call L1

Register thunk where the function address is in a register, reg:

__x86_indirect_thunk_reg:
call L2
L1:
pause
lfence
jmp L1
L2:
movq %reg, (%rsp)|movl    %reg, (%esp)
ret

where reg is one of (r|e)ax, (r|e)dx, (r|e)cx, (r|e)bx, (r|e)si, (r|e)di,
(r|e)bp, r8, r9, r10, r11, r12, r13, r14 and r15.

Indirect jmp via register, "jmp reg", is converted to

jmp __x86_indirect_thunk_reg

Indirect call via register, "call reg", is converted to

call __x86_indirect_thunk_reg

gcc/

* config/i386/i386-opts.h (indirect_branch): New.
* config/i386/i386-protos.h (ix86_output_indirect_jmp): Likewise.
* config/i386/i386.c (ix86_using_red_zone): Disallow red-zone
with local indirect jump when converting indirect call and jump.
(ix86_set_indirect_branch_type): New.
(ix86_set_current_function): Call ix86_set_indirect_branch_type.
(indirectlabelno): New.
(indirect_thunk_needed): Likewise.
(indirect_thunk_bnd_needed): Likewise.
(indirect_thunks_used): Likewise.
(indirect_thunks_bnd_used): Likewise.
(INDIRECT_LABEL): Likewise.
(indirect_thunk_name): Likewise.
(output_indirect_thunk): Likewise.
(output_indirect_thunk_function): Likewise.
(ix86_output_indirect_branch): Likewise.
(ix86_output_indirect_jmp): Likewise.
(ix86_code_end): Call output_indirect_thunk_function if needed.
(ix86_output_call_insn): Call ix86_output_indirect_branch if
needed.
(ix86_handle_fndecl_attribute): Handle indirect_branch.
(ix86_attribute_table): Add indirect_branch.
* config/i386/i386.h (machine_function): Add indirect_branch_type
and has_local_indirect_jump.
* config/i386/i386.md (indirect_jump): Set has_local_indirect_jump
to true.
(tablejump): Likewise.
(*indirect_jump): Use ix86_output_indirect_jmp.
(*tablejump_1): Likewise.
(simple_return_indirect_internal): Likewise.
* config/i386/i386.opt (mindirect-branch=): New option.
(indirect_branch): New.
(keep): Likewise.
(thunk): Likewise.
(thunk-inline): Likewise.
(thunk-extern): Likewise.
* doc/extend.texi: Document indirect_branch function attribute.
* doc/invoke.texi: Document -mindirect-branch= option.

gcc/testsuite/

* gcc.target/i386/indirect-thunk-1.c: New test.
* gcc.target/i386/indirect-thunk-2.c: Likewise.
* gcc.target/i386/indirect-thunk-3.c: Likewise.
* gcc.target/i386/indirect-thunk-4.c: Likewise.
* gcc.target/i386/indirect-thunk-5.c: Likewise.
* gcc.target/i386/indirect-thunk-6.c: Likewise.
* gcc.target/i386/indirect-thunk-7.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
* gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
* gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
* gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
* gcc.target/i386/indirect-thunk-inline-7.c: Likewise.

From-SVN: r256660
43 files changed:
gcc/ChangeLog
gcc/config/i386/i386-opts.h
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/config/i386/i386.opt
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/indirect-thunk-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c [new file with mode: 0644]