Sysprogs forums › Forums › VisualGDB › BIN file size ecxeeds flash size with no error
- This topic has 8 replies, 2 voices, and was last updated 5 years, 8 months ago by support.
-
AuthorPosts
-
March 11, 2019 at 06:38 #24190wtywtykkParticipant
Hello,
I found that the compiler/linker stores the initial value of the variables just after code area in the flash. But the size of this area is not taken into account when linking. So the actual BIN file size can exceed the size of the flash, without triggering any warnings or errors. However, under this condition, the initial values are actually placed outside the flash and will be missing at runtime.
Procedures to reproduce the problem:
1. Create a project with a low density mcu (i.e. stm32f030)
2. Write lots of code, trying to use every bytes in the flash. You can also declare a large constant array to occupy the area.
3. Declare a large non-constant array with initial values.
4. Compile.
5. The code should compile. The memory report will look like this:
1>——————- Memory utilization report ——————-
1>Used FLASH: 17KB out of 16KB (100%)
1>Used SRAM: 2036 bytes out of 4096 bytes (49%)Clearly that’s not right. The actual BIN file is larger than 16K.
The demonstration project is attached. (Edit: I failed to upload it, so I put the file to https://pan.baidu.com/s/1SuToeenDg9T6_gxF1PkyDg . The extration code(password) is “ch6p” (without the quotation marks) .)
I suspect that’s a linker bug or a problem with the linker script. But I’m not familar with the linker script so that’s all I can investigate.
March 11, 2019 at 17:05 #24199supportKeymasterHi,
Most likely the new variable gets optimized away or placed into a different section. Please try following our linker script tutorial to familiarize yourself with customizing the linker-related settings and techniques used to troubleshoot them.
March 12, 2019 at 17:54 #24217wtywtykkParticipantHi,
The variables aren’t optimized away or placed into a different section. Normally they are placed after the code and copied to sram by a for loop in the Reset_Handler. But in this case, they are simply placed outside the flash because there are no room left.
It turns out that the original linker script makes the linker unware of the size needed for the initial value area. From the report by objdump, no section is assigned for them, and the linker simply put all the data after the address that symbol “_sidata” points to.
The solution I found is changing the data section description in the linker script to
.data :
{
. = ALIGN(4);
_sdata = .;PROVIDE(__data_start__ = _sdata);
*(.data)
*(.data*)
. = ALIGN(4);
_edata = .;PROVIDE(__data_end__ = _edata);
} > SRAM AT > FLASHNote that the “AT” at the first line is removed and the “AT > FLASH” at the last line is added.
PS: I doesn’t have a board to test this fix for now. But I checked the symbols and sections with objdump, and it seems to work. The linker also shows an error message if the flash isn’t large enough.
PPS: May be the there are still some problems with the ALIGN statements. It’s not fully tested.
March 13, 2019 at 06:19 #24226supportKeymasterThanks for sharing this. We will investigate it and get back to you in the next 24 hours.
March 13, 2019 at 23:21 #24233supportKeymasterOK, we have tried reproducing this issue with the default linker script file for STM32F030F4 (unfortunately, the project link you shared does not work without a login and generally we are not able to review the code/projects that does not come from us unless it triggers bugs in VisualGDB itself), using several variations of the attributes. Generally, unless you declare the variable as volatile, gcc optimizes it away (you can verify it with the offline disassembly). If you do declare it as volatile, you do get a linker error as expected.
We have used the following definition (tried data/rodata and also with/without const):
volatile __attribute__((section(".rodata"))) const char g_LargeVar[32 * 1024] = {1, 2, 3}; int main() { volatile int test = g_LargeVar[0]; }
Please double-check if you can reproduce the problem with the default linker script coming from our STM32 BSP and with minimal modifications to the default LEDBlink source (i.e. just adding one global variable and the line accessing it). If not, the problem is likely caused by some other setting specific to your project.
March 14, 2019 at 03:24 #24244wtywtykkParticipantHi,
I’m sorry. I just forgot the fact that I can just put the code here…. The code is based on the LEDBlink project for stm32f030f4.
#include <stm32f0xx_hal.h> #include <stm32_hal_legacy.h> const uint8_t Large_Const_Array[1024 * 13 + 256] = { 0 }; uint8_t Large_Nonconst_Array[2000] = { 0x00,0x01,0x03,0x04,0x05 }; #ifdef __cplusplus extern "C" #endif void SysTick_Handler(void) { HAL_IncTick(); HAL_SYSTICK_IRQHandler(); } int main(void) { HAL_Init(); __GPIOC_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_PIN_12; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; GPIO_InitStructure.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); uint32_t i = 0; for (;;) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET); HAL_Delay(500); HAL_Delay(Large_Const_Array[(i++) % sizeof(Large_Const_Array)]);//Just prevent the array from being optimized out HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET); HAL_Delay(500); HAL_Delay(Large_Nonconst_Array[i % sizeof(Large_Nonconst_Array)]);//Just prevent the array from being optimized out } }
- This reply was modified 5 years, 8 months ago by support. Reason: formatting
March 15, 2019 at 01:58 #24267supportKeymasterNo problem. We have investigated this and confirm that the syntax used in the VisualGDB-supplied linker scripts indeed does not check for FLASH overflow when placing the initialization data for RAM sections.
We have done several tests with the “> SRAM AT > FLASH” syntax and confirm that it solves the problem and is otherwise equivalent to the old one, so we have updated our linker script generation tool to use the new syntax and also changed the logic used by the “Additional Memories” page in VisualGDB.
The next STM32 BSP update will include the linker scripts using the new syntax. As a workaround until then, please consider editing them manually, although the only difference in behavior would be the error message for FLASH overflows caused by the RAM initialization data (regular FLASH and RAM overflows are still reported correctly with both linker script versions).
Thanks for providing detailed repro steps and sorry for the confusion – we have previously encountered many cases when the unexpected image layout was caused by optimization and have never received any reports on issues caused by the VisualGDB’s linker script format.
March 18, 2019 at 08:40 #24312wtywtykkParticipantHi,
Bad news. The new syntax has some new problem. The “_sidata” symbol points to a wrong address when the “Ignore standard libraries (-nostdlib)” option is turned on in the project properties. I do find an solution to this (using LOADADDR() ), but I’m not confident about it. I’ll test my modification with my previous projects and some special cases.
However I suspect whether it’s worth taking the risk to change a stable code. May be the linker script should remain untouched.
March 18, 2019 at 17:03 #24319supportKeymasterWe did actually use LOADADDR in our tests and the new generator – this is the proper documented way to get the load address of a section (i.e. the location of the section values stored in FLASH) and it worked reliably in several different configurations.
-
AuthorPosts
- You must be logged in to reply to this topic.