'Naked function and stacking procedure

I searched the Internet, but I didn't quite get it. It's about stacking. When a c function called another a c function, each function procedure has own responsibility for protect last data in registers and stacks. There is calee and caller stacking procedure and caller saves r0-r3, lr, etc. and callee saves r4-r11 if it use them. Also before when callee function works, there is some additional procedure named as epilogue and prologue (I am working on stm32f4).

I do not fully understand why the prologue and epilogue are needed. I would be very happy if there is a resource you can offer to learn it.

But my main question is about naked function and stacking procedure. When we use the Naked attribute, the epilogue and prologue procedure are not performed. But if I use the naked function, will the caller and callee procedure be applied or i have to do this in my application code ? I'm really confused about this point. I would very appreciate it if you could answer these questions. Thank you.



Solution 1:[1]

I'm busy these days and I'm sorry I haven't been able to write anything. First of all, thank you for your answers. Answers were really descriptive and informative. Actually, I think that I know enough assembly on the platform where I am developing an application. I actively use argument passes and calling conversions using inline assembly. I am very confused at one point. Normally, stacking is performed automatically when executing a c function. In addition, prologue and epilogue processes are also applied, followed by unstacking. However, prologue and epilogue operations are not automatically applied when a naked function is executed. In this case, is the stacking process applied automatically? I have to secure the system and if stacking is not done automatically then I will have to do it myself for coherency and working fine. For example, I have to reach the stack pointer value while executing a function and for modularity I have to provide it with a different function defination. I cannot use inline assembly directly. In this case, I should execute a naked function so that the corresponding register value does not change. There are many situations like this and I need to be sure at this point in order to provide them safely. Thanks a lot for your answer.

Solution 2:[2]

On ARM there isn't really much of a "prologue" and "epilogue" as there is on x86 and other processors.

At the start of the function there is usually just as single push instruction, which includes some set of registers including the link register:

push {r4-r6,lr}

And at the end of the function there is a single pop instruction, including the program counter:

pop {r4-r6,pc}

This both restores the saved registers and returns to the caller.

Saving registers is only performed if the compiler decides it needs them. In particular it only needs the link register if the function calls other functions. In many small functions, there is no "prologue" at all, and at the end there is just a single instruction to return:

bx lr

The naked function attribute tells the compiler not to generate these instructions. The main purpose of this as far as I can tell on ARM is if you are going to write the entire function in inline assembly and manage all the registers yourself, but you still want to put the function in a C or C++ file. In my opinion this is a very untidy thing to do. If the function is entirely in assembly then it should be in an assembly file. Inline assembly should be used in C or C++ functions where the compiler manages the register allocation, and you just need access to particular instructions that you cannot get from C or C++.

Other details:

I don't believe the naked attribute changes anything in the code that calls the function (but I do not know about every possible architecture).

Note that on ARM when starting a function that will call other functions you must push an even number of registers to keep the stack aligned.

Note that when starting a variadic function (such as printf) you must start with:

push {r0-r3}

This ensures that the first few function arguments are contiguously in memory on the stack along with the later ones that did not fit in these registers.

On processors other than Cortex-M a much more complicated prologue and epilogue is required interrupt handler functions. This usually requires adding an extra attribute (eg: attribute((interrupt(N)))). On Cortex-M such as your STM32 the hardware interrupt controller sets up the registers exactly as a software would call a function, so nothing special is required.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MCM
Solution 2