Reputation: 643
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