Skip to main content
Senior
October 17, 2025
Solved

Build Fails after Updating STM32CubeIDE from 1.14.0 to 1.19.0

  • October 17, 2025
  • 2 replies
  • 556 views

Hi

Just hours ago, I updated the IDE from 1.14.0 to the latest version 1.19.0, a build on the project I have been working on fails by RAM and Flash overflow. This issue has been resolved before the IDE update. 

Check the 2 map files, I found the (NOLOAD) in the linker script has no effect in the new IDE.

The error message from the linker:

 

Chao_0-1760690285209.png

 

The F767 board is customized with 32MB external SDRAM, memory map and sections are defined as below:

 

MEMORY
{
 MEM3BASE (xrw) : ORIGIN = 0X20000000, LENGTH = 60K
 MEM3MAP (xrw) : ORIGIN = 0x2000F000, LENGTH = 4K
 MEM1BASE (xrw) : ORIGIN = 0x20010000, LENGTH = 160K
 MEM1MAP (xrw) : ORIGIN = 0x20038000, LENGTH = 10K
 RAM (xrw) : ORIGIN = 0x2003A800, LENGTH = 512K-234K
 FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
 LCD_BUF (xrw) : ORIGIN = 0XC0000000, LENGTH = 2000K
 MEM2BASE (xrw) : ORIGIN = 0XC01F4000, LENGTH = 28912K
 MEM2MAP (xrw) : ORIGIN = 0XC1E30000, LENGTH = 1807K
 MEM4BASE (xrw) : ORIGIN = 0xC1FF3C00, LENGTH = 49K
}

/* After the .data section: */

 .mem1_base (NOLOAD):
 {
 . = ALIGN(64);
 mem1base = .; /* create a global symbol at data start */
 } >MEM1BASE

 /* Place array mem1mapbase into internal memory MEM1 region */
 .mem1_map (NOLOAD):
 {
 . = ALIGN(4);
 mem1mapbase = .; /* create a global symbol at data start */
 } >MEM1MAP

 /* Place array mem2base into external SDRAM memory MEM2 region */
 .mem2_base (NOLOAD):
 {
 . = ALIGN(64);
 mem2base = .; /* create a global symbol at data start */
 } >MEM2BASE

 /* Place array mem2mapbase into external SDRAM memory MEM2 region */
 .mem2_map (NOLOAD):
 {
 . = ALIGN(4);
 mem2mapbase = .; /* create a global symbol at data start */
 } >MEM2MAP

 /* Place array ltdc_lcd_framebuf into external SDRAM memory LTDC_FRAME_BUF region */
 .lcd_buffer (NOLOAD):
 {
 . = ALIGN(4);
 ltdc_lcd_framebuf = .; /* create a global symbol at data start */
 } >LCD_BUF

 /* Place array mem3base into internal memory MEM3 region */
 .mem3_base (NOLOAD):
 {
 . = ALIGN(64);
 mem3base = .; /* create a global symbol at data start */
 } >MEM3BASE

 /* Place array mem3mapbase into internal memory MEM3 region */
 .mem3_map (NOLOAD):
 {
 . = ALIGN(4);
 mem3mapbase = .; /* create a global symbol at data start */
 } >MEM3MAP

 /* Place array mem2base into external SDRAM memory MEM2 region */
 .mem4_base (NOLOAD):
 {
 *(.mem4_base*); /* create a global symbol at data start */
 } >MEM4BASE

 

In C files:

 

__attribute__((section(".lcd_buf"))) uint16_t ltdc_lcd_framebuf[1280][800];

// mem1base (internal RAM,160KB,64 bytes alignment) address = 0x20010000 ~ 0x20037FFF
__attribute__((section(".mem1_base"))) static uint8_t mem1base[160 * 1024] = { 0 };

// mem2base (external SDRAM,30MB,address = 0xC01F4000 ~ 0xC1E2FFFF,64 bytes alignment )
// the first 2MB is used by LTDC (1280*800*2)
__attribute__((section(".mem2_base"))) static uint8_t mem2base[28912 * 1024] = { 0 };

// mem3base (internal RAM, 60KB, address = 0x20000000 ~ 0x2000EFFF,64 bytes alignment)
__attribute__((section(".mem3_base"))) static uint8_t mem3base[60 * 1024] = { 0 };

/* memory management tables */

// mem1mapbase (internal RAM,10KB,address = 0x20038000 ~ 0x2003A7FF,64 bytes alignment)
__attribute__((section(".mem1_map"))) static uint32_t mem1mapbase[160 * 1024 / 64] = { 0 };

// mem2mapbase (external SDRAM,1807K,address = 0xC1E30000 ~ 0xC1FF3BFF,64 bytes alignment )
__attribute__((section(".mem2_map"))) static uint32_t mem2mapbase[28912 * 1024 / 64] = { 0 };

// mem3mapbase (internal RAM,4KB,address = 0x2000F000 ~ 0x2000FFFF,64 bytes alignment)
__attribute__((section(".mem3_map"))) static uint32_t mem3mapbase[60 * 1024 / 64] = { 0 };

 

mem4_based region is used for absolute addressing for some variables, such as:

 

/* variable definitions for a circular buffer placed in the external SDRAM: */
/* byte and uint are defined as uint8_t and uint32_t */
 byte* powerOn; 
 byte* buffer; 
 uint* numBytesLeft;
 uint* rdAddr; 
 uint* wrAddr; 
 byte* status; 

/* initializations */

void BufferX::Init()
{
 powerOn = (byte*) POWER_ON_FLAG_ADDR; /* SDRAM Location: 0xC1FF3C00 */
 buffer = (byte*) DBG_PRINT_BUFFER_START_ADDR; /* SDRAM Location: 0xC1FF5000 */
 rdAddr = (uint*) DBG_BUFFERX_READ_ADDR; /* SDRAM Location: 0xC1FF3C30 */ 
 wrAddr = (uint*) DBG_BUFFERX_WRITE_ADDR; /* SDRAM Location: 0xC1FF3C34 */
 status = (byte*) DBG_BUFFERX_STATUS_ADDR; /* SDRAM Location: 0xC1FF3C0C */
 numBytesLeft = (uint*) DBG_BUFFERX_NUM_BYTES_LEFT_ADDR; /* SDRAM Location: 0xC1FF3C38 */
	if (*powerOn != 0xAA)
	{	// MCU power on
	 *rdAddr = 0;
	 *wrAddr = 0;
	 *status = BUFFER_EMPTY;
	 *numBytesLeft = 0;
	}
 overflowPrintable = true;
}

 

Map file by CubeIDE V1.14.0:

 

.mem1_base 0x0000000020010000 0x28000
 0x0000000020010000 . = ALIGN (0x40)
 0x0000000020010000 mem1base = .
 .mem1_base 0x0000000020010000 0x28000 ./ThirdParty/MALLOC/malloc.o

.mem1_map 0x0000000020038000 0x2800
 0x0000000020038000 . = ALIGN (0x4)
 0x0000000020038000 mem1mapbase = .
 .mem1_map 0x0000000020038000 0x2800 ./ThirdParty/MALLOC/malloc.o

.mem2_base 0x00000000c01f4000 0x1c3c000
 0x00000000c01f4000 . = ALIGN (0x40)
 0x00000000c01f4000 mem2base = .
 .mem2_base 0x00000000c01f4000 0x1c3c000 ./ThirdParty/MALLOC/malloc.o

.mem2_map 0x00000000c1e30000 0x1c3c00
 0x00000000c1e30000 . = ALIGN (0x4)
 0x00000000c1e30000 mem2mapbase = .
 .mem2_map 0x00000000c1e30000 0x1c3c00 ./ThirdParty/MALLOC/malloc.o

.lcd_buffer 0x00000000c0000000 0x0
 0x00000000c0000000 . = ALIGN (0x4)
 0x00000000c0000000 ltdc_lcd_framebuf = .

.mem3_base 0x0000000020000000 0xf000
 0x0000000020000000 . = ALIGN (0x40)
 0x0000000020000000 mem3base = .
 .mem3_base 0x0000000020000000 0xf000 ./ThirdParty/MALLOC/malloc.o

.mem3_map 0x000000002000f000 0xf00
 0x000000002000f000 . = ALIGN (0x4)
 0x000000002000f000 mem3mapbase = .
 .mem3_map 0x000000002000f000 0xf00 ./ThirdParty/MALLOC/malloc.o

.mem4_base
 *(.mem4_base*)
 0x000000002000ff00 . = ALIGN (0x4)

 

Map file by CubeIDE V1.19.0:

 

.mem1_base 0x2003a8b0 0x28000 load address 0x0801c6f4
 .mem1_base 0x2003a8b0 0x28000 ./ThirdParty/MALLOC/malloc.o

.mem2_base 0x200628b0 0x1c3c000 load address 0x080446f4
 .mem2_base 0x200628b0 0x1c3c000 ./ThirdParty/MALLOC/malloc.o

.mem3_base 0x21c9e8b0 0xf000 load address 0x09c806f4
 .mem3_base 0x21c9e8b0 0xf000 ./ThirdParty/MALLOC/malloc.o

.mem1_map 0x21cad8b0 0x2800 load address 0x09c8f6f4
 .mem1_map 0x21cad8b0 0x2800 ./ThirdParty/MALLOC/malloc.o

.mem2_map 0x21cb00b0 0x1c3c00 load address 0x09c91ef4
 .mem2_map 0x21cb00b0 0x1c3c00 ./ThirdParty/MALLOC/malloc.o

.mem3_map 0x21e73cb0 0xf00 load address 0x09e55af4
 .mem3_map 0x21e73cb0 0xf00 ./ThirdParty/MALLOC/malloc.o

.mem1_base 0x20010000 0x0
 0x20010000 . = ALIGN (0x40)
 0x20010000 mem1base = .

.mem1_map 0x20038000 0x0
 0x20038000 . = ALIGN (0x4)
 0x20038000 mem1mapbase = .

.mem2_base 0xc01f4000 0x0
 0xc01f4000 . = ALIGN (0x40)
 0xc01f4000 mem2base = .

.mem2_map 0xc1e30000 0x0
 0xc1e30000 . = ALIGN (0x4)
 0xc1e30000 mem2mapbase = .

.lcd_buffer 0xc0000000 0x0
 0xc0000000 . = ALIGN (0x4)
 0xc0000000 ltdc_lcd_framebuf = .

.mem3_base 0x20000000 0x0
 0x20000000 . = ALIGN (0x40)
 0x20000000 mem3base = .

.mem3_map 0x2000f000 0x0
 0x2000f000 . = ALIGN (0x4)
 0x2000f000 mem3mapbase = .

.mem4_base
 *(.mem4_base*)
 0x2000f000 . = ALIGN (0x4)

 

I wonder why this happens, I would like to receive anyone's suggestions, and especially to invite @TDK  to have a look at this issue as you resolved this issue in IDE version 1.14.0.

Chao

 

Best answer by Chao

By doing some experiments, the following section definitions will pass the project build:

 

 .mem2_base (NOLOAD):
 {
 . = ALIGN(64);
 *(.mem2_base) 
 } >MEM2BASE

 /* and */

 .mem2_base (NOLOAD):
 {
 . = ALIGN(64);
 *(.mem2_base*) 
 } >MEM2BASE

 

Then what are the difference between     *(.mem2_base)     and     *(.mem2_base*) ?  What do they exactly mean ?

2 replies

ChaoAuthor
Senior
October 17, 2025

I missed a warning message from the linker just after the link errors:

../../../arm-none-eabi/bin/ld.exe: warning: Tunnel.elf has a LOAD segment with RWX permissions

Andrew Neil
Super User
October 17, 2025

Going from v1.14.0 to 1.19.0 is quite a jump, so not really surprising that things have changed - in particular, the GCC toolchain version will most likely have changed.

Quite a few previous posts on this "LOAD segment with RWX permissions" warning:

https://community.st.com/t5/forums/searchpage/tab/message?advanced=false&allow_punctuation=false&q=LOAD%20segment%20with%20RWX%20permissions

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
TDK
Super User
October 17, 2025

NOLOAD hasn't changed how it works. Recheck your assumptions. Probably a mismatch in the linker file you're using. Don't see anything wrong in the information you presented--issue is likely elsewhere.

"If you feel a post has answered your question, please click ""Accept as Solution""."
ChaoAuthorBest answer
Senior
October 17, 2025

By doing some experiments, the following section definitions will pass the project build:

 

 .mem2_base (NOLOAD):
 {
 . = ALIGN(64);
 *(.mem2_base) 
 } >MEM2BASE

 /* and */

 .mem2_base (NOLOAD):
 {
 . = ALIGN(64);
 *(.mem2_base*) 
 } >MEM2BASE

 

Then what are the difference between     *(.mem2_base)     and     *(.mem2_base*) ?  What do they exactly mean ?

Andrew Neil
Super User
October 18, 2025

I don't really know, but this would be general GCC linker stuff - not specific to STM32, so any general GCC resources would be applicable...

 

PS:

Where is the official documentation of gnu linker script command language?

Using ld, The GNU linker - Linker Scripts.

via a google search for "gcc linker script".

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.