This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Declaring local variable causes L15 warnings, but only on optimization level 9

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-main
Previously, 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.

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

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:

*** 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.

Curiously, the MAP file says

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().

Any suggestions on what is going on and how to fix it are welcome!

Parents
  • 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.htm
    So 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

Reply
  • 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.htm
    So 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

Children
No data