Hello! attribute ((naked)) generates function body without function frame, and as shown in PR 25967 [1], users are looking for this feature also for x86 targets. Recently, Daniel introduced a testcase that would benefit from this attribute.
Attached patch also adds a trap instruction (ud2) at the end of the naked function, where epilogue would be. If there is a path through the function that would reach epilogue, trap insn triggers, as shown in added naked-3.c test. As documented (many times) in the documentation, the only correct usage is with classic "asm" statement. The documentation is perhaps too pessimistic; with some caution, quite complex c code can be mixed with asm prologue and epilogue. YMMV, the warning is there. 2017-07-30 Uros Bizjak <ubiz...@gmail.com> PR target/25967 * config/i386/i386.c (ix86_function_naked): New function. (ix86_can_use_return_insn_p): Return false for naked functions. (ix86_expand_prologue): Skip prologue for naked functions. (ix86_expand_epilogue): Skip epilogue for naked functions and emit trap instruction. (ix86_warn_func_return): New function. (ix86_attribute_table): Add "naked" attribute specification. (TARGET_WARN_FUNC_RETURN): Define. * doc/extend.texi (x86 Function Attributes) <naked>: Document it. testsuite/ChangeLog: 2017-07-30 Uros Bizjak <ubiz...@gmail.com> PR target/25967 * gcc.target/i386/naked-1.c: New test. * gcc.target/i386/naked-2.c: Ditto. * gcc.target/i386/naked-3.c: Ditto. * gcc.target/x86_64/abi/ms-sysv/ms-sysv.c: Remove do_test_body0 stub function, use attribute "naked" instead. * gcc.dg/pr44290-1.c: Use naked_functions effective target. * gcc.dg/pr44290-2.c: Ditto. Patch was bootstrapped and regression tested on x86_64-linux-gnu {,-m32}. [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25967 Uros.
Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 250721) +++ config/i386/i386.c (working copy) @@ -8748,6 +8748,15 @@ ix86_function_ms_hook_prologue (const_tree fn) return false; } +static bool +ix86_function_naked (const_tree fn) +{ + if (fn && lookup_attribute ("naked", DECL_ATTRIBUTES (fn))) + return true; + + return false; +} + /* Write the extra assembler code needed to declare a function properly. */ void @@ -12249,6 +12258,9 @@ ix86_can_use_return_insn_p (void) { struct ix86_frame frame; + if (ix86_function_naked (current_function_decl)) + return false; + /* Don't use `ret' instruction in interrupt handler. */ if (! reload_completed || frame_pointer_needed @@ -14327,6 +14339,9 @@ ix86_expand_prologue (void) bool sse_registers_saved; rtx static_chain = NULL_RTX; + if (ix86_function_naked (current_function_decl)) + return; + ix86_finalize_stack_realign_flags (); /* DRAP should not coexist with stack_realign_fp */ @@ -15184,6 +15199,13 @@ ix86_expand_epilogue (int style) bool using_drap; bool restore_stub_is_tail = false; + if (ix86_function_naked (current_function_decl)) + { + /* The program should not reach this point. */ + emit_insn (gen_trap ()); + return; + } + ix86_finalize_stack_realign_flags (); frame = m->frame; @@ -31652,6 +31674,14 @@ ix86_trampoline_init (rtx m_tramp, tree fndecl, rt LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode); #endif } + +static bool +ix86_warn_func_return (tree decl) +{ + /* Naked functions are implemented entirely in assembly, including the + return sequence, so suppress warnings about this. */ + return !ix86_function_naked (decl); +} /* The following file contains several enumerations and data structures built from the definitions in i386-builtin-types.def. */ @@ -46486,6 +46516,8 @@ static const struct attribute_spec ix86_attribute_ ix86_handle_interrupt_attribute, false }, { "no_caller_saved_registers", 0, 0, false, true, true, ix86_handle_no_caller_saved_registers_attribute, false }, + { "naked", 0, 0, true, false, false, + ix86_handle_fndecl_attribute, false }, /* End element. */ { NULL, 0, 0, false, false, false, NULL, false } @@ -52722,6 +52754,9 @@ ix86_run_selftests (void) #undef TARGET_RETURN_POPS_ARGS #define TARGET_RETURN_POPS_ARGS ix86_return_pops_args +#undef TARGET_WARN_FUNC_RETURN +#define TARGET_WARN_FUNC_RETURN ix86_warn_func_return + #undef TARGET_LEGITIMATE_COMBINED_INSN #define TARGET_LEGITIMATE_COMBINED_INSN ix86_legitimate_combined_insn Index: doc/extend.texi =================================================================== --- doc/extend.texi (revision 250721) +++ doc/extend.texi (working copy) @@ -5370,6 +5370,17 @@ this function attribute to make GCC generate the ` prologue used in Win32 API functions in Microsoft Windows XP Service Pack 2 and newer. +@item naked +@cindex @code{naked} function attribute, x86 +This attribute allows the compiler to construct the +requisite function declaration, while allowing the body of the +function to be assembly code. The specified function will not have +prologue/epilogue sequences generated by the compiler. Only basic +@code{asm} statements can safely be included in naked functions +(@pxref{Basic Asm}). While using extended @code{asm} or a mixture of +basic @code{asm} and C code may appear to work, they cannot be +depended upon to work reliably and are not supported. + @item regparm (@var{number}) @cindex @code{regparm} function attribute, x86 @cindex functions that are passed arguments in registers on x86-32 Index: testsuite/gcc.dg/pr44290-1.c =================================================================== --- testsuite/gcc.dg/pr44290-1.c (revision 250721) +++ testsuite/gcc.dg/pr44290-1.c (working copy) @@ -1,4 +1,5 @@ -/* { dg-do compile { target arm*-*-* avr-*-* mcore-*-* rx-*-* spu-*-* } } */ +/* { dg-do compile } */ +/* { dg-require-effective-target naked_functions } */ /* { dg-options "-O2 -fdump-tree-optimized" } */ static void __attribute__((naked)) Index: testsuite/gcc.dg/pr44290-2.c =================================================================== --- testsuite/gcc.dg/pr44290-2.c (revision 250721) +++ testsuite/gcc.dg/pr44290-2.c (working copy) @@ -1,4 +1,5 @@ -/* { dg-do compile { target arm*-*-* avr-*-* mcore-*-* rx-*-* spu-*-* } } */ +/* { dg-do compile } */ +/* { dg-require-effective-target naked_functions } */ /* { dg-options "-O2 -fdump-tree-optimized" } */ static unsigned long __attribute__((naked)) Index: testsuite/gcc.target/i386/naked-1.c =================================================================== --- testsuite/gcc.target/i386/naked-1.c (nonexistent) +++ testsuite/gcc.target/i386/naked-1.c (working copy) @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +/* Verify that __attribute__((naked)) produces a naked function + that does not use ret to return but traps at the end. */ +void +__attribute__((naked)) +foo (void) +{ + __asm__ ("# naked"); +} +/* { dg-final { scan-assembler "# naked" } } */ +/* { dg-final { scan-assembler "ud2" } } */ +/* { dg-final { scan-assembler-not "ret" } } */ Index: testsuite/gcc.target/i386/naked-2.c =================================================================== --- testsuite/gcc.target/i386/naked-2.c (nonexistent) +++ testsuite/gcc.target/i386/naked-2.c (working copy) @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +/* Verify that __attribute__((naked)) produces a naked function + that does not construct a frame. */ +void +__attribute__((naked)) +foo (void) +{ + __asm__ ("# naked"); +} +/* { dg-final { scan-assembler "# naked" } } */ +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ Index: testsuite/gcc.target/i386/naked-3.c =================================================================== --- testsuite/gcc.target/i386/naked-3.c (nonexistent) +++ testsuite/gcc.target/i386/naked-3.c (working copy) @@ -0,0 +1,39 @@ +/* { dg-do run { target *-*-linux* *-*-gnu* } } */ +/* { dg-options "-O2" } */ + +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> + +int data; + +/* Verify that naked function traps at the end. */ + +void +__attribute__((naked, noinline, noclone)) +naked (void) +{ + if (data == 0x12345678) + return; + asm ("ret"); +} + +void handler (int i) +{ + exit (0); +} + +int main () +{ + struct sigaction s; + + sigemptyset (&s.sa_mask); + s.sa_handler = handler; + s.sa_flags = 0; + sigaction (SIGILL, &s, NULL); + + data = 0x12345678; + naked (); + + abort (); +} Index: testsuite/gcc.target/x86_64/abi/ms-sysv/ms-sysv.c =================================================================== --- testsuite/gcc.target/x86_64/abi/ms-sysv/ms-sysv.c (revision 250721) +++ testsuite/gcc.target/x86_64/abi/ms-sysv/ms-sysv.c (working copy) @@ -169,15 +169,9 @@ static const char *argv0; #define TEST_DATA_OFFSET(f) ((int)__builtin_offsetof(struct test_data, f)) -void __attribute__((used)) -do_test_body0 (void) -{ - __asm__ ("\n" - " .globl " ASMNAME(do_test_body) "\n" -#ifdef __ELF__ - " .type " ASMNAME(do_test_body) ",@function\n" -#endif - ASMNAME(do_test_body) ":\n" +void __attribute__((naked)) +do_test_body (void) +{__asm__ ( " # rax, r10 and r11 are usable here.\n" "\n" " # Save registers.\n" @@ -212,9 +206,6 @@ static const char *argv0; " call " ASMNAME(mem_to_regs) "\n" "\n" " retq\n" -#ifdef __ELF__ - " .size " ASMNAME(do_test_body) ",.-" ASMNAME(do_test_body) "\n" -#endif :: "i"(TEST_DATA_OFFSET(regdata[REG_SET_SAVE])), "i"(TEST_DATA_OFFSET(regdata[REG_SET_INPUT])),