cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 : can't read global variables

David PICARD
Associate II
Posted on December 23, 2016 at 15:23

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
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on December 28, 2016 at 14:39

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.o

I'm in no way expert in this but this is some interpretation of what we see:

  • in .map, we see a .got section (for Global Offset Table holding addresses of the global variables)

    .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
  • lines 19-21 you mention above which are supposed to execute the

     p = &stupidVar

    ; C statement do this:
    • r3 already holds pointer to .got section (calculated relatively to pc at the beginning of the routine - this again is a PIC feature, and in STM32 may/will fail if FLASH is run from the relocated position at 0x00000000)
    • load stupidVar's offset (0x10) in .got into r2
    • add r2 and r3 and use the result as address from which load value into r2 (i.e. load the address from .got, but that's garbage as said above)
    • store the result into stack frame offset 4 (i.e. into local variable p )
  • the problem upon startup you mention is that as .got contains garbage, that garbage is used as address of SystemCoreClock global variable, and accessing that address resulted in some of the faults (as you have no explicit fault handler, it ended up in the default fault handler)

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

View solution in original post

13 REPLIES 13
Posted on December 23, 2016 at 15:32

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Seb
ST Employee
Posted on December 23, 2016 at 17:19

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!

David PICARD
Associate II
Posted on December 23, 2016 at 17:35

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.

Posted on December 23, 2016 at 17:21

 ,

 ,

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

:
  • load r2 with the value at address 0x800029c, which is 0.
  • load r3 with the value of r3 (0x0x20000010) with the offset contained in r2 (0), so r2 should equal r3, right ? But r2 == 0x1876bf44 instead.
  • store the value in r2, 4 bytes after the start of the stack (pointed to by r7). p == 0x1876bf44 too.

Does that help ?

About the registers, I really don't know where to look.

Posted on December 23, 2016 at 17:38

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

Posted on December 23, 2016 at 17:56

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 !

Posted on December 23, 2016 at 18:49

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
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on December 23, 2016 at 19:45

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

David PICARD
Associate II
Posted on December 26, 2016 at 12:13

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.

  • Before line 19 (address 80017a0), r2=0x20017fe8 (address of local dummyLoc), pc=0x80017a0, r3=0x20000
  • After line 19, r2=0x00000
  • After line 20, r2=0x6702e8f5, r3 unchanged.
  • After line 21, p=0x6702e8f5

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