We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi,
This post is about the classic problem creating pointers to function using the overlay procedure.
The reference in the manual suggest the OVERLAY directive to modify the call tree that is automatically generated by the linker. But what happeneds if we don't know the name of the indirect function the pointer calls? Yes this is true.
Consider the possibility of someone who try to build a lib. And this lib provide a function(funA) that calls an afterwards user defined procedure unknown by the lib function(funA). Here an example
//lib_file.h // ... typedef void (* Tpfun)(void); void module_init (Tpfun pf); void module (void); // ... //lib_file.c static Tpfun pfun; //-------------------------------- void module_init (Tpfun pf) { pfun = pf; } //---------------------- void module (void) { //code // ... pfun(); // code }
In this simple program there is no call to module_init(&..) and it is impossible to know the address/name of the indirect function and so it is also impossible to use the OVERLAY directive(i think). We know only the pointer to function "pfun". We also don't know if the indirect function call other functions. The only way to know the name of the indirect function is when the lib user decide to use the module and initializes the module using the module_init(&..);
But how can we build the lib so the user uses it???
The question is:
1)Is there a way to modify the call tree that is automatically generated by the linker in order to include the indirect function? And if there is no way. 2)How can someone enable the normal way of function call using the stack?
I'm using the eval version C51 8.08
effectively, this does at link time what a real stack does at runtime.
Which means that recursive function call chains - or unknown call chains (pointers) - are not suited for a '51 processor.
I don't know about any other architecture where the linker knows about the internals of all functions. A linker normally have to fixup addresses depending on order and size of individual modules.
What the Keil linker does is a hack. But it is the only known method to make the '51 processor at least reasonably compatible with any high och medium level language. Keil is basically continuing something that was started with the PLM51 language from Intel.
"What the Keil linker does is a hack. But it is the only known method to make the '51 processor at least reasonably compatible with any high or medium level language."
Exactly!
It brings its problems - like all this call-tree analysis stuff - but can the OP suggest a better way?
I wouldn't call it a hack, so much as a fairly powerful optimization. Most C compilers generate code that spends a lot of run time pushing and popping onto a stack, and uses indirect references to access commonly used variables. The call tree analysis allows you to eliminate all that code and directly reference locals, temps, and parameters. Sometimes it would be nice to have this option on other architectures, even those that are much better suited to maintaining a stack and indirect references. For a great many programs, you don't actually need the features that all that run-time stack manipulation provides.
The cost of eliminating the stack, however, is fairly severe -- no recursion, no reentrancy, and limitations on the use of function pointers.
If you want, though, you can just declare all your functions reentrant and get the behavior you'd expect of a "normal" C compiler without the "hack". I don't think you'll like the results on the 8051 so much.
Most C compilers generate code that spends a lot of run time pushing and popping onto a stack, and uses indirect references to access commonly used variables.
No, they don't.
Most processors have a suitable set of instructions for implementing a stack, and suitable base pointer registers for accessing parameters and auto variables relative the current stack frame.
At function entry, a typical processor has to capture the current stack pointer as a base address for accessing parameters and auto variables. It then as to adjust the stack pointer to allocate room for auto variables. This can often be done with two instructions - neither instruction requiring any memory reference.
At function exit, a typical processor has to restore the current stack pointer, which can normally be done with a single register assign.
Standard pipelining can normally perform multiple instructions concurrently (especially instructions that doesn't require explicit memory accesses).
The net result is that for most programs, a very small part of the processor capacity is used for the stack manipulation.
The exception is when a large number of calls are to miniature functions with very few instructions in them. But in such cases, more processor capacity is normally lost in cache misses than in the stack manipulation. But then the normal - and trivially simple - way to handle such cases (if it is important) is to inline tiny functions. Either automatically, or by use of an inline keyword. The removal of the call statement will in many cases allow inlining without increasing the code size. And good code optimizers will perform the optimization after the inlining, allowing prefetches and optimum use of registers etc.
I wouldn't call it a hack, so much as a fairly powerful optimization.
The reason I called the Keil linker work a hack is because it is a very heavy-duty work-around to make the C51 processor do tricks it was specifically not inteded to do. It is a hack because it isn't a general solution to the problem. It can only perform it's workaround magic for a specific limited set of problems, and in some situations the user must be knowledgeable enough to help the compiler/linker. If it was a general solution and not a hack, you would never need to specify if a function is reentrant or not.
For other processor architectures, it is normally enough to specify if you want the compiler to optimize for speed, size or "debugability".
and in some situations the user must be knowledgeable enough to help the compiler/linker. If it was a general solution and not a hack, you would never need to specify if a function is reentrant or not.
oh WOW, I did not know that. I always thought you were supposed to know the tools you worked with.
Erik