For reference, please take a look at this older question of mine:https://community.arm.com/developer/tools-software/tools/f/keil-forum/41992/spurious-link-from-isr-to-pr-mainPreviously, function pointers that were placed in a global table made the linker think ?CO?MAIN is calling all of those referenced functions. Telling the linker to OVERLAY(?CO?MAIN ~ ThoseReferencedFunctions) (and adding OVERLAY(TheFunctionUsingThatTable ! ThoseReferencedFunctions), of course) fixed the problem.
OVERLAY(?CO?MAIN ~ ThoseReferencedFunctions)
OVERLAY(TheFunctionUsingThatTable ! ThoseReferencedFunctions)
The linker warnings back then looked very similar to the ones I am getting now:
*** WARNING L15: MULTIPLE CALL TO FUNCTION NAME: FOO/MAIN CALLER1: INTERRUPTVECTORS_INT0/MAIN CALLER2: INTERRUPTVECTORS_UART/MAIN*** WARNING L15: MULTIPLE CALL TO FUNCTION NAME: FOO/MAIN CALLER1: INTERRUPTVECTORS_UART/MAIN CALLER2: ?C_C51STARTUP
*** WARNING L15: MULTIPLE CALL TO FUNCTION
NAME: FOO/MAIN
CALLER1: INTERRUPTVECTORS_INT0/MAIN
CALLER2: INTERRUPTVECTORS_UART/MAIN
CALLER1: INTERRUPTVECTORS_UART/MAIN
CALLER2: ?C_C51STARTUP
These warnigs show up when, in `void Foo()`, i simply only declare a local variable. Like unsigned char i; or bit b;. (That is, the function is empty except for the declaration.) If I add some more code that accesses a few global variables (but does not call any other functions), an L13 appears too:
unsigned char i;
bit b;
*** WARNING L13: RECURSIVE CALL TO FUNCTION CALLED: MAIN CALLER: HARDWARETEST_GP_TESTRS485_QUEUEFIRSTIDLETEST/MAIN
*** WARNING L13: RECURSIVE CALL TO FUNCTION
CALLED: MAIN
CALLER: HARDWARETEST_GP_TESTRS485_QUEUEFIRSTIDLETEST/MAIN
But all of these warnings only show up when the code optimization level is set to 9: Common Block Subroutines. On the lower levels, the warnings don't show up. Now... the errors last time were also insane, so nothing can shock me anymore, but goodamnit the error messages are just so useless for finding the actual cause.
9: Common Block Subroutines
Curiously, the MAP file says
MAIN ----- ----- ----- ----- +--> ?CO?MAIN +--> ?PR?FOO... +--> ?PR?_BAR?MAIN
MAIN ----- ----- ----- -----
+--> ?CO?MAIN
+--> ?PR?FOO...
+--> ?PR?_BAR?MAIN
(Please note that Foo and Bar are short placeholders. The real function names are longer, which is why "FOO..." has an ellipsis at the end.)I don't know why BAR has an underscore and FOO doesn't. I also don't know why these show up here in the first place. I never take function pointers to either. They are also not called directly from void main().
void main()
Any suggestions on what is going on and how to fix it are welcome!
Related:
"BL51: Warning L13 (Recursive Call to Segment) with Constants"
developer.arm.com/.../latest
I don't think this explains all of the symptoms I'm seeing. I made sure to add appropriate overlay-directives in regards to function pointers. Remove the link between the "function that takes the pointer" to "the function pointed to" and add a link between "the function that performs the indirect call" to "the function pointed to". Simply declaring a local variable does not add anything to the constant segment. Or at least it should not. f it does, it's non-deterministic when it does and when it doesn't. Anyways, "?CO?EXAMPLE1 ~ FUNC2 deletes the implied call reference between func2 and the code constant segment in the example." seems like a very bad workaround. Either link isn't actually needed when using a string literal like that, in which case the compiler shouldn't add that link in the first place, or the link is needed, in which case removing it will likely break things.
Also, at some point this worked:
void Blubb(); void Bla() { Blubb(); } void Blubb() { unsigned char c; }
While this didn't:
void Blubb(); void Blubb() { unsigned char c; } void Bla() { Blubb(); }
Which is just insane.
Hi Niko,I'd like to explain how the linker works so that you understand all its warnings and strange messages. BTW, the compiler has nothing to do with all these issues. Only the linker BL51 or LX51 does all the program flow analysis and overlaying of local data segments.
You should read the chapter about data overlaying. This is the link to the LX51 manual:https://www.keil.com/support/man/docs/lx51/lx51_overlaying.htm>Simply declaring a local variable does not add anything to the constant segment. Or at least it should not.That's correct, but this is a side effect. The linker analyzes the program flow of your application in order to overlay the local data segments of the functions. This is necessary because the 8051 core does not have instructions to address local variables on the stack efficiently. What our linker is doing, is sometimes called a 'compiled stack'.
When the linker analyzes the program flow, it only 'sees' the references between the segments. It cannot distinguish between a function call or a usage of a constant. Because of this, you need to fix the call tree manually with the OVERLAY directive as soon as constants of one array are used in several functions. On the other hand, most function calls via pointer are not visible to the linker.
When the linker analyzes the program flow to overlay segments, only functions that have a local data segment must be handled by the linker. A local data segment only exists when you have local variables (which cannot be located in registers), or when too many parameters are passed to this function which cannot be assigned to registers. This is the reason why you see a different behavior as soon as you define a local variable. Functions without a local data segment are reentrant by default and do not have to be considered for data overlaying.
>I solved this problem in a different project by setting the optimization level to 8
Well, this is something I cannot explain without seeing this project. This must be a side effect. With optimization level 9, you enable 'Common Subroutine' optimizations. This means that identical code sequences are extracted from several functions and this code sequence is then called like a function. As you can imagine, this adds lots of cross-references between functions which usually do not call each other.
>I don't know why BAR has an underscore and FOO doesn't.
This is defined in the calling conventions. See https://www.keil.com/support/man/docs/c51/c51_ap_progobj.htmSo the underscore means that this function receives parameters in registers.
Does that explain the seemingly weird messages of the linker? Let me know if you have further questions.
Hans