3
votes

I have MCU with flash memory breaked in sections(as usual). Linker places .struct_init, .struct_init_const, .struct_not_init sections to addresses belongs to flash memory section20. It is hardcoded in linker script.

Consider following test code: test.h

typedef struct
{
    int val1;
    int val2;
} mystruct_t;

test.cpp

#include "test.h"

// each variable is placed in dedicated section
// sections are placed in flash section20
// linker exports symbols with address of eaach section
__attribute__((section(".struct_init")))
mystruct_t struct_init = {
    .val1 = 1,.val2 = 2};

__attribute__((section(".struct_init_const")))
extern const mystruct_t struct_init_const = {
    .val1 = 1, .val2 = 2};

__attribute__((section(".struct_not_init")))
mystruct_t struct_not_init;

main.cpp

#include <stdint.h>

// This symbols exported by linker
// contains addresses of corresponding sections
extern uintptr_t LNK_STRUCT_INIT_ADDR;
extern uintptr_t LNK_STRUCT_INIT_CONST_ADDR;
extern uintptr_t LNK_STRUCT_NOT_INIT_ADDR;

// Pointers for indirect access to data
mystruct_t* struct_init_ptr = (mystruct_t*)LNK_STRUCT_INIT_ADDR;
const mystruct_t* struct_init_const_ptr = (const mystruct_t*)LNK_STRUCT_INIT_CONST_ADDR;
mystruct_t* struct_not_init_ptr = (mystruct_t*)LNK_STRUCT_NOT_INIT_ADDR;

// Extern variables declarations for DIRECT access data
extern mystruct_t struct_init;
extern const mystruct_t struct_init_const;
extern mystruct_t struct_not_init;

// This is some variables representing config values
// They can be more complex objects(classes) with internal state and logic..
int param1_direct;
int param1_init_const_direct;
int param1_not_init_direct;

int param1_indirect;
int param2_init_const_indirect;
int param1_not_init_indirect;

int main(void)
{
    // local variables init with direct access
    int param1_direct_local = struct_init.val1;
    int param1_init_const_direct_local = struct_init_const.val1;
    int param1_not_init_direct_local = struct_not_init.val1;

    // local variables init with indirect access
    int param1_indirect_local = struct_init_ptr->val1;
    int param2_init_const_indirect_local = struct_init_const_ptr->val1;
    int param1_not_init_indirect_local = struct_not_init_ptr->val1;

    //global variables init direct
    param1_direct = struct_init.val1;
    param1_init_const_direct = struct_init_const.val1;
    param1_not_init_direct = struct_not_init.val1;
    //global variables init indirect
    param1_indirect = struct_init_ptr->val1;
    param2_init_const_indirect = struct_init_const_ptr->val1;
    param1_not_init_indirect = struct_not_init_ptr->val1;

    while(1){
        // use all variables we init above
        // usage of variables may also occure in some functions or methods
        // directly or indirectly called from this loop
    }
}

I wanna be sure that initialization of param1_ variables will lead to fetch data from flash. Because data in flash section20 can be changed using bootloader(at the moment when main firmware is not running).

The question is: Can LTO(and other optimizations) throw away fetches from flash and just substitute known values because they are known at link time because of initialization. What approach is better? If LTO can substitute values - then initialization should be avoided? I know volatile can help, but is it really needed in this situation?

Code exampe shows different approaches of accessing and initializing data. not_init version seems to be the best, because compiler can't substitute anything. But it will be a good idea to have some default parameters, so i'd prefer init version if it can be used.

What approach should be chosen?

Currently i am using GCC 4.9.3 but this is general question about any C/C++ compiler.

1
There is no language "C/C++". Please pick one. Expecially with const, there are differences between them. - too honest for this site
Is there a reason you do not use the proper types? - too honest for this site
Language is C++. What do you mean ? "Is there a reason you do not use the proper types". Code example just illustrate different methods of accessing data in flash. Direct and indirect. With const and without... - sigmaN
Just wonder why you cast that much and do not use the correct types? - too honest for this site
Linker exports int with address of section. I need pointer from int. This is just example of one possible solution. It is definetly better to use & operator. Idea of int initialized pointer comes from this thread stackoverflow.com/questions/31322646/… - sigmaN

1 Answers

3
votes

C and C++ both feature extern variables, which lets you define constants without immediately giving away their values:

// .h
extern int const param1;
extern char const* const param2;
// ...

In general you would define them in a (single) source file, which would hide them away from anything not in this source file. This is not LTO resilient, of course, but if you can disable LTO it is an easy enough strategy.

If disabling LTO is not an option, another solution is to not define them, let LTO produce a binary, and then use a script to splice the definitions in the produced binary in the right section (the one that can be flashed).

With the value not available at LTO time, you are guaranteed that it will not be substituted.


As for the solutions you presented, while volatile is indeed a standard compliant solution, it implies that the value is not constant, which prevents caching it during run-time. Whether this is acceptable or not is for you to know, just be aware it might have a performance impact, which as you are using LTO I surmised you would like to avoid.