Using the GNU Linker Script to know the FLASH and RAM Areas in the Application

Sometimes it is handy to know in the running application the start address, end address and the size of a linked section, e.g. to know the boundaries of RAM or FLASH areas. This means that from the application code I can get access to knowledge of the GNU linker:

Information about Linker Sections

Information about Linker Sections

To access the section information from the GNU linker script is pretty easy and simple. For example in my GNU linker file I have the following memory mapping:

MEMORY {
 m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000198
 m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x000FFBF0
 m_data_1FFF0000 (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000
 m_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000
 m_cfmprotrom (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
}

I can define additional symbols inside the SECTIONS part of the linker script like this to know the boundaries and size of the m_text MEMORY area:

SECTIONS {
  /* other section placement here. */

  __m_text_start = ORIGIN(m_text);
  __m_text_end = ORIGIN(m_text)+ LENGTH(m_text);
  __m_text_size = LENGTH(m_text);
}

ORIGIN() will return the start address of the section and LENGTH() the size of the section, and I can do basic arithmetic too. The linker generated symbols will have an address.

To use them from the application code, I have to declare them like this:

/* the following symbols are defined in the GNU linker script */
extern int *__m_text_start;
extern int *__m_text_end;
extern int *__m_text_size;

Taking the address of these symbols will return the address information. To build a string with the address information I can use snprintf() or xsnprintf() (see XFormat, a Lightweight printf() and sprintf() Alternative):

res = XF1_xsnprintf(buffer, sizeof(buffer), "Start Addr: 0x%X, End Addr: 0x%X, Size: 0x%X\r\n", &__m_text_start, &__m_text_end, &__m_text_size);

With this I get the start and end address plus the section size I can use in my application:

Information about Linker Sections

Information about Linker Sections

Happy Linking 🙂

Links

9 thoughts on “Using the GNU Linker Script to know the FLASH and RAM Areas in the Application

    • Hi Juan,
      it really does not matter: it is a linker symbol (from which I can take the address) but the symbol itself has no type or size. So it could be a char, enum, struct or whatever. I usually declare it as a pointer or as a int type.

      Like

  1. Hi Erich,
    Just had a problem making a few changes to my big project…
    Got the error something like _user_heap_stack does not fit into m_data : something something overfull by 52 bytes.

    I’m using a K22FX512 for this, and KDS cannot generate the right linker file because it doesn’t understand that the FX has 128K SRAM in 2 64K segments. I’ve been running all along on a hand modified linker file with no problems til now.
    So, I figure since I just added a big array, I just have to cut down the size of that by 52 bytes or more. I do so, but no change, still 52 bytes over.
    I actually went trimming a lot of types of memory, even reducing the size of my FRTOS task stacks, but nothing changed that 52 bytes. I finally went into the linker file and cut the __stack_size from 0x3000 to 0x2F00 and that worked.

    So the question is what should I be doing and what should I have for the __heap_size and __stack_size ?

    (I have the FRTOS heap set to m_data_2000000 and malloc most of my big structures from that, but the data I just added is a two dimensional array of chars statically declared as, uint8 biff[16][80]; How would I use a pointer that came from malloc for a 2d array? )

    Will/has NXP fixed KDS so it can generate the linker for the FX512 correctly?

    Brynn

    Like

    • Hi Brynn,
      if you are not using the standard library malloc(), then you could have a __heap_size of zero too. It is just that some other standard library functions (e.g. printf() with newlib) might use it too. If you are using the FreeRTOS malloc(), then it will use the FreeRTOS heap (unless you are using the FreeRTOS memory scheme 3 which is a wrapper to malloc()/free() of the standard library.

      The stack size with 0x3000 is very high. You only need some stack during main() until the RTOS is started. I usually have 0x100 there. Depending what you do in main(), this might be even smaller.

      As for the Processor Expert wrong memory map: I use the workaround described in https://mcuoneclipse.com/2012/03/23/disable-my-code-generation/: I let Processor Expert generate the linker file initially, then turn off linker file generation and have my linker file modified.

      I hope this helps,
      Erich

      Like

  2. Hi Erich,
    Another thing that I am not sure if there is a solution to, is that the ‘size’ command doesn’t run when the linker fails, so getting those hints of where the memory got used is not provided. I presume it doesn’t have a file to work from – but it would be nice if it was more clear what memories got used up in the case of a failed link.

    Brynn

    Like

  3. Hello Erich,

    My linker file contains the folllowing
    —————————————————
    _dataramLower_end = .;
    .data_RAM2 : ALIGN(4)
    {
    FILL(0xff)
    PROVIDE(__start_data_RAM2 = .) ;
    *(.ramfunc.$RAM2)
    *(.ramfunc.$SRAM_LOWER)
    *(.data.$RAM2*)
    *(.data.$SRAM_LOWER*)
    . = ALIGN(4) ;
    PROVIDE(__end_data_RAM2 = .) ;
    } > SRAM_LOWER AT>PROGRAM_FLASH
    _dataramLower_end = .;
    —————————————————
    My source code contains the following:
    —————————————————
    #define BL_SIZE2 (((uint32_t)&__end_data_RAM2) – ((uint32_t)&__start_data_RAM2))
    #define BOOTLOADER_BLOCK_SIZE (BL_SIZE2)
    const ImageId_t BImageInfo = {
    .Size = BOOTLOADER_BLOCK_SIZE,
    };
    —————————————————
    I get the following compile error in eclipse:
    ——————————————————
    ..\source\BootloaderId.c:30:32: error: initializer element is not constant
    #define BOOTLOADER_BLOCK_SIZE (BL_SIZE2)
    ^
    ..\source\BootloaderId.c:48:23: note: in expansion of macro ‘BOOTLOADER_BLOCK_SIZE’
    .Size = BOOTLOADER_BLOCK_SIZE,
    ^~~~~~~~~~~~~~~~~~~~~
    ..\source\BootloaderId.c:30:32: note: (near initialization for ‘g_BootloaderImageInfo.Size’)
    #define BOOTLOADER_BLOCK_SIZE (BL_SIZE2)
    ^
    ——————————————————
    Any suggestions are welcome! I am struggling with this one!
    Cheers,
    Paul

    Like

    • Hi Paul,
      “initializer element is not constant”
      The compiler is correct: your BL_SIZE2 macro is not a constant expression at compile time (it is a substraction of two addresses which are not known at compile time), so it cannot be used that way in your source code.
      Arrays need to be defined with a constant size known at compile time.

      Like

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.