Hello Everyone! Today we are going to learn about Naked Function Calls in C++. We would have a doubt why the function is call naked in C++. Before, knowing about it we should learn about what a function call is?
Function Call in C++
The process of activating the function and allowing it to run at the place where we require it to be executed in C++ Program is known as Function Call in C++.
There two types of function calls in C++. They are:
- Function Call with Parameter
Here, in this function call we do assign or pass any parameters to the C++ Program. These Parameters play a crucial role in the running of the program.
- Functions Call without Parameter
Here, in this function call we do assign or pass any parameters to the C++ Program. These Parameters play a crucial role in the running of the program.
Example
File name: withParameters1. cpp
/* This is a program written to find the factorial of a number using function call which is parameterized or we can say that parameters are passed into the program */
#include <iostream>
#include <cstdio>
using namespace std;
int factorial (int number)
{
int i;
int f=1;
for(i = 1; i <= number; i++)
{
f = f * i;
}
return f;
}
int main()
{
int n;
cout <<"Enter any number: " << endl;
cin >>n;
int fact;
fact = factorial(n);
printf("%d is the factorial of %d",fact,n);
return 0;
}
Input:
Enter any number:
10
Output:
3628800 is the factorial of 10
Example
File name: withoutParameters1. cpp
/* This is a program written to find the factorial of a number using function call which is not parameterized or no parameter passing */
#include <iostream>
#include <cstdio>
using namespace std;
void factorial ()
{
int number;
cout <<"Enter any number: " << endl;
cin >>number;
int i;
int f=1;
for(i = 1; i <= number; i++)
{
f = f * i;
}
printf("%d is the factorial of %d",f,number);
}
int main()
{
int fact;
factorial();
return 0;
}
Input:
Enter any number:
15
Output:
2004310016 is the factorial of 15
Naked Function Calls
When a function is declared with the naked property, no prolog or epilog code is generated, allowing you to use the inline assembler to create your own unique prolog/epilog sequences.
An advanced feature is the availability of naked functions. They provide you the option to declare a function that is being called from a context other than C or C++, allowing you to base assumptions about the location of parameters or the preservation of registers differently.
Routines like interrupt handlers are examples. The creators of virtual device drivers (VxDs) will find this functionality especially very handy or easy to use.
The naked property is used to specify functions, and when code is generated for such functions, prolog and epilog are not included.
Using inline assembler code, you may utilize this functionality to create your own prolog/epilog code sequences. Writing virtual device drivers makes good use of naked functions. Keep in mind that the x64 platform does not support the naked property; it is only valid on x86 and ARM.
Syntax
_delspec (naked)
Naked functions must utilize extended attribute syntax and the __declspec keyword as the naked attribute only affects a function's declaration and is not a type modifier.
Even if a function is tagged with the __force inline keyword and the naked attribute, the compiler cannot create an inline function for that function.
If the naked attribute is used on anything other than the definition of a non-member method, the compiler throws an error.
Examples
_declspec (naked) float fun ( initial parameters ) { }
Or
#define Naked _declspec (naked)
Naked float fun ( initial parameters ) { }
Only the nature of the prolog and epilog sequences generated by the compiler is impacted by the naked property.
It has no impact on the code created to invoke these functions. Thus, function pointers cannot contain the naked property since it is not regarded as a component of the type of the function. Additionally, a data definition cannot use the naked property.
Rules and Limitations
Following are the rules and limitations of Naked Function Call in C++:
- The return keyword cannot be used here in this type of function call
- _alloca function cannot be used in this type of function calls
- Initialized local variables are not allowed at function scope to guarantee that no initialization code for local variables enters before the prolog sequence. Particularly, function scope does not allow the definition of C++ objects. A nested scope could, however, include initialized data.
- Naked Function Calls in C++ must unwind over the stack frame. So, C++ exception handling constructs and structured exception handling are not allowed.
- Naked Function Calls in C++ must unwind over the stack frame. So, setjmp cannot be used for Naked Function Calls in C++.
- Every time one of the register parameters for __fastcall bare functions is referenced in C/C++ code, the prolog code should save the value of that register onto the stack location for that variable.
- If the Naked function call is in lexical scope, C++ class objects cannot be declared. But you are still allowed to define objects in nested blocks.
- Although it is not advised, the frame pointer optimization (the / Oy compiler option) is automatically suppressed for a naked function.
- When Naked Function Call building is done with / clr, the naked keyword can be ignored.
Example
// nkdfastcl.cpp
// compile with: /c
// processor: x86
__declspec(naked) int __fastcall power(int i, int j) {
// This code is written to calculate the value of x EXOR y, assumes that j >= 0
// prolog
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
// Place ECX and EDX in the x and y stack places.
mov x, ecx
mov y, edx
}
{
int s = 1; // return value
while (y-- > 0)
s * = x;
__asm {
mov eax, k
};
}
// epilog
__asm {
mov esp, ebp
pop ebp
ret
}
}
Ideas to Keep in Mind While Writing Prolog/Epilog Code
It's crucial to comprehend the structure of the stack frame before creating your own prolog and epilog code sequences. Understanding how to utilize the __LOCAL SIZE symbol is also helpful.
Stack Frame Layout
This illustration displays typical prolog code that might be used in a 32-bit function:
Example:
push ebp ; Save ebp
sub esp, localbytes ; Allocate space for locals
mov ebp, esp ; Set stack frame pointer
push <registers> ; Save registers
The "registers" variable is a placeholder for the list of registers that should be saved on the stack, and the "localbytes" variable indicates how many bytes are required on the stack for local variables. You can put any other pertinent data on the stack after pushing the registers. The relevant epilog code is as follows:
Epilog Code
pop <registers> ; Restore registers
pop ebp ; Restore ebp
mov esp, ebp ; Restore stack pointer
ret ; Return from function
The stack always becomes smaller (from high to low memory addresses). The pushed value of ebp is where the base pointer (ebp) points. At ebp-4, the residents' region starts. Calculate an offset from ebp by deducting the right amount from ebp in order to access local variables.
LOCAL SIZE
For usage in the inline assembler block of the function prolog code, the compiler supplies a symbol called __LOCAL SIZE. In custom prolog code, this symbol is used to allocate space for local variables on the stack frame.
The value of LOCAL SIZE is set by the compiler. The sum of all user-defined local variables and compiler-generated temporary variables makes up its value. Only as an instantaneous operand, LOCAL SIZE cannot be utilized in an expression. You are not permitted to alter or reinterpret the meaning of this symbol. For instance:
mov eax, [ebp - __LOCAL_SIZE] ;Error
mov eax, __LOCAL_SIZE ;Immediate operand--Okay
The __LOCAL SIZE symbol is used in the prolog sequence of the naked function that employs unique prolog and epilog sequences as follows:
Example
// the__local_size_symbol.cpp
// processor: x86
__declspec ( naked ) int main() {
int x;
int y;
__asm { /* prolog */
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
/* Function body */
__asm { /* epilog */
mov esp, ebp
pop ebp
ret
}
}
This is all about Naked Function Calls in C++ Language.