From 53221dd2ccf29fc5e357ffb67363ca7461d24193 Mon Sep 17 00:00:00 2001 From: Zeex Date: Sun, 5 Jan 2014 01:16:47 +0700 Subject: [PATCH] Introduce #pragma naked When applied to a function #pragma naked merely disables the "should return a value" warning for the function. It's intended to be used with functions that return a value via #emit instead of the normal return statement. This pragma works only on function definitions, not declarations. It's also pretty stupid - the function may be defined way after this directive and it won't stop on things coming in between. For example, here all declarations between #pragma naked and f() are effectively ignored: #pragma naked new x; // ignored forward g(); // ignored native n(); // ignored f() { // f() becomes naked } Note that #pragma naked does not affect generated code in any way, unlike e.g. __declspec(naked) or __attribute__((naked)) in C/C++ where the compiler omits the code for the prolog and epilog. --- source/compiler/sc.h | 2 ++ source/compiler/sc1.c | 9 +++++++-- source/compiler/sc2.c | 2 ++ source/compiler/sc3.c | 2 +- source/compiler/scvars.c | 1 + 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/source/compiler/sc.h b/source/compiler/sc.h index 707b053..3395169 100644 --- a/source/compiler/sc.h +++ b/source/compiler/sc.h @@ -219,6 +219,7 @@ typedef struct s_symbol { #define uRETNONE 0x10 #define flgDEPRICATED 0x01 /* symbol is deprecated (avoid use) */ +#define flagNAKED 0x10 /* function is naked */ #define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */ #define uSIZEOF 0x80 /* set in the "hasdefault" field of the arginfo struct */ @@ -808,6 +809,7 @@ SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecate SC_VDECL int sc_curstates; /* ID of the current state list */ SC_VDECL int pc_optimize; /* (peephole) optimization level */ SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */ +SC_VDECL int pc_naked; /* if true mark following function as naked */ SC_VDECL constvalue sc_automaton_tab; /* automaton table */ SC_VDECL constvalue sc_state_tab; /* state table */ diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index ead5cd6..14f7c95 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -843,6 +843,7 @@ static void resetglobals(void) pc_deprecate=NULL; sc_curstates=0; pc_memflags=0; + pc_naked=FALSE; } static void initglobals(void) @@ -3513,6 +3514,10 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc char *ptr= (sym->documentation!=NULL) ? sym->documentation : ""; error(234,symbolname,ptr); /* deprecated (probably a public function) */ } /* if */ + if (pc_naked) { + sym->flags|=flagNAKED; + pc_naked=FALSE; + } /* if */ begcseg(); sym->usage|=uDEFINE; /* set the definition flag */ if (stock) @@ -3572,7 +3577,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc if ((lastst!=tRETURN) && (lastst!=tGOTO)){ ldconst(0,sPRI); ffret(strcmp(sym->name,uENTRYFUNC)!=0); - if ((sym->usage & uRETVALUE)!=0) { + if ((sym->usage & uRETVALUE)!=0 && (sym->flags & flagNAKED)==0) { char symname[2*sNAMEMAX+16]; /* allow space for user defined operators */ funcdisplayname(symname,sym->name); error(209,symname); /* function should return a value */ @@ -5748,7 +5753,7 @@ static void doreturn(void) } else { /* this return statement contains no expression */ ldconst(0,sPRI); - if ((rettype & uRETVALUE)!=0) { + if ((rettype & uRETVALUE)!=0 && (sym->flags & flagNAKED)==0) { char symname[2*sNAMEMAX+16]; /* allow space for user defined operators */ assert(curfunc!=NULL); funcdisplayname(symname,curfunc->name); diff --git a/source/compiler/sc2.c b/source/compiler/sc2.c index 44a36df..113198b 100644 --- a/source/compiler/sc2.c +++ b/source/compiler/sc2.c @@ -1168,6 +1168,8 @@ static int command(void) if (comma) lptr++; } while (comma); + } else if (strcmp(str,"naked")==0) { + pc_naked=TRUE; } else { error(207); /* unknown #pragma */ } /* if */ diff --git a/source/compiler/sc3.c b/source/compiler/sc3.c index af8437d..1ccbeb5 100644 --- a/source/compiler/sc3.c +++ b/source/compiler/sc3.c @@ -433,7 +433,7 @@ static void checkfunction(value *lval) /* function is defined, can now check the return value (but make an * exception for directly recursive functions) */ - if (sym!=curfunc && (sym->usage & uRETVALUE)==0) { + if (sym!=curfunc && (sym->usage & uRETVALUE)==0 && (sym->flags & flagNAKED)==0) { char symname[2*sNAMEMAX+16]; /* allow space for user defined operators */ funcdisplayname(symname,sym->name); error(209,symname); /* function should return a value */ diff --git a/source/compiler/scvars.c b/source/compiler/scvars.c index 84c4798..152ccbb 100644 --- a/source/compiler/scvars.c +++ b/source/compiler/scvars.c @@ -90,6 +90,7 @@ SC_VDEFINE char *pc_deprecate=NULL;/* if non-null, mark next declaration as depr SC_VDEFINE int sc_curstates=0; /* ID of the current state list */ SC_VDEFINE int pc_optimize=sOPTIMIZE_NOMACRO; /* (peephole) optimization level */ SC_VDEFINE int pc_memflags=0; /* special flags for the stack/heap usage */ +SC_VDEFINE int pc_naked=FALSE; /* if true mark following function as naked */ SC_VDEFINE constvalue sc_automaton_tab = { NULL, "", 0, 0}; /* automaton table */ SC_VDEFINE constvalue sc_state_tab = { NULL, "", 0, 0}; /* state table */