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.

Compiler/TM4C1294NCPDT: using CODE_SECTION and RUN_START giving wrong address

Part Number: TM4C1294NCPDT

Tool/software: TI C/C++ Compiler

I like to setup a group of function to a specific memory by using the pragma CODE_SECTION

In the source file I used the CODE_SECTION pragma like this

#pragma CODE_SECTION(initBuffer, "my_sect")
void initBuffer(void);

In the linker cmd file I made a section

 my_sect:   > FLASH, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart)

and the map file looks like this

my_sect    0    00000f9c    00000014     
                  00000f9c    00000014     test_sm.obj (my_sect:initBuffer)

...

address   name                           
-------   ----

00000f9d  initBuffer   

My problem now is that the function initBuffer() is at the address 0xF9D but the variable _RamfuncsRunStart or even _RamfuncsLoadStart have the address 0xF9C.

If I try to run the functions like this

uint32_t _RamfuncsLoadStart;
uint32_t _RamfuncsLoadEnd;
uint32_t _RamfuncsRunStart;

typedef void (*fctCall)();
fctCall fCall;

extern void initBuffer(void);

void testFctCall(void)
{
    fCall = initBuffer; // works
    fCall();

    fCall = (fctCall)&_RamfuncsRunStart; // works not
    fCall();
}

will not work.

  • Rene H. said:
    My problem now is that the function initBuffer() is at the address 0xF9D but the variable _RamfuncsRunStart or even _RamfuncsLoadStart have the address 0xF9C.

    In the ARM-v7 architecture the least significant bit in the branch address of a BX or BLX instruction sets the target state. If the branch address bit 0 is zero the processor changes to, or remains in, ARM state. If the branch address bit 0 is one the processor changes to, or remains in, Thumb state.

    The Cortex-M4 which implements the ARM-v7M architecture only supports Thumb state, and attempting to enter ARM state causes a usage fault - see Branch instructions in the Cortex-M4 Devices Generic User Guide.

    Therefore, while the initBuffer function is placed at address 0xF9C in flash (bit 0 is zero), the branch address must be address 0xF9D (bit 0 is one). That is why the fCall = (fctCall)&_RamfuncsRunStart statement will cause the fCall() to fail.

  • Thanks for this explanation.

    But why has RamfuncsRunStart the wrong address?
    And is there something that I could do to get it running?
  • Rene H. said:
    But why has RamfuncsRunStart the wrong address?

    RamfuncsRunStart has the correct address, with bit 0 cleared, to give the start address to which the code must be copied to.

    Rene H. said:
    And is there something that I could do to get it running?

    When converting the RamfuncsRunStart to a function pointer you need to set bit zero to ensure Thumb mode is used. E.g.:

        /* Set bit zero of the target address to ensure Thumb mode is used */
        fCall = (fctCall)(((size_t)&_RamfuncsRunStart) | 1);
        fCall();

    I have attached an example project for a TM4C1294NCPDT which demonstrates this, including copying the initBuffer function from FLASH to SRAM.

    TM4C_code_section.zip

  • Thanks. That works fine.

    Is it possible that one function is executed in Thumb mode and an other one in ARM state?
    Should I take care of the execution mode by my self or could I use this workaround for all functions?
  • Rene H. said:
    Is it possible that one function is executed in Thumb mode and an other one in ARM state?

    Cortex-M devices such as theTM4C1294NCPDT  only support Thumb mode, and so it is not possible to execute functions in ARM mode.

    Whereas Cortex-A based devices to allow mixed execution of Thumb and ARM states.

    Rene H. said:
    Should I take care of the execution mode by my self or could I use this workaround for all functions?

    The normal use case is making use of function pointers by getting the address of the function symbolic name, such as the statement fCall = initBuffer; where the compiler and linker handle setting of the bit zero of the address to control selection of Thumb and ARM states.

    What was the reason for trying to use fCall = (fctCall)&_RamfuncsRunStart; ?

  • Thanks for clearing that behavior.

    My intention is to have a memory block with functions (pointers) that I could easily iterate.

    But I don't want to initialize an array because the functions could be in every module of my project.

    And I don't want a fixed length array because the amount of functions could change.

    What I want is a list of pointers like

    pInitBufferA
    pInitBufferB
    ....
    pInitBufferL
    pInitBufferM
    etc.

    and iterate through this by

    fCall = (fctCall)&_RamfuncsRunStart;
    fCall();
    fCall++;
    fCall();

    until the end of the memory block

    I tried it already with DATA_SECTION like this

    #pragma DATA_SECTION(pInitBuffer, "my_sect")
    void initBuffer(void);
    uint32_t *pInitBuffer = (uint32_t*)initBuffer;

    But the memory area in the map file is UNINITIALIZED

    my_sect    0    20000000    00000000     UNINITIALIZED

    while the function is still in the project.

    000004ed  initBuffer

    So my next trail was CODE_SECTION that end with this question here.

    With your help I realized now that I couldn't iterate through this memory block with CODE_SECTION this.

    Do you have some more ideas to solve this?

    I saw this kind of logic in an other ARM project (not a TI one). It was also done with DATA_SECTION but the original ARM compiler.

  • Chester - I got it.

    I have to use the RETAIN pragma or the compiler removes the pointer pInitBuffer.

    Thank you very much, your explanations help me a lot to get more into this topic.


    #include <stdint.h> #include <string.h> char bufferA[20]; char bufferB[20]; typedef void (*fctCall)(); fctCall fCall; void initBufferA(void); #pragma RETAIN(pInitBufferA) #pragma DATA_SECTION(pInitBufferA, "my_sect") fctCall pInitBufferA = initBufferA; void initBufferB(void); #pragma RETAIN(pInitBufferB) #pragma DATA_SECTION(pInitBufferB, "my_sect") fctCall pInitBufferB = initBufferB; //********************************************* void initBufferA(void) { memset (bufferA, 0xee, sizeof (bufferA)); } void initBufferB(void) { memset (bufferB, 0x55, sizeof (bufferB)); } //********************************************* uint32_t _MySectLoadStart; uint32_t _MySectLoadEnd; int main(void) { uint32_t *fctCallPointer = &_MySectLoadStart; while(fctCallPointer < &_MySectLoadEnd) { fCall = (fctCall)(*fctCallPointer++); fCall(); } return 0; }

    And this line in the linker command file

    my_sect:   > SRAM LOAD_START(_MySectLoadStart), LOAD_END(_MySectLoadEnd)

  • Rene H. said:
    My intention is to have a memory block with functions (pointers) that I could easily iterate.

    But I don't want to initialize an array because the functions could be in every module of my project.

    And I don't want a fixed length array because the amount of functions could change.

    In the thread How to correctly declare initialized data into FLASH using C/C++ there is another example which may help you.