STM32 + GCC v8 + Qt Creator + Qbs : crash in __libc_init_array - gcc

After upgrading my host PC to a newer Linux version, I can't run my project anymore. I just want to program a copy of a working electronic board : hardware and code have been validated before.
More accurately, the code crashes in the startup script at _libc_init_array and jump either to BusFault_Handler() or HardFault_Handler().
I have read a lot on the forum, and it seems is related to linking to the wrong libc flavor (Thumb vs. ARM).
Tools :
code generation : STM32CubeMX
compiler : GNU GCC version 8.2.1 (8-2018-q4-major)
IDE : Qt Creator
build system : Qbs (Qt's tool)
The MCU is a STM32L476RG, Cortex-M4, ARM v7e-m, with FPU. In GNU GCC installation folder, share/doc/gcc-arm-none-eabi/readme.txt tells me what flags I need :
|------------|--------------------------------------------|--------------|
| Cortex-M4 | -mthumb -mcpu=cortex-m4 -mfloat-abi=softfp | thumb |
| (Soft FP) | -mfpu=fpv4-sp-d16 | /v7e-m+fp |
| |--------------------------------------------| /softfp |
| | -mthumb -march=armv7e-m -mfloat-abi=softfp | |
| | -mfpu=fpv4-sp-d16 | |
|------------|--------------------------------------------|--------------|
| Cortex-M4 | -mthumb -mcpu=cortex-m4 -mfloat-abi=hard | thumb |
| (Hard FP) | -mfpu=fpv4-sp-d16 | /v7e-m+fp |
| |--------------------------------------------| /hard |
| | -mthumb -march=armv7e-m -mfloat-abi=hard | |
| | -mfpu=fpv4-sp-d16 | |
|------------|--------------------------------------------|--------------|
Only -mfloat-abi=softfp works, not -mfloat-abi=hard, but GCC documentation suggests the result is the same ; only calling conventions differ.
Here is my Qbs file :
import qbs
CppApplication {
consoleApplication: true
property string family: "STM32L4xx"
property string linkerScript: "STM32L476RGTx_FLASH.ld"
cpp.positionIndependentCode: false // make sure option -fPIC is not passed to GCC
cpp.defines: [
"USE_HAL_DRIVER",
"STM32L476xx",
"__weak=__attribute__((weak))",
"__packed=__attribute__((__packed__))"
]
cpp.commonCompilerFlags: [
"-fno-common",
"-specs=nosys.specs",
"-specs=nano.specs",
"-march=armv7e-m",
"-mcpu=cortex-m4",
"-mthumb-interwork", // support ARM and Thumb instruction sets
"-mthumb",
"-mfloat-abi=softfp",
"-mfpu=fpv4-sp-d16",
"-mtune=cortex-m4", // tune performance of code for this processor
// "-std=c99",
"-ffunction-sections",
"-fdata-sections",
// "-Os",
"-O0",
"-g3",
"-Wall",
"-c", // don't run the linker
// "-v" // print a lot of details (too much ?)
]
cpp.linkerFlags: [
"-T"+path+"/"+linkerScript,
"--gc-sections", // fixes "undefined reference to _exit" error
"-Map="+buildDirectory+"/memory.map", // file created at the end of the link step
"-static",
"--verbose", // displays library search
// "-lgcc",
// "-lg",
// "-lm"
]
cpp.includePaths: [
"Inc",
"Drivers/CMSIS/Include",
"Drivers/CMSIS/Device/ST/"+family+"/Include",
"Drivers/STM32L4xx_HAL_Driver/Inc",
"Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc",
"Middlewares/ST/STM32_USB_Device_Library/Core/Inc/"
]
files: [
"Inc/*.h",
linkerScript,
"Src/*.c",
"Drivers/CMSIS/Device/ST/"+family+"/Include/*.h",
"Drivers/CMSIS/Device/ST/"+family+"/Source/Templates/gcc/*.s",
"Drivers/CMSIS/Device/ST/"+family+"/Source/Templates/*.c",
"Drivers/CMSIS/Include/*.h",
"Drivers/"+family+"_HAL_Driver/Inc/*.h",
"Drivers/"+family+"_HAL_Driver/Src/*.c",
"Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/*.c",
"Middlewares/ST/STM32_USB_Device_Library/Core/Src/*.c"
]
Properties {
condition: qbs.buildVariant === "debug"
cpp.defines: outer.concat(["DEBUG=1"])
}
Group { // Properties for the produced executable
fileTagsFilter: product.type
qbs.install: true
}
}
The linker --verbose option lets it print the full path of the libraries it links to. And it always resolves to arm-none-eabi/lib/libc.a. But I would have expected arm-none-eabi/lib/thumb/v7e-m+fp/softfp/libc.a instead.
I also tried the linker option -nostdlib in conjunction with the -L flag , but it has no effect. It compiles even when I omit -L, but according to GCC man page, it shouldn't.
So, I am pretty stuck here. That 5 minute work is turning into days...

The problem was that the newer version of Qbs I got (v1.12.1) is smart enough to prepend "-Wl," to all options under cpp.linkerFlags... The solution is to set those flags needed to compile AND link in a cpp.driverFlags section.
Should it be helpful to anyone, here is my working (to date ;-) ) Qbs file.
import qbs
CppApplication {
consoleApplication: true
property string family: "STM32L4xx"
property string linkerScript: "STM32L476RGTx_FLASH.ld"
cpp.positionIndependentCode: false // make sure option -fPIC is not passed to GCC
// Make sure to call the linker through GCC driver :
cpp.linkerMode: "manual" // default : "automatic"
cpp.linkerName: "gcc" // this string is appended to "<full_path_to_toolchain>/arm-none-eabi-"
// Define some symbols (GCC -D flag)
cpp.defines: [
"USE_HAL_DRIVER",
"STM32L476xx",
"__weak=__attribute__((weak))",
"__packed=__attribute__((__packed__))"
]
// Options for compilation AND linking.
cpp.driverFlags: [
// CPU
"-mcpu=cortex-m4",
"-mthumb",
"-mfpu=fpv4-sp-d16",
"-mfloat-abi=hard",
"-specs=nano.specs", // use smaller libc
]
// Compiler flags for all langages (C, C++).
cpp.commonCompilerFlags: [
// Optimizations
//"-Os",
//"-O0",
"-Og",
"-Wall",
"-fdata-sections",
"-ffunction-sections",
// For debug
"-g",
"-gdwarf-2",
"-c", // don't run the linker
//"-v" // print a whole lot of details
]
// Linker flag only i.e. understood by LD !!!
// Qbs will prepend all these flags with "-Wl," so that GCC transfers them to LD.
// Other options required for linking should be set in the driverFlags section.
cpp.linkerFlags: [
"-T"+path+"/"+linkerScript,
"-static",
"--verbose", // displays library search
"-lc",
"-lm",
"-lnosys",
"-Map="+buildDirectory+"/memory.map", // file created at the end of the link step
"--cref", // map file formatting
"--gc-sections", // enables garbage collection for unused sections
]
// Include directories.
cpp.includePaths: [
"Inc",
"Drivers/CMSIS/Include",
"Drivers/CMSIS/Device/ST/"+family+"/Include",
"Drivers/STM32L4xx_HAL_Driver/Inc",
"Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc",
"Middlewares/ST/STM32_USB_Device_Library/Core/Inc/"
]
// Source files.
files: [
"Inc/*.h",
linkerScript,
"Src/*.c",
"Drivers/CMSIS/Device/ST/"+family+"/Include/*.h",
"startup/*.s",
"Drivers/CMSIS/Device/ST/"+family+"/Source/Templates/*.c",
"Drivers/CMSIS/Include/*.h",
"Drivers/"+family+"_HAL_Driver/Inc/*.h",
"Drivers/"+family+"_HAL_Driver/Src/*.c",
"Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/*.c",
"Middlewares/ST/STM32_USB_Device_Library/Core/Src/*.c"
]
Properties {
condition: qbs.buildVariant === "debug"
cpp.defines: outer.concat(["DEBUG=1"])
}
Group { // Properties for the produced executable
fileTagsFilter: product.type
qbs.install: true
}
}

Related

Bazel genrule invoked through dependency has not same behavior (local=1)

I'm a beginner with bazel and I know I did not undertsand all and concepts too, I am really more familiar with makefile and cmake.
What I dont understand and need explanation please is the following behavior with the dependency I created
Myrepo
|
| WORKSPACE
|inc
| hello.h
| BUILD
| src
| hello.c
| BUILD
| deps
| third_part # not from git repo , can be deleted
| BUILD
| scripts
| install_third_part.sh
| BUILD
so my hello.c needs headers that script install_third_part.sh puts inside the deps/third_part
so that bazels files are:
src/BUILD
cc_library(
name = "hello",
visibility = ["//visibility:public"],
linkstatic = 1,
hdrs = glob(["inc/*.h"]),
srcs = glob(["src/*.c"]),
deps = ["//deps:third",
]
)
deps/BUILD
cc_library(
name = "third",
hdrs = glob(["third_part/usr/local/include/**/*"]),
data = ["//scripts:install_third_part"],
copts=["-Ithird_part/usr/local/include/"],
visibility = ["//visibility:public"],
)
scripts/BUILD
genrule(
name = "install_third_part",
srcs= ["//scripts:install_third_part.sh"],
outs = ["install_third_part.txt"],
cmd = "$(location //scripts:install_third_part.sh) -i > \"$#\"",
local =1,
visibility = ["//visibility:public"],
)
so when I called
bazel build //deps:third
bazel build //scripts:install_third_part
as I set local to true, I can see the folder deps/third_part/ created with all header files
BUT when I called
bazel build //src:hello
I can see the rule is executed as bazel-bin/scripts/install_third_part.txt is present but the deps/third_part is not created if I removed it before.
(bazel 5.2)
what's wrong with my way of doing that ?
maybe you will told me to create a macro to do such thing, I need a clear example to understand please
thank you
Karim
#ahumesky

`cmse_check_address_range` changes behaviour with compiler upgrade

I'm using a Cortex-M33 with arm trust-zone. I have a secure api inside my secure firmware that I can call from my non-secure firmware. All works as expected - at least until I upgraded my compiler from gcc-arm-none-eabi-7-2018-q2-update to gcc-arm-none-eabi-10-2020-q4-major.
The function in question looks like this:
bool __attribute__((cmse_nonsecure_call)) (*Callback_Handler)();
__unused __attribute__((cmse_nonsecure_entry))
bool Secure_SetSomeCallbackHandler(bool (*handler)()) {
// this cmse-check fails with the compiler in `version gcc-arm-none-eabi-10-2020-q4-major`
// it works with the `gcc-arm-none-eabi-7-2018-q2-update` though
handler = cmse_check_address_range(handler, 4, CMSE_NONSECURE);
if (handler == NULL) {
return false;
}
Callback_Handler = handler;
return true;
}
I make sure the supplied pointer really is in non-secure space by using cmse_check_address_range. That works for the version 7, but if I compile the code with version 10, NULL is returned. I did not change anything in the source or any other part, just the compiler.
I checked for any changes in that function, but even https://github.com/gcc-mirror/gcc/commits/master/libgcc/config/arm/cmse.c does not show any changes whatsoever.
Did anything change? Maybe I'm using the function not as intended (do I need different flags for functions? But then again, it works with version 7.
Update:
I also posted this in arm embedded toolchain forum:
https://answers.launchpad.net/gcc-arm-embedded/+question/695596
#HsuHau https://stackoverflow.com/a/66273629/1358283 posted a bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99157
It seems to be a GCC bug when libgcc checking CMSE support.
It checks $? for the return value of a gcc command, but in Makefile it should use $$? instead.
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 364f40ebe7f9..3625a2590bee 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
## -4,7 +4,7 ## LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
HAVE_V81M:=$(findstring armv8.1-m.main,$(gcc_compile_bare))
-ifeq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null >/dev/null 2>/dev/null; echo $?),0)
+ifeq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null >/dev/null 2>/dev/null; echo $$?),0)
CMSE_OPTS:=-mcmse
endif
I have reported the bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99157

Simple Arduino PlatformIO C++11 project has undefined reference to default constructor during linking stage (but intellisense detects no errors)

I've been scouring the internet trying to find a solution and done a ton of tinkering myself, but at this point, I've lost all my hair and feel no closer to solving this problem.
The intellisense in VSCode with Platformio extension is able to auto complete the constructors from /lib/SelectWheel/SelectWheel.h, but it seems like the build linker can't find the header and/or cpp file. Why would the intellisense and build process disagree? How can I fix this?
Here's the error:
Linking .pio\build\megaatmega2560\firmware.elf
C:\Users\matth\AppData\Local\Temp\cclHZ2N6.ltrans0.ltrans.o: In function `_GLOBAL__sub_I_selectWheel':
<artificial>:(.text.startup+0xf6): undefined reference to `SelectWheel::SelectWheel()'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\megaatmega2560\firmware.elf] Error 1
Here's the terminal output for pio run -t clean and platformio run --verbose: https://pastebin.com/xn862p00
Here's the project structure:
Hydro9000
| -- .pio
| -- .vscode
| -- include
| | -- Adafruit_BusIO
| | -- Adafruit_EPD
| | -- Adafruit_GFX_Library
| | -- Adafruit_SSD1306
| | -- ArduinoSTL
| -- lib
| | -- SelectWheel
| | | -- SelectWheel.h
| | | -- SelectWheel.cpp
| -- src
| | -- main.cpp
| -- platformio.ini
Here's platformio.ini
[env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
framework = arduino
Here's /src/main.cpp
#include <Arduino.h>
#include "SelectWheel/SelectWheel.h"
SelectWheel* selectWheel = new SelectWheel();
void setup() {}
void loop() {}
Here's /lib/SelectWheel/SelectWheel.h
#ifndef SelectWheel_h
#define SelectWheel_h
#include "Arduino.h"
class SelectWheel {
private:
int pinA, pinB;
public:
SelectWheel();
SelectWheel(int, int);
};
#endif
Here's /lib/SelectWheel/SelectWheel.cpp
#include "SelectWheel.h"
SelectWheel::SelectWheel() {}
SelectWheel::SelectWheel(int pinA, int pinB) {
this->pinA = pinA;
this->pinB = pinB;
pinMode(this->pinA, INPUT);
pinMode(this->pinB, INPUT);
}
Let me know if there is any additional information I can supply to help as I've already tried a bunch of ways to fix this.
I am using...
VSCode v1.47.2
PlatformIO IDE Extension (platformio.platformio-ide) v1.10.0
Microsoft C/C++ Extension (ms-vscode.cpptools) v0.29.0
According to your build log, your file SelectWheel.cpp didn't participate in build process at all (it has not been built). So, add it to build process and make sure it's linked

Package xkbcommon was not found in the pkg-config search path. when building Yocto image

On Ubuntu 14.04
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.3 LTS
Release: 14.04
Codename: trusty
Building a Yocto Poky image using the fido branch
inherit core-image
IMAGE_FEATURES += "x11-base x11-sato package-management ssh-server-dropbear"
IMAGE_INSTALL += "chromium \
lsb \
kernel-modules \
alsa-utils \
... and I am getting this sort of message
I look like it related to the Chromium recipe /meta-browser/recipes-browser/chromium/chromium_45.0.2454.85.bb which starts as such
include chromium.inc
DESCRIPTION = "Chromium browser"
DEPENDS += "libgnome-keyring"
and I get this message
ERROR: Logfile of failure stored in: /home/joel/yocto/build-fido/tmp/work/cortexa7hf-vfp-vfpv4-neon-poky-linux-gnueabi/chromium/45.0.2454.85-r0/temp/log.do_configure.28622
Log data follows:
| DEBUG: Executing python function sysroot_cleansstate
| DEBUG: Python function sysroot_cleansstate finished
| DEBUG: Executing shell function do_configure
| Updating projects from gyp files...
| Package xkbcommon was not found in the pkg-config search path.
| Perhaps you should add the directory containing `xkbcommon.pc'
| to the PKG_CONFIG_PATH environment variable
| No package 'xkbcommon' found
| gyp: Call to 'pkg-config --cflags xkbcommon' returned exit status 1.
| WARNING: exit code 1 from a shell command.
What I have tried
Installed the library
$ sudo apt-get install libxkbcommon-x11-dev
Search for xkbcommon.pc
$ apt-file search xkbcommon.pc
libxkbcommon-dev: /usr/lib/x86_64-linux-gnu/pkgconfig/xkbcommon.pc
pkg-config
joel#linux-Lenovo-G50-70:~/yocto/build-fido$ pkg-config --cflags xkbcommon
<=== Return is EMPTY (?)
joel#linux-Lenovo-G50-70:~/yocto/build-fido$ pkg-config --libs xkbcommon
-lxkbcommon <=== Looks correct
Added PKG_CONFIG_PATH
$ PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/x86_64-linux-gnu/pkgconfig/
$ export PKG_CONFIG_PATH
$ env | grep PKG
PKG_CONFIG_PATH=:/usr/lib/x86_64-linux-gnu/pkgconfig/
but I am still getting the same message when running bitbake
Any suggestions?
Find xkbcommon
$ find /usr/lib/ -name *xkbcommon*
/usr/lib/x86_64-linux-gnu/libxkbcommon.so
/usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0.0.0
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.a
/usr/lib/x86_64-linux-gnu/libxkbcommon.a
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so
/usr/lib/x86_64-linux-gnu/pkgconfig/xkbcommon.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/xkbcommon-x11.pc
/usr/lib/x86_64-linux-gnu/libxkbcommon.so.0
In this case, it was the chromium recipe that failed to find libxkbcommon. As the error occurred when building a recipe for the target system, we need to tell the build system that the chromium recipe has a dependency on libxkbcommmon.
This can be done by adding
DEPENDS += "libxkbcommon"
to the chromium recipe.
It's worth noting, that libxkbcommon quite likely is an optional dependency, and in that case, it should be handled by a suitable PACKAGECONFIG. (See PACKAGECONFIG in ref.manual).
Note: I've never built chromium myself, thus I'd prefer to not suggest any suitable PACKAGECONFIG.
I think the Chromium_45 recipe is taken down since the last time I saw it (don't see it anymore).
Anyway, this is what I did to Chromium_40.
I have disabled Wayland (ozone-wayland in Chromium) so that it will only use x11.
In local.conf, I added
CHROMIUM_ENABLE_WAYLAND = "0"
By doing this, I will bypass CHROMIUM_WAYLAND_DEPENDS = "wayland libxkbcommon"
CHROMIUM_X11_DEPENDS = "xextproto gtk+ libxi libxss"
CHROMIUM_X11_GYP_DEFINES = ""
CHROMIUM_WAYLAND_DEPENDS = "wayland libxkbcommon"
CHROMIUM_WAYLAND_GYP_DEFINES = "use_ash=1 use_aura=1 chromeos=0 use_ozone=1"
python() {
if d.getVar('CHROMIUM_ENABLE_WAYLAND', True) == '1':
d.appendVar('DEPENDS', ' %s ' % d.getVar('CHROMIUM_WAYLAND_DEPENDS', True))
d.appendVar('GYP_DEFINES', ' %s ' % d.getVar('CHROMIUM_WAYLAND_GYP_DEFINES', True))
else:
d.appendVar('DEPENDS', ' %s ' % d.getVar('CHROMIUM_X11_DEPENDS', True))
d.appendVar('GYP_DEFINES', ' %s ' % d.getVar('CHROMIUM_X11_GYP_DEFINES', True))
}
P.S.: One more thing I found weird is use-egl.
PACKAGECONFIG[use-egl] = ",,virtual/egl virtual/libgles2" is overrided with PACKAGECONFIG[use-egl] = "" so I have removed PACKAGECONFIG[use-egl] = "" from chromium.inc
PACKAGECONFIG ??= "use-egl"
# this makes sure the dependencies for the EGL mode are present; otherwise, the configure scripts
# automatically and silently fall back to GLX
PACKAGECONFIG[use-egl] = ",,virtual/egl virtual/libgles2"
# Additional PACKAGECONFIG options - listed here to avoid warnings
PACKAGECONFIG[component-build] = ""
PACKAGECONFIG[disable-api-keys-info-bar] = ""
PACKAGECONFIG[ignore-lost-context] = ""
PACKAGECONFIG[impl-side-painting] = ""
PACKAGECONFIG[use-egl] = ""
PACKAGECONFIG[kiosk-mode] = ""

GDB: Question about relative and absolute paths to files in backtraces

I have question about gdb or gcc (but not firefox).
I see only absolute paths in gdb when i debugging firefox. Example:
5 0x01bb0c52 in nsAppShell::ProcessNextNativeEvent
(this=0xb7232ba0, mayWait=1)
at
/media/25b7639d-9a70-42ca-aaa7-28f4d1f417fd/firefox-dev/mozilla-central/widget/src/gtk2/nsAppShell.cpp:144
It's uncomfortable for reading such backtraces.
If i try to compile and debug tiny test program i see such backtrace (with relative paths to files):
0 main () at prog.c:5
How can i see only relative paths in backtraces when debugging firefox?
P.S. gcc 4.4.1; gdb 7.0.
GDB will show absolute or relative path depending on how the program was compiled. Consider:
$ cd /tmp
$ cat t.c
int main() { return 0; }
$ gcc -g t.c && gdb -q -ex start -ex quit ./a.out
Reading symbols from /tmp/a.out...done.
Temporary breakpoint 1 at 0x4004c8: file t.c, line 1.
Temporary breakpoint 1, main () at t.c:1
1 int main() { return 0; }
Now the same, but compile source via absolute path:
$ gcc -g /tmp/t.c && gdb -q -ex start -ex quit ./a.out
Reading symbols from /tmp/a.out...done.
Temporary breakpoint 1 at 0x4004c8: file /tmp/t.c, line 1.
Temporary breakpoint 1, main () at /tmp/t.c:1
1 int main() { return 0; }
And again, this time with relative path that includes directory prefix:
$ cd /
$ gcc -g tmp/t.c -o tmp/a.out && gdb -q -ex start -ex quit tmp/a.out
Reading symbols from /tmp/a.out...done.
Temporary breakpoint 1 at 0x4004c8: file tmp/t.c, line 1.
Temporary breakpoint 1, main () at tmp/t.c:1
1 int main() { return 0; }
So, you can get gdb to show relative path if you change the way firefox is built. That may prove to be a very non-trivial proposition.

Resources