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