MulattoKid
MulattoKid

Reputation: 643

Force .bss section to be in last program header

I'm wondering if it's possible to force the .bss section (or any section for that matter) to be put in the last program header in my linker script, or using some other tool after linking?

My issue is that when changing my source code (adding in the use of AT_NONCACHEABLE_SECTION_INIT from NXP's SDK), .bss is moved from the last program header to an earlier one. When this happens, the integrity check our bootloader runs before booting the FW fails. The reason for this is that when using the Cortex-Debug extension in VSCode to flash the FW, the .bss section isn't flashed, and thus the flash where .bss should be remains at the flash's erased value (0xFF), whereas the binary that's built has the .bss section set to all 0x00, resulting in the SHA256 of the binary and the flash differing.

However, if .bss (and other uninitialized sections) are placed in the last program header, this works fine as objcopy doesn't include these sections when extracting the binary from the ELF.

A solution could be to change the contents of the .bss section to 0xFF, but that isn't ideal wrt. performing over-the-air updates, as there would effectively be an empty part of the binary that is transmitted (decreases with delta updates, but still not ideal).

For reference, this is what my program header and segments looked like before:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x60010000 0x60010000 0x00100 0x00100 RW  0x10000
  LOAD           0x010100 0x60010100 0x60010100 0x00400 0x00400 R   0x10000
  LOAD           0x010500 0x60010500 0x60010500 0x0ad70 0x0ad70 RWE 0x10000
  LOAD           0x020000 0x20000000 0x6001b270 0x000a0 0x03a58 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .image_header 
   01     .interrupts 
   02     .text .ARM .init_array .fini_array 
   03     .data .ram_function .bss .heap .stack 

and this is after adding in the use of AT_NONCACHEABLE_SECTION_INIT:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x60010000 0x60010000 0x00100 0x00100 RW  0x10000
  LOAD           0x010100 0x60010100 0x60010100 0x00400 0x00400 R   0x10000
  LOAD           0x010500 0x60010500 0x60010500 0x0ad70 0x0ad70 RWE 0x10000
  LOAD           0x020000 0x20000000 0x6001b270 0x000a0 0x02a58 RW  0x10000
  LOAD           0x030000 0x20200000 0x6001b370 0x00800 0x00800 RW  0x10000
  LOAD           0x002a58 0x20002a58 0x6001dcc8 0x00000 0x00800 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .image_header 
   01     .interrupts 
   02     .text .ARM .init_array .fini_array 
   03     .data .ram_function .bss 
   04     .ncache.init 
   05     .heap .stack 

Notice how .ncache.init splits .bss from .heap and .stack.

And here are the relevant part of my linker script (mostly a direct copy of NXP's default for this processor):

MEMORY
{
  m_image_header          (RX)  : ORIGIN = 0x60010000, LENGTH = 0x00000100
  /* Vector table has room for 256 entries, each being 4 bytes = 1024 bytes = 0x400 */
  m_interrupts            (RX)  : ORIGIN = 0x60010100, LENGTH = 0x00000400
  /* Actual application flash uses remaining of BOOT partition */
  m_text                  (RX)  : ORIGIN = 0x60010500, LENGTH = 0x0001FB00

  /* RAM */
  m_data                  (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00020000
  m_ncache                (RX)  : ORIGIN = 0x20200000, LENGTH = 0x00040000
  m_data2                 (RW)  : ORIGIN = 0x00000000, LENGTH = 0x00020000
}

SECTIONS
{
  __NCACHE_REGION_START = ORIGIN(m_ncache);
  __NCACHE_REGION_SIZE  = LENGTH(m_ncache);

  .image_header :
  {
      KEEP(*(.image_header))
  } > m_image_header

  .interrupts :
  {
    __VECTOR_TABLE = .;
    __Vectors = .;
    . = ALIGN(4);
    KEEP(*(.isr_vector))     /* Startup code */
    . = ALIGN(4);
  } > m_interrupts

  .text :
  {
    . = ALIGN(4);
    KEEP(*(.flash_config))
    *(EXCLUDE_FILE(
        /* Exclude flash operation functions. */
        */mflash_drv.c.obj
        */fsl_flexspi.c.obj
        */fsl_cache.c.obj
    ) .text)                 /* .text sections (code) */
    *(EXCLUDE_FILE(
        /* Exclude flash operation functions. */
        */mflash_drv.c.obj
        */fsl_flexspi.c.obj
        */fsl_cache.c.obj
    ) .text*)                /* .text* sections (code) */
    *(EXCLUDE_FILE(
        /* Exclude flash operation functions. */
        */mflash_drv.c.obj
        */fsl_flexspi.c.obj
        */fsl_cache.c.obj
    ) .rodata)               /* .rodata sections (constants, strings, etc.) */
    *(EXCLUDE_FILE(
        /* Exclude flash operation functions. */
        */mflash_drv.c.obj
        */fsl_flexspi.c.obj
        */fsl_cache.c.obj
    ) .rodata*)              /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)               /* glue arm to thumb code */
    *(.glue_7t)              /* glue thumb to arm code */
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
  } > m_text

  .ARM.extab :
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } > m_text

  .ARM :
  {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } > m_text

 .ctors :
  {
    __CTOR_LIST__ = .;
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
    __CTOR_END__ = .;
  } > m_text

  .dtors :
  {
    __DTOR_LIST__ = .;
    KEEP (*crtbegin.o(.dtors))
    KEEP (*crtbegin?.o(.dtors))
    KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
    __DTOR_END__ = .;
  } > m_text

  .preinit_array :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } > m_text

  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } > m_text

  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } > m_text

  __etext = .;    /* define a global symbol at end of code */
  __DATA_ROM = .; /* Symbol is used by startup for data initialization */

  .interrupts_ram :
  {
    . = ALIGN(4);
    __VECTOR_RAM__ = .;
    __interrupts_ram_start__ = .; /* Create a global symbol at data start */
    *(.m_interrupts_ram)     /* This is a user defined section */
    . += VECTOR_RAM_SIZE;
    . = ALIGN(4);
    __interrupts_ram_end__ = .; /* Define a global symbol at data end */
  } > m_data

  __VECTOR_RAM = DEFINED(__ram_vector_table__) ? __VECTOR_RAM__ : ORIGIN(m_interrupts);
  __RAM_VECTOR_TABLE_SIZE_BYTES = DEFINED(__ram_vector_table__) ? (__interrupts_ram_end__ - __interrupts_ram_start__) : 0x0;

  .data : AT(__DATA_ROM)
  {
    . = ALIGN(4);
    __DATA_RAM = .;
    __data_start__ = .;      /* create a global symbol at data start */
    *(m_usb_dma_init_data)

    /* Explicitly place flash operation functions in RAM. */
    */mflash_drv.c.obj(.text .text* .rodata .rodata*)
    */fsl_flexspi.c.obj(.text .text* .rodata .rodata*)
    */fsl_cache.c.obj(.text .text* .rodata .rodata*)

    *(.data)                 /* .data sections */
    *(.data*)                /* .data* sections */
    *(DataQuickAccess)       /* quick access data section */
    KEEP(*(.jcr*))
    . = ALIGN(4);
    __data_end__ = .;        /* define a global symbol at data end */
  } > m_data

  __ram_function_flash_start = __DATA_ROM + (__data_end__ - __data_start__); /* Symbol is used by startup for TCM data initialization */

  .ram_function : AT(__ram_function_flash_start)
  {
    . = ALIGN(32);
    __ram_function_start__ = .;
    *(CodeQuickAccess)
    . = ALIGN(128);
    __ram_function_end__ = .;
  } > m_data

  __NDATA_ROM = __ram_function_flash_start + (__ram_function_end__ - __ram_function_start__);
  .ncache.init : AT(__NDATA_ROM)
  {
    __noncachedata_start__ = .;   /* create a global symbol at ncache data start */
    *(NonCacheable.init)
    . = ALIGN(4);
    __noncachedata_init_end__ = .;   /* create a global symbol at initialized ncache data end */
  } > m_ncache
  . = __noncachedata_init_end__;
  .ncache :
  {
    *(NonCacheable)
    . = ALIGN(4);
    __noncachedata_end__ = .;     /* define a global symbol at ncache data end */
  } > m_ncache

  __DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__);
  text_end = ORIGIN(m_text) + LENGTH(m_text);
  ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data")

  .bss :
  {
    . = ALIGN(4);
    __START_BSS = .;
    __bss_start__ = .;
    *(m_usb_dma_noninit_data)
    *(.bss)
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    __bss_end__ = .;
    __END_BSS = .;
  } > m_data

  .heap :
  {
    . = ALIGN(8);
    __end__ = .;
    PROVIDE(end = .);
    __HeapBase = .;
    . += HEAP_SIZE;
    __HeapLimit = .;
    __heap_limit = .; /* Add for _sbrk */
  } > m_data

  .stack :
  {
    . = ALIGN(8);
    . += STACK_SIZE;
  } > m_data
}

Upvotes: 0

Views: 66

Answers (0)

Related Questions