Weird bug in GCC ARM 32F4 - Page 1
Forum section: electronics / general

author: peter-h
author_rank: Super Contributor
timestamp: December 01, 2021, 10:00:16 pm
content: The code crashes in the sprintf, into one of the illegal instruction traps. However I found that shortly before it, data which is supposed to be initialised on the stack, isn't. AIUI, if you do say int x=2; inside a function, the compiler generates some code which sets up that data, and it puts it on the stack (unless it is declared "static" in which case it goes into, IIRC, BSS).Here the bytes remain 0xFF. Does this make any sense to anybody?The code runs fine when loaded with the STLINK debugger, and has done so for ages. It crashes when loaded from a serial FLASH device, into the CPU FLASH. Then the system reboots (as is necessary) and promptly crashes. Could this data be stored at the very end of the file, and I am failing to load the entire image?Where in the binary would the string MonTue... be stored - for stuff destined for the stack? I guess it is missing. The 0xFF bytes are indicative of an erased FLASH device. SP and PC look good; the stack is at the top of the 128k RAM.

author: langwadt
author_rank: Super Contributor
timestamp: December 01, 2021, 10:10:07 pm
content: look at the disassembly

author: ataradov
author_rank: Super Contributor
timestamp: December 01, 2021, 10:31:22 pm
content: How exactly do you obtain the file that you put into the flash?This constant string will typically go into .rodata section. Where it is located depends on your linker script. With more or less standard linker scripts, all those strings will be located at the end of the binary, after all the code (text) sections.Indeed, look at the disassembly and see what is actually going on.Also, it is not a bug in GCC. It is a bug somewhere in your system. Compiler bugs are much more rare than you think, and chances of you running into one are negligible.

author: peter-h
author_rank: Super Contributor
timestamp: December 01, 2021, 10:51:14 pm
content: Sorry; didn't mean to say it is a bug in GCCIt is a system built with GCC ARM 32F4The file comes from a FAT file system, originally, implemented on the target via USB. But that aspect of the project has been working for 1+ year, until a few weeks ago. Recently it has grown in size (by replacing PolarSSL with MbedTLS) from 170k to 300k and this issue has appeared. My code should support a file up to 510k (size of the entire binary) so that's not the simple answer, but I can see I may be dropping something off the end..Disassembly:I can see the two arrays are initialised to zero with explicit instructions (r5=0 etc). But I can't see how the MonTue... bit gets initialised.In the linkfile, it does indeed look like rodata is loaded after all the codeCode:.main.o :{. = ALIGN(4);KEEP(*(.main.o))*main.o (.text .text* .rodata .rodata*). = ALIGN(4);} >FLASH_APP/* This collects all other stuff, which gets loaded into FLASH after main.o above */.text :{. = ALIGN(4);*(.text) /* .text sections (code) */*(.text*) /* .text* sections (code) */*(.rodata) /* .rodata sections (constants, strings, etc.) */*(.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);_etext = .; /* define a global symbol at end of code */} >FLASH_APPThank you for any pointers, so to speak.

author: ataradov
author_rank: Super Contributor
timestamp: December 01, 2021, 11:10:02 pm
content: ldmia and stmia instructions starting from 0x803abc6 is what loads that constant string to the stack.So you can look at the address stored in r6 before the first instructions is executed. As you can see that address is located in a constant pool at the end of the function and is loaded by the ldr instruction (from address 0x803ac60). Your binary should contain that string at that address.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 01, 2021, 11:13:22 pm
content: Note that the following declaration for 'dow' would have made more sense here:const char *dow = "MonTue...";No need to allocate an array on the stack to have it initialized with a string constant at run-time, here. You're wasting stack space and CPU cycles.And, have you checked the value of sDate.WeekDay?

author: peter-h
author_rank: Super Contributor
timestamp: December 02, 2021, 08:23:18 am
content: Thanks everyone. Yeah, I can see 0x803ac60 contains 0x8055398 which contains... FFs. In fact everything above 0x8048000 is FFs.The .map file shows that rodata starts shortly above that value, so I am losing all of that. I am dropping 57632 bytes off the end of the file! Is there anything in the 32F417 which happens at 0x8048000? It doesn't lie on one of the FLASH block boundaries.The binary file is fine; the code runs via a debugger ok.Thanks for the coding tips. It was actually written by someone elseI would have declared it as static. I made the mistake once of declaring an array of about 1k bytes inside a function and then found the function was running really slowlyYes; that index should be checked.

author: ataradov
author_rank: Super Contributor
timestamp: December 02, 2021, 08:32:06 am
content: Just debug the writing procedure and see the error code it returns. There is no point in guessing. It may not even be a write issue, but SD Card reading issue, or FS issue.

author: peter-h
author_rank: Super Contributor
timestamp: December 02, 2021, 09:51:29 am
content: Spot the mistakeCode:for (uint32_t block32k=1; block32k<16; block32k++)// 1-15{// Read each 32k block into buffer1buffer1idx=0;for ( uint32_t page=pagebase; page<(pagebase+64); page++ ){AT45dbxx_ReadPage(&buffer1,512,page*512);buffer1idx+=512;}// Program 32k blockL_HAL_FLASH_Unlock();for (uint32_t i=0; i<(32*1024); i+=4){uint32_t data=buffer1|(buffer1[i+1]<<8)|(buffer1[i+2]<<16)|(buffer1[i+3]<<24);L_FLASH_Program_Word(i+cpubase, data);}L_HAL_FLASH_Lock();// Verify 32k block against buffer1for (uint32_t i=0; i<(32*1024); i+=4){uint32_t data=buffer1|(buffer1[i+1]<<8)|(buffer1[i+2]<<16)|(buffer1[i+3]<<24);if ( (*(volatile uint32_t*) (i+cpubase)) != data ) error++;}cpubase+=(32*1024);pagebase+=64;block32k++;}Two lots of fossil code there. One is the block32k++. The other is the fact that black32k is not used within the loop. That is why everything worked for binary files up to 8 blocks (256k) or so.