2016-12-23 06:23 AM
I'm trying to blink a LED on a Nucleo-L476 with CubeMX and ST's HAL. It worked perfectly on Windows (System Workbench). Now, I'm trying to do the same on Linux with CubeMX and Qt Createor (my favorite IDE) and OpenOCD. I am now able to compile and debug the target.
However, the program crashes during HAL initialization. More precisely, when it tries to access the
SystemCoreClock
variable.
The problem, in general, is that a global function can't be accessed from a function :
uint32_t dummyVar = 123;
void dummyFunc()
{
uint32_t loc = 123;
uint32_t *p = &loc;
p = &dummyVar; // debugger says &dummyVar = 0x20000004 and p = 0x011a3b01 (outside RAM)
__asm('nop');
__asm('nop');
__asm('nop');
loc = dummyVar; // *** crash here (WWDG IRQ) or random value
}
The variable
p
here points outside the RAM, which starts at 0x20000000. The nop instructions make sure
p = &dummyVar;
is really executed and the debugger doesn't fool me.
#hal #linux #memory #gcc
Solved! Go to Solution.
2016-12-28 06:39 AM
So, Clive was right - you compile this as
https://en.wikipedia.org/wiki/Position-independent_code
, as witnessed by 'build_output.txt':/usr/local/gcc-arm-none-eabi-6_2-2016q4/bin/arm-none-eabi-gcc -g -O0 -Wall -Wextra -pipe -fvisibility=default -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -std=c99 -ffunction-sections -g3 -fmessage-length=0 -Wall -c -v
-fPIC
-DUSE_HAL_DRIVER -DSTM32L476xx '-D__weak=__attribute__((weak))' '-D__packed=__attribute__((__packed__))' -DDEBUG=1 -I/home/picard/prog/stm32/L4_blinky/Inc -I/home/picard/prog/stm32/L4_blinky/Drivers/CMSIS/Include -I/home/picard/prog/stm32/L4_blinky/Drivers/CMSIS/Device/ST/STM32L4xx/Include -I/home/picard/prog/stm32/L4_blinky/Drivers/STM32L4xx_HAL_Driver/Inc -c /home/picard/prog/stm32/L4_blinky/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c -o /home/picard/prog/stm32/build-L4_blinky-STM32_gcc_6_2-Debug/qtc_STM32_gc_6615075b-debug/L4-blinky.qtc-STM32-gc-6615075b.dd71dff9/.obj/b730380c1c8c37a8/stm32l4xx_hal_pwr.c.oI'm in no way expert in this but this is some interpretation of what we see:
.got 0x0000000020000010 0x14 load address 0x0000000008001aa0
though it is probably not loaded upon startup, i.e. as it is in RAM it contains some garbage p = &stupidVar
; C statement do this:
As you are not aware of the -fPIC nor is it in files which appear to hold the user settings, it probably had been kindly supplied by the IDE you are using.
JW
2016-12-23 06:32 AM
Does it 'crash' or Hard Fault?
Review a disassembly of the offending code and the processor registers when it fails.
Make sure the startup code is initializing the statics properly, and that the linker script properly describes the memory of the part, and doesn't misalign the stack.
2016-12-23 08:19 AM
Variables within a function may be put by compiler in Core registers : They don't have valid addresses to be pointed at, unless you mention 'volatile' or 'static'.
The global variable is initialized by 123, and it is not modified, the generated optimized code might put it in flash or else.
==> Put static or volatile for this type of example, and gear down the optimisation levels of the compiler...
Have a look at Clojure programming language. The nice thing to make recursive, multi-core, multi-task function naturally is to pass a context pointer by the function parameter. The context being a structure with all what's need for the function to perform its task without using globals directly. Elegant and requires discipline at minimum code size/performance cost.
Good luck!
2016-12-23 08:35 AM
Hi,
volatile has no effect, but static works. However, I discovered the problem with a variable from the HAL / CMSIS driver called SystemCoreClock. I can't change it to static since it needs to be visible from other .c files.
My CFLAGS contain '-O0 -g3'. I read somewhere -O0 disables optimization and -g3 adds extra information for debugging.
2016-12-23 09:21 AM
,
,
The linker script and the startup_stm32l476xx.s are exactly the same in both configurations (working and not working). I compiled with the same CFLAGS, LDFLAGS and ♯ defines (-D options to gcc).
Here is the disassembly of the function. The address of
dummyVar
is 0x20000000, which is the beginning of the RAM as defined in the linker script.>, , , , {
,08000264 <,dummyFunc>,:
,
,8000264: , , ,b480 , , , , , , , ,push , , ,{r7}
,
,8000266: , , ,b083 , , , , , , , ,sub , , ,sp, ♯ 12
,
,8000268: , , ,af00 , , , , , , , ,add , , ,r7, sp, ♯ 0
,
,800026a: , , ,4b0b , , , , , , , ,ldr , , ,r3, [pc, ♯ 44] , , ,, (8000298 <,dummyFunc+0x34>,)
,
,800026c: , , ,447b , , , , , , , ,add , , ,r3, pc
>, , , , uint32_t loc = 123,
,800026e: , , ,227b , , , , , , , ,movs , , ,r2, ♯ 123 , , ,, 0x7b
,
,8000270: , , ,603a , , , , , , , ,str , , ,r2, [r7, ♯ 0]
>, , , , uint32_t *p = &,loc,
,8000272: , , ,463a , , , , , , , ,mov , , ,r2, r7
,
,8000274: , , ,607a , , , , , , , ,str , , ,r2, [r7, ♯ 4]
>, , , , p = &,dummyVar,
,
,8000276: , , ,4a09 , , , , , , , ,ldr , , ,r2, [pc, ♯ 36] , , ,, (800029c <,dummyFunc+0x38>,)
,
,8000278: , , ,589a , , , , , , , ,ldr , , ,r2, [r3, r2]
,
,800027a: , , ,607a , , , , , , , ,str , , ,r2, [r7, ♯ 4]
>, , , , __asm('nop'),
,800027c: , , ,bf00 , , , , , , , ,nop
>, , , , __asm('nop'),
,800027e: , , ,bf00 , , , , , , , ,nop
>, , , , __asm('nop'),
,8000280: , , ,bf00 , , , , , , , ,nop
>, , , , loc = dummyVar,
,
,8000282: , , ,4a06 , , , , , , , ,ldr , , ,r2, [pc, ♯ 24] , , ,, (800029c <,dummyFunc+0x38>,)
,
,8000284: , , ,589b , , , , , , , ,ldr , , ,r3, [r3, r2]
,
,8000286: , , ,681b , , , , , , , ,ldr , , ,r3, [r3, ♯ 0]
,
,8000288: , , ,603b , , , , , , , ,str , , ,r3, [r7, ♯ 0]
>, , , , , }
,
,800028a: , , ,bf00 , , , , , , , ,nop
,
,800028c: , , ,370c , , , , , , , ,adds , , ,r7, ♯ 12
,
,800028e: , , ,46bd , , , , , , , ,mov , , ,sp, r7
,
,8000290: , , ,f85d 7b04 , , ,ldr.w , , ,r7, [sp], ♯ 4
,
,8000294: , , ,4770 , , , , , , , ,bx , , ,lr
,
,8000296: , , ,bf00 , , , , , , , ,nop
,
,8000298: , , ,17fffda0 , , ,ldrbne , , ,pc, [pc, r0, lsr ♯ 27]! , , ,, <,UNPREDICTABLE>,
,
,800029c: , , ,00000000 , , ,andeq , , ,r0, r0, r0
Well, I'm not exactly fluent in assembly code... I tried to understand a bit, though.
What I understand for
p=&,dummyVar
:Does that help ?
About the registers, I really don't know where to look.
2016-12-23 09:38 AM
How exactly was DummyVar defined in this last example?
Post the *complete* source (copy-paste, don't edit) and complete disassembly of the binary (elf) resulting from that source.
JW
2016-12-23 09:56 AM
I uploaded the complete project, the elf and the objdump in the original post. The function is defined in stm32l4xx_hal.c but there is a similar one in main.c just before main() that behaves as badly. The compile flags are in the .qbs file.
Thanks for looking !
2016-12-23 10:49 AM
Something very odd going on with the linker, the .MAP file might shed some light on why the literal pools have weird addresses in them, but I see it throughout the file, not just your dummyFunc. It is perhaps for position independence but there is no tie in between 0x08000000 and 0x20000000, and I'm sure the math doesn't work for the TCM FLASH mapping.
08000264SUB16dummyFunc:; Xref 80002AA
08000264 B480push{r7}
08000266 B083subsp, #12
08000268 AF00addr7, sp, #0
0800026A 237Bmovsr3, #123
0800026C 603Bstrr3, [r7, #0]
0800026E 463Bmovr3, r7
08000270 607Bstrr3, [r7, #4]
08000272 BF00nop
08000274 4B07ldrr3, [pc, #28]; ($8000294=$17FFFD86)
08000276 447Baddr3, pc
08000278 607Bstrr3, [r7, #4]
0800027A BF00nop
0800027C BF00nop
0800027E 4B06ldrr3, [pc, #24]; ($8000298=$17FFFD7C)
08000280 447Baddr3, pc
08000282 681Bldrr3, [r3, #0]
08000284 603Bstrr3, [r7, #0]
08000286 BF00nop
08000288 370Caddsr7, #12
0800028A 46BDmovsp, r7
0800028C F85D 7B04ldr.wr7, [sp], #4
08000290 4770bxlr
08000292 BF00nop
08000294 17FFFD86dd$17FFFD86
08000298 17FFFD7Cdd$17FFFD7C
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2016-12-23 11:45 AM
David PICARD wrote:
I uploaded the complete project, the elf and the objdump in the original post.
Yes, but the example you've posted at
Dec 23, 2016 4:23 PM was compiled from a different source. If I understand the disasm correctly, you compiled it with dummyVar being defined as a pointer rather than an integer. I hate to analyze a changing object.
Clive wrote:
Something very odd going on with the linker
+1. I might recommend you to run your gcc with -v and -dumpspecs, but I am no good at analyzing the infinite variations in which gcc binaries/toolchains may come.
Get a toolchain from a reputable source,
https://launchpad.net/gcc-arm-embedded
perhaps. I don't linux but from what I've heard, stock cross-toolchains from the distributions' repositories are very often source of grief.JW
2016-12-26 03:13 AM
Hi,
I downloaded the last compiler from the location pointed by
.Sorry for messing things up. This time, I attached a single tar file with the full project file under L4_blinky/ and the corresponding build artifacts under build-20161226-1051/ including objdump output with source code, compiler output to stdout, elf, and map, gcc dumpspecs.
The portions of code to look at are main.c, lines 63 to 76 and stm32l4xx_hal.c, lines 244 to In the former case, the static keyword is omitted, and things go wrong (p does not point at &stupidVar) ; see bellow. In the latter case, I declared the global variable dummyVar as a static uint32_t, not a pointer), as suggested by
and it makes things work as expected. But it work without this.Here is the sample from main.c, followed by the disassembly.
uint32_t stupidVar = 4000000; void stupidFunc(void) { uint32_t dummyLoc; uint32_t *p; __asm ('nop'); dummyLoc = 123; p = &dummyLoc; p = &stupidVar; __asm ('nop'); dummyLoc = stupidVar; }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
r7=0x20017fe8, start of the stack (=address of dummyLoc). p is stored 4 bytes farther, I guess.
What exactly does line 20 here ? The resulting value of r2 looks very odd...
void stupidFunc(void) { 800178c: b480 push {r7} 800178e: b083 sub sp, #12 8001790: af00 add r7, sp, #0 8001792: 4b0a ldr r3, [pc, #40] ; (80017bc <stupidFunc+0x30>) 8001794: 447b add r3, pc uint32_t dummyLoc; uint32_t *p; __asm ('nop'); 8001796: bf00 nop dummyLoc = 123; 8001798: 227b movs r2, #123 ; 0x7b 800179a: 603a str r2, [r7, #0] p = &dummyLoc; 800179c: 463a mov r2, r7 800179e: 607a str r2, [r7, #4] p = &stupidVar; 80017a0: 4a07 ldr r2, [pc, #28] ; (80017c0 <stupidFunc+0x34>) 80017a2: 589a ldr r2, [r3, r2] 80017a4: 607a str r2, [r7, #4] __asm ('nop'); 80017a6: bf00 nop dummyLoc = stupidVar; 80017a8: 4a05 ldr r2, [pc, #20] ; (80017c0 <stupidFunc+0x34>) 80017aa: 589b ldr r3, [r3, r2] 80017ac: 681b ldr r3, [r3, #0] 80017ae: 603b str r3, [r7, #0] } 80017b0: bf00 nop 80017b2: 370c adds r7, #12 80017b4: 46bd mov sp, r7 80017b6: f85d 7b04 ldr.w r7, [sp], #4 80017ba: 4770 bx lr 80017bc: 17ffe878 .word 0x17ffe878 80017c0: 00000010 .word 0x00000010�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Reminder : The original bug occurs at line stm32l4xx_hal.c:295, when reading the global variable SystemCoreClock. The execution suddenly jumps to startup_stm32l476xx.s, line 135 (I added the nop line 134 for convenience).
I am looking forward to reading your suggestions !
________________ Attachments : L4_blinky_20161226-1051.tar.gz : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006Hym3&d=%2Fa%2F0X0000000bFI%2Fd6XbR1HXOYFybzJVb8J.6e_wE3JGw5whs1tBcvJFM_c&asPdf=false