special_function_p has /* ECF_RETURNS_TWICE is safe even for -ffreestanding. */ if (! strcmp (tname, "setjmp") || ! strcmp (tname, "sigsetjmp") || ! strcmp (name, "savectx") || ! strcmp (name, "vfork") || ! strcmp (name, "getcontext")) ^^^^^^^^^^^^ getcontext never returns twice. Instead swapcontext may return twice. flags |= ECF_RETURNS_TWICE;
getcontext does return twice. Swapcontext only returns once. If you get the current context, and then latter on swap the context, you just returned to the place where getcontext is called. you do setcontext (or swapcontext again), you get the swapcontext context. That is it only ever returns once.
http://pubs.opengroup.org/onlinepubs/007904975/functions/getcontext.html If the ucp argument was created with getcontext(), program execution continues as if the corresponding call of getcontext() had just returned. That means it does return twice.
Technically, swapcontext only returns once, but not when it is called. In that sense, it returns twice.
(In reply to H.J. Lu from comment #3) > Technically, swapcontext only returns once, but not when it is called. > In that sense, it returns twice. Huh? For the purpose of ECF_RETURNS_TWICE, swapcontext does not need to be marked as such. ECF_RETURNS_TWICE is only needed for CFG reasons.
[hjl@gnu-skx-1 ucontext-1]$ cat y.i struct ucontext; typedef struct ucontext ucontext_t; extern int swapcontext (ucontext_t *__restrict __oucp, const ucontext_t *__restrict __ucp); extern int res; void foo (ucontext_t *oucp, ucontext_t *ucp) { res = swapcontext (oucp, ucp); } [hjl@gnu-skx-1 ucontext-1]$ make y.s /export/build/gnu/gcc-8-test/build-x86_64-linux/gcc/xgcc -B/export/build/gnu/gcc-8-test/build-x86_64-linux/gcc/ -O2 -fcf-protection -S y.i [hjl@gnu-skx-1 ucontext-1]$ cat y.s .file "y.i" .text .p2align 4,,15 .globl foo .type foo, @function foo: .LFB0: .cfi_startproc endbr64 subq $8, %rsp .cfi_def_cfa_offset 16 call swapcontext <<<<<<< This may return via indirect branch. <<<<<<<<<<< Need ENDBR here. movl %eax, res(%rip) addq $8, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE0: .size foo, .-foo .ident "GCC: (GNU) 8.1.1 20180502" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4: [hjl@gnu-skx-1 ucontext-1]$
It has been fixed in glibc.
We want to generate ENDBR after swapcontext. swapcontext didn't return the first time. It was just kind of "suspended". Mark it return twice will unnecessarily disable compiler optimization.
Author: hjl Date: Wed Jul 4 03:01:33 2018 New Revision: 262370 URL: https://gcc.gnu.org/viewcvs?rev=262370&root=gcc&view=rev Log: i386: Add indirect_return function attribute On x86, swapcontext may return via indirect branch when shadow stack is enabled. To support code instrumentation of control-flow transfers with -fcf-protection, add indirect_return function attribute to inform compiler that a function may return via indirect branch. Note: Unlike setjmp, swapcontext only returns once. Mark it return twice will unnecessarily disable compiler optimization as shown in the testcase here. gcc/ PR target/85620 * config/i386/i386.c (rest_of_insert_endbranch): Also generate ENDBRANCH for non-tail call which may return via indirect branch. * doc/extend.texi: Document indirect_return attribute. gcc/testsuite/ PR target/85620 * gcc.target/i386/pr85620-1.c: New test. * gcc.target/i386/pr85620-2.c: Likewise. * gcc.target/i386/pr85620-3.c: Likewise. * gcc.target/i386/pr85620-4.c: Likewise. Added: trunk/gcc/testsuite/gcc.target/i386/pr85620-1.c trunk/gcc/testsuite/gcc.target/i386/pr85620-2.c trunk/gcc/testsuite/gcc.target/i386/pr85620-3.c trunk/gcc/testsuite/gcc.target/i386/pr85620-4.c Modified: trunk/gcc/ChangeLog trunk/gcc/config/i386/i386.c trunk/gcc/doc/extend.texi trunk/gcc/testsuite/ChangeLog
Fixed for GCC 9.
ISTM that if you have to insert an endbr over indirect_return, a call should only be eligible for sibcall if the caller is also marked with indirect_return, otherwise the callee will indirectly return directly to an upstack caller that may not have an endbr after the call, no?
Created attachment 53299 [details] A patch
The master branch has been updated by H.J. Lu <hjl@gcc.gnu.org>: https://gcc.gnu.org/g:2582080f19e8fe9c1204dfb6fecf744311f00777 commit r13-1717-g2582080f19e8fe9c1204dfb6fecf744311f00777 Author: H.J. Lu <hjl.tools@gmail.com> Date: Thu Jul 14 10:31:21 2022 -0700 x86: Disable sibcall if indirect_return attribute doesn't match When shadow stack is enabled, function with indirect_return attribute may return via indirect jump. In this case, we need to disable sibcall if caller doesn't have indirect_return attribute and indirect branch tracking is enabled since compiler won't generate ENDBR when calling the caller. gcc/ PR target/85620 * config/i386/i386.cc (ix86_function_ok_for_sibcall): Return false if callee has indirect_return attribute and caller doesn't. gcc/testsuite/ PR target/85620 * gcc.target/i386/pr85620-2.c: Updated. * gcc.target/i386/pr85620-5.c: New test. * gcc.target/i386/pr85620-6.c: Likewise. * gcc.target/i386/pr85620-7.c: Likewise.
.