Yes you are right, the code will attempt to access the global variable at the same location as it is linked for loader. This is because linking involves replacing all occurrences of identifiers (including function names and variable names) by the addresses determined after compiling.
In your application, the variable, even if it does exist there too, is likely to be at a different address.
The calling of the functions happens to work, because they are located in ROM and cannot be different for application and loader. Calling them via const pointers, which are also stored in ROM, bypasses the problem.
The solution is using a file system simulator, if you can find one for your hardware.
Otherwise you will hate having to do the following.
Part 1, setup:
- introduce a special linker section with all the variables accessed by both system paprts (application and loader)
- let one linker fill it
- set it up for the other linker as don't-tocuh
- be careful with the initialisation
- preferrably do not assume any intialisation value
- if you need initialisation, e.g. "bss" (init to 0) or "data" (init to specified value),
do so explicitly at the start of the system part which is not associated to the linker you let setup the variables
- for safety, it is recommended to do the init the same way in both system parts
- "data" init uses a special non-volatile linker section with a copy of the to-be-initialised variables, accessing that is possible
Part 2, access:
- option 1)
store const pointers to those variables, like you did for the functions
- option 2)
get the second linker (the other one, which did not do the actual setup of the common variable section) to create an identically structured and identically located section as the one from first linker; more studying of your linker needed here
Part 3, resuing values stored by other system part
(e.g. you want to leave some kind of message from loader, to be read my application)
- design which system part initisalises which variable, the other one only reads them
- separate the common variables in four sections,
- written and read by both system parts, initialised by both
- written and read by x, only read by y, initialised by x
- written and read by y, only read by x, initialised by y
- written by both system parts, not initialised, uses checksums and plausibility cehcks,
if a variable has not been initialised, init to default
- init each section only in the corresponding writer system part
- setup as "no init" in the other linker
- setup as "no init" in both linkers for the fourth case
- use getters and setters with checksum update and plausibility for the fourth case
To do all that, intense study of your linker features and syntax is needed.
So I recommend not to try, if you can get around it. Consider using an existing file system simulator; because that is basically what above means.