Sources compilation order affects the application

Hello,
I’m migrating the project from mbed cli 1 to mbed cli 2. Target is NRF52xxxx. During CMakeLists.txt creation I discovered the following issue. If I add source files in the following order the app inits fine:

target_sources(${APP_TARGET}
    PRIVATE
        main.cpp

        ${APPLICATION_SOURCES}
        ${DRIVERS_SOURCES}
        ${MIDDLEWARE_SOURCES}
)

But if I swap the order of sources:

target_sources(${APP_TARGET}
    PRIVATE
        main.cpp

        ${APPLICATION_SOURCES}
        ${MIDDLEWARE_SOURCES}
        ${DRIVERS_SOURCES}
)

Then I’ve got errors on the initialization of one of the Middleware components.

++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x8DE8
Error Value: 0x200032F4
Current Thread: main Id: 0x200021A8 Entry: 0x1512F StackSize: 0x800 StackMem: 0x20002AB0 SP: 0x20003290 

The order of sources determines the order of code in the linkage map and in the final application. Further investigation has shown that if I call any function which address is near the 0x0000000000008de8, then I get a hardfault. In the first case, the Middleware module initialization function has the address 0x0000000000008de8. In the second case, this address is occupied by the ToF driver, and if I try to use ToF sensor, the hardfault occurs.

I’ve never seen such type of problem before. Do you have any idea how I should debug this issue? Is it a compiler/linker error or hardware error (broken loading app from flash to RAM)?

quick question: how do you generate/populate the APPLICATION_SOURCES and other variables?

and follow-up, can you try the same thing by explicitly listing the .c/cpp files and trying the different orders.

from my experience, the order should not matter.

another thing to try is to create different targets for your middleware and drivers and link against those for your APP_TARGET

These resources might be helpful:

Hi Ladislas, thanks for the answer.

The `APPLICATION_SOURCES and other SOURCES are just simple sets of source files, for example:

set (APPLICATION_SOURCES 
    application/Source1.cpp
    application/Source2.cpp
    ...  
)
set (DRIVERS_SOURCES 
    drivers/Driver1.cpp
    drivers/Driver2.cpp
    ...  
)

from my experience, the order should not matter.

I agree. This is really extraordinary behaviour.

another thing to try is to create different targets for your middleware and drivers and link against those for your APP_TARGET

I guess that will cause another memory layout. I can try this and check if the function under 0x0000000000008de8 (or somewhere nearby) causes faults, but it won’t explain the root cause of the issue.

  • When you make an external reference to a function or variable in C or C++, the linker, upon encountering this reference, can do one of two things. If it has not already encountered the definition for the function or variable, it adds the identifier to its list of “unresolved references.” If the linker has already encountered the definition, the reference is resolved.

  • If the linker cannot find the definition in the list of object modules, it searches the libraries in the order you give them.

  • Because the linker searches files in the order you give them, you can pre-empt the use of a library function by inserting a file with your own function, using the same function name, into the list before the library name appears. Since the linker will resolve any references to this function by using your function before it searches the library, your function is used instead of the library function. Note that this can also be a bug, and the kind of thing C++ namespaces prevent.

or maybe some double weak symbol definitions? I think the linker will not complain, but its the question which module is the winner.