Hi rnk,

For naked functions with parameters, Clang would emit prologues that end up 
clobbering the stack because LLVM doesn't set up a stack frame. For example, 
this function on X86:

__attribute__((naked)) int f(int x) {
  asm("movl $42, %eax");
  asm("retl");
}

Results in:

_Z1fi:
        movl    12(%esp), %eax
        movl    %eax, (%esp)  <--- Oops.
        movl    $42, %eax
        retl

(This was already reported as PR18791, and PR20028 for the epilogue.)

My patch does three things, which can be committed separately, but I figured 
it's easier to review them together:
- Don't emit prologues/epilogues for naked functions
- Don't allow non-asm statements in naked functions
- Don't allow asm statements to refer to parameters in naked functions.

Please take a look.

http://reviews.llvm.org/D5183

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/CodeGen/CGCall.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaStmtAsm.cpp
  test/CodeGen/attr-naked.c
  test/Sema/attr-naked.c
  test/Sema/ms-inline-asm.c
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6984,6 +6984,11 @@
 def err_filter_expression_integral : Error<
   "filter expression type should be an integral value not %0">;
 
+def err_non_asm_stmt_in_naked_function : Error<
+  "non-ASM statement in naked function is not supported">;
+def err_asm_naked_parm_ref : Error<
+  "parameter references not allowed in naked functions">;
+
 // OpenCL warnings and errors.
 def err_invalid_astype_of_different_size : Error<
   "invalid reinterpretation: sizes of %0 and %1 must match">;
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -1462,6 +1462,10 @@
 void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
                                          llvm::Function *Fn,
                                          const FunctionArgList &Args) {
+  if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>())
+    // Naked functions don't have prologues.
+    return;
+
   // If this is an implicit-return-zero function, go ahead and
   // initialize the return value.  TODO: it might be nice to have
   // a more general mechanism for this that didn't require synthesized
@@ -1985,6 +1989,12 @@
 void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
                                          bool EmitRetDbgLoc,
                                          SourceLocation EndLoc) {
+  if (CurCodeDecl && CurCodeDecl->hasAttr<NakedAttr>()) {
+    // Naked functions don't have epilogues.
+    Builder.CreateUnreachable();
+    return;
+  }
+
   // Functions with no result always return void.
   if (!ReturnValue) {
     Builder.CreateRetVoid();
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10376,6 +10376,17 @@
          !CheckConstexprFunctionBody(FD, Body)))
       FD->setInvalidDecl();
 
+    if (FD && FD->hasAttr<NakedAttr>()) {
+      for (const Stmt *S : Body->children()) {
+        if (!isa<AsmStmt>(S)) {
+          Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function);
+          Diag(FD->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
+          FD->setInvalidDecl();
+          break;
+        }
+      }
+    }
+
     assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");
     assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
     assert(MaybeODRUseExprs.empty() &&
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -405,6 +405,18 @@
   Result = CheckPlaceholderExpr(Result.get());
   if (!Result.isUsable()) return Result;
 
+  // Referring to parameters is not allowed in naked functions.
+  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Result.get())) {
+    if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+      if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+        if (Func->hasAttr<NakedAttr>()) {
+          Diag(Id.getLocStart(), diag::err_asm_naked_parm_ref);
+          Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute);
+        }
+      }
+    }
+  }
+
   QualType T = Result.get()->getType();
 
   // For now, reject dependent types.
Index: test/CodeGen/attr-naked.c
===================================================================
--- test/CodeGen/attr-naked.c
+++ test/CodeGen/attr-naked.c
@@ -12,7 +12,16 @@
 // Make sure this doesn't explode in the verifier.
 // (It doesn't really make sense, but it isn't invalid.)
 // CHECK: define void @t2() [[NAKED]] {
-__attribute((naked, always_inline)) void t2()  {
+__attribute((naked, always_inline)) void t2() {
+}
+
+// Make sure not to generate prolog or epilog for naked functions.
+__attribute((naked)) void t3(int x) {
+// CHECK: define void @t3(i32)
+// CHECK-NEXT: entry
+// CHECK-NOT: alloca
+// CHECK-NOT: store
+// CHECK-NEXT: unreachable
 }
 
 // CHECK: attributes [[NAKED]] = { naked noinline nounwind{{.*}} }
Index: test/Sema/attr-naked.c
===================================================================
--- test/Sema/attr-naked.c
+++ test/Sema/attr-naked.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -triple i686-pc-linux
 
 int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to functions}}
 
@@ -10,3 +10,16 @@
 
 void t2() __attribute__((naked(2))); // expected-error {{'naked' attribute takes no arguments}}
 
+__attribute__((naked)) int t3() { // expected-note{{attribute is here}}
+  return 42; // expected-error{{non-ASM statement in naked function is not supported}}
+}
+
+__attribute__((naked)) int t4() {
+  asm("movl $42, %eax");
+  asm("retl");
+}
+
+__attribute__((naked)) int t5(int x) {
+  asm("movl x, %eax");
+  asm("retl");
+}
Index: test/Sema/ms-inline-asm.c
===================================================================
--- test/Sema/ms-inline-asm.c
+++ test/Sema/ms-inline-asm.c
@@ -103,3 +103,14 @@
 void test_operand_size() {
   __asm { call word t4 } // expected-error {{Expected 'PTR' or 'ptr' token!}}
 }
+
+__declspec(naked) int t5(int x) { // expected-note {{attribute is here}}
+  asm { movl eax, x } // expected-error {{parameter references not allowed in naked functions}}
+  asm { retl }
+}
+
+int y;
+__declspec(naked) int t6(int x) {
+  asm { mov eax, y } // No error.
+  asm { ret }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to