This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28069: Know the LOAD and RUN address of initialized global variables placed in a custom section

Part Number: TMS320F28069


Using the COFF compiler for this C2000: 

At the end of the task, my objective at a high level is to: 

1) Know the flash address of a variable which has been declared and initialized in my C code as global

2) Know the RAM/run address of that variable which has been declared and initialized in my C code as global

3) Using the knowledge provided in objective 1 - use an external tool to manipulate the .out/hex file at that known flash address. 

To convey the idea more simply: I'd like to be able to modify some global values in the output binary - without recompiling.  To calibrate values, which might be unique to systems - which will run identical code otherwise. 

I've been assigning global variables into a custom data section: 

float sc_PVDD __attribute__((section(".mySectionName"))) = 12.0F ;

This declaration is at the head of a source file. 

The information regarding the 'load' and 'run' address is then conveyed to our external tool, along with a copy function within the same source file (in a startup routine) through linker directives which extract LOAD and RUN addresses to the global variables _runmySectionName and _initmySectionName

SECTIONS
{
.vectors: load = 0x000000000

.text : > FLASH1 | FLASH2, PAGE = 0
appheader : > APPHDR, PAGE = 0
codestart : > CODESTART PAGE = 0
.switch : > FLASH1 | FLASH2, PAGE = 0

.cinit : > FLASH1 | FLASH2, PAGE = 0

.pinit : > FLASH1 | FLASH2, PAGE = 0
.const : > FLASH1 | FLASH2, PAGE = 0
.econst : > FLASH1 | FLASH2, PAGE = 0
.rtdx_text : > FLASH1 | FLASH2, PAGE = 0
IQmath : > FLASH1 | FLASH2, PAGE = 0
ramfuncs : LOAD = FLASH1 | FLASH2,
RUN = PRAM,
LOAD_START(_RamfuncsLoadStart),
LOAD_END(_RamfuncsLoadEnd),
RUN_START(_RamfuncsRunStart),
PAGE = 0

.bss : > RAML4, PAGE = 0
.ebss : > RAML4, PAGE = 0
.far : > RAML4, PAGE = 0
.reset : > RESET, PAGE = 0, TYPE = DSECT
.data : > RAML4, PAGE = 0
.cio : > RAML4, PAGE = 0
.sysmem : > RAML4, PAGE = 0
.esysmem : > RAML4, PAGE = 0
.stack : > RAMM0M1, PAGE = 0
.rtdx_data : > RAML4, PAGE = 0

.mySectionName: LOAD = FLASH1, RUN = RAML4, PAGE = 0, LOAD_START(__initmySectionName), RUN_START(__runmySectionName)

}

To gather the Run address of the variable has been, so far, trivial.  It is neatly populated in the _runmySectionName in every compile; however the location, in flash/init, of any variables placed in .mySectionName remains unknown, as at the linker stage the following is returned: 

LOAD placement ignored for ".mySectionName":  object is uninitialized

The variables are indeed being initialized by the .cinit table at startup by the startup assembly code provided by TI; but my objective is to prevent the variables from being placed in that region of memory.  

A solution I have seen is to declare the variables in this section as 'const'; which does indeed provide a load and a run address - however that doesn't satisfy my needs - as the variables can be altered by the running program during runtime.  These values are initial-values which can be updated as runtime moves forward.

  • I'd like to be able to modify some global values in the output binary - without recompiling.

    I'll refine that a bit more.  You want to modify the initialization values of some global variables without recompiling.  I can think of a method for doing that.  But, you may conclude that recompiling is easier.

    Because ...

    the variables can be altered by the running program during runtime

    ... they cannot reside in flash.  They have to be in RAM.

    When you write ...

    int variable_in_ram = 25;

    ... variable_in_ram is located in RAM, and the value 25 (along with other details) is in the section .cinit, which resides in flash.  I suppose you could consider changing the part of .cinit that holds 25.  However, that's quite difficult to implement and maintain. It is easier to write this ...

    const int initialization_value __attribute__((section(".mySectionName"))) = 25;
    int variable_in_ram;
    
    void function_called_early()
    {
        variable_in_ram = initialization_value;
    }

    Then use the techniques described in this forum post to modify the bytes in the output binary for the const variable initialization_value.  

    To arrange for function_called_early to be called before main starts, call it from the boot hook function _system_post_cinit.  To learn more about this function, please search for it in the C28x compiler manual.

    Thanks and regards,

    -George

  • Your refinement in the question I asked is accurate. 

    So to clarify an off-point of what you've outlined: There isn't a way for me to (at least not through assigning a variable's section) retrieve both a RAM and LOAD address for a single defined variable in COFF?  

    Meaning: The .cinit section will always be the implied "LOAD" section (the location of the actual initial value) for a variable written as: 

    float sc_PVDD __attribute__((section(".mySectionName"))) = 12.0F ;

    I can either define the location of the constant "12.0" in a known flash/load location or I can know its run/ram location but using a single linker entry will not reveal both, if I understand what your saying?

    For context - we traditionally had compiled in EABI which, not using the same linker structure, was much more pliable in this singular regard. 

    The actual manipulation of the .out file (once this address scheme is resolved) is already a thing that's handled in existing tools - along with the functionality of the _system_post_cinit call, which is handled in our existing code (regardless of the resulting answer found here - its purpose will be to read flash write ram for those init values; and will be indifferent to their literal addresses).

  • we traditionally had compiled in EABI which, not using the same linker structure, was much more pliable in this singular regard.

    With regard to your situation, I don't see any significant differences between EABI and COFF ABI.  Low level details are different.  But there are no conceptual differences.  This causes me to ask:  How do you make it work in EABI?  Please be detailed in your reply.

    Thanks and regards,

    -George

  • I owe the detailed response with example code to you; as your answer functionally provided enough detail for me to generate a working solution but right now that compilation is several environment iterations old and will be difficult for me to go back to just this minute. 

    However; I will say that the procedure was to execute the TI document describing migration from COFF to EABI. 

    After having executed that document completely - the same section declaration i've noted above; will produce a Load address that points to the initialization of the variable and the RUN location - pointing to the ram address after initialization.  I took it for granted that this was typical functionality - but now can only assume that this is due to a paraphrased comment about the EABI link processing being direct vs the COFF link.  

    But, again: These details are admittedly vague.  It became clear in this project that the EABI migration process was flawed for reasons outside the linkers control and our code base and so the result is returning to this COFF configuration.