JMGross wrote:
It's a tricky thing. In the early days of compilers, I'd just had
done function pointer arithmetics (subtract the start address from
the start address of the following function) but today with all these
optimisations, the compiler can rearrange everything. It' s not even
sure whether it is not re-using the epilogue of a different function
at the end of the one you want to move, so the space between its
start and end does not contain all the function code.
One can circumvent this by placing the function into its own source
file.
Placing the function into RAM section indeed is the only safe way to,
well, place it into the RAM section.
But this has several drawbacks. First you must be absolutely sure
that this part of the ram section is never clobbered, as the function
is placed there at start of the processor and never refreshed. This
should be normal condition, but, well..., the stack is never far from
And the risk of stating the blindingly obvious, if your stack is
crashing into your data, or you have other unexpected clobbers of your
ram, then your program is trashed anyway.
your data :) Second, it uses RAM space. Always. And even if never
used at all. Third, if you have several of these functions, they ALL
use ALWAYS their full size in RAM.
These are valid points - it's normally important to keep your ram
functions as small as possible.
I don't see, however, why functions in RAM shall not call any
function in FLASH (except when writing to flash is active)
If your ram functions could call code in flash, there would (normally)
be no point in putting them in ram in the first place! Flash
programming functions are the main use of such code in user applications.
There are other uses of ram functions, such as for run-time patches, but
that's more specialised.
Copying the function only if used allows re-use of a buffer that is
currently unused (such as an sprintf buffer or whatever) to
temporarily store the function, execute it and then continue with the
required space free again. It might even reserved space on the stack.
It also allows loading different functions to the same RAM space,
when needed. This way, the functions might be more specific and
therefore smaller in RAM even if they might take up more space in ROM
all together.
If you keep your ram functions small, this is not normally a problem.
And (ab)using the .data section for your functions means you don't have
to worry about loading the code, and you don't have to think about where
the function is or how to call it - just treat it as a normal function.
You can even step in and out of it with a debugger.
One possible solution would be to look for the 'POP/RET' epilogue as
delimiter for the function-end. But it also requires a look into the
LST file to ensure optimisation hasn't messed-up things. One can,
however, apply the optimize attribute tot he function so it won't be
optimized or only optimized locally.
It would be nice to have GCC emit a global symbol such as
'__sizeof_fname' along with the '.size' statement. Shouldn't be a big
thing to implement. But still risky because of the optimisation
problem described above. Something like that is done with the
following ASM hack:
extern const int __sizeof_myFunc; void myFunc(void){ // code } asm ("
__sizeof_myFunc: .short . - myFunc \n");
While this is not perfect, it generates a const value of the proper
size of the function (in bytes) right behind the function itself.
(check the .lst file to be sure) You should still take care of any
optimizations and it is best to place the whole thing into a separate
object file. The declaration has to be 'extern' as the ASM line
actually generates the definition of the constant. But it only needs
to be known where it is actually used.