Skip to main content
Senior
Oct 17, 2025 8:44 AM UTC
Solved

Build Fails after Updating STM32CubeIDE from 1.14.0 to 1.19.0

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

 

This topic has been closed for replies.
ChaoBest answer
Senior
Oct 17, 2025 7:17 PM UTC

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 ?

6 replies

ChaoAuthor
Senior
Oct 17, 2025 8:46 AM UTC

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
Oct 17, 2025 9:31 AM UTC

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
Oct 17, 2025 12:55 PM UTC

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
Oct 17, 2025 7:17 PM UTC

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
Oct 18, 2025 8:20 AM UTC

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.