That’s a great post! I have also tried to experiment with Clang few months ago to solve the problem related to iostream C++ STL header.
The problem is that if one would like to include iostream or sstream to implement e.g. nice streaming to a logger, or to some other peripheral, using operator<< for example, then the binary size increases so much, that it will not fit into Flash memory.
This is really annoying, because I can’t simply use std::ostringstream, to reuse easy string conversion, and I need to add quite a lot of boilerplate to be able to convert various types to string, using e.g. std::to_string.
As I researched, I have found out that it is caused by the standard library bundled with GCC. After iostream is included some static objects are instantiated, even though they are not used at all.
In this post it is explained that the STL from ARM Toolchain is used. Do you know whether the use of the lld or the -Oz flag resolves the problem related to too big size of the binary?
When I try even a simple program, which had main() and used std::ostringstream to stringify some numbers, and was compiled for a ARM Cortex M CPU (with e.g. 256 kB of Flash), the Flash area was overflown.
Thanks for the post, really interesting. I gave this a try (had to make some tweaks to my CMake builds first) but can’t seem to get it to work properly.
I get a bunch of errors similar to this:
In file included from /Users/kamil/xxxxx/../Drivers/CMSIS/CMSIS/Include/cmsis_compiler.h:48:
/Users/kamil/xxx/../Drivers/CMSIS/CMSIS/Include/cmsis_gcc.h:868:19: error: invalid instruction mnemonic 'isb'
__ASM volatile ("isb 0xF":::"memory");
^
<inline asm>:1:2: note: instantiated into assembly here
isb 0xF
^~~
In any parts of the code that are trying to compile the hardware drivers (from ST in this case)
Glad to hear you enjoyed the article! The error you hit above suggests you may not be targeting the right architecture. What CFLAGs are you using? (For example, if you are compiling for a cortex M4, you want to make sure you have something like -mthumb-mcpu=cortex-m4).
Ah, looks like you are missing --target=arm-none-eabi to tell clang to cross-compile which will result in those warnings and the assembly one you are seeing.
Hey @KKoovalsky, you’re right that using the STL on embedded in general is tricky. I don’t use C++ much myself, but Phillip at Embedded Artistry does and writes about it. Check out his article about the Embedded Templates Library: https://embeddedartistry.com/blog/2018/12/13/embedded-template-library/. It might be what you’re looking for!
Another great post at Interrupt, thank you @chrisc! This is the first time I am reading about ownership_returns and ownership_takes and it looks like some powerful tool beyond malloc-like functions (especially in combination with ownership_holds).
I failed to find real-world examples on Github. Are you aware of any non-trivial examples I could learn from?
Unfortunately I have not found any examples either. I think today it’s really only used within the llvm-project for the unix MallocChecker but agree there seems like a lot of potential for other types of passes with the annotation in general!
Something I’d like to try is implementing a custom plugin that uses the ownership_ type attribute.
Great article! The majority of my company’s firmware (with the exception of PIC-based systems) is developed & shipped with clang; when we switched 5-6 years ago the primary motivation was the superior quality of its diagnostic messages compared to GCC. I understand GCC’s output has improved drastically since then, but we haven’t had any practical reasons to reconsider that decision. We’re currently building with c++17 and I’m hoping to get clang 10 up and running soon so we can take advantage of some c++20 features.
I think clang-tidy also belongs in this conversation: it includes the static analyzer checks performed by scan-build, and additionally can perform a whole raft of checks against various coding & style guidelines including the C++ core guidelines. Running it is a little bit more involved than scan-build as it works best with a compile_commands database and introducing it to an existing codebase can be a big task, but it’s got some great checks: https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/list.html
Welcome to Interrupt @gdharris! Exciting to hear from more folks using clang on embedded. We had evaluated clang 5-6 years ago, but we found that it wasn’t quite as good at optimizing for code size then. Was that a concern for your use case?
Thank you for bringing up clang-tidy. I have not had the change to try it, but I will. If you’re ever inspired to write a short post about it, we’d love to publish it :-).
Hi I follow your posts regularly. I am interested in converting some of my gcc projects to clang. This article is a great starting point. However, I am stuck early on in the scan-build step. I am getting the following errors: ~/.../example/freertos-example-llvm >>> scan-build make scan-build: Using '/usr/bin/clang-10' for static analysis /usr/bin/../lib/clang/ccc-analyzer ===GCC Compiler Detected=== Compiling src/builtin_scanbuild_examples.c gcc: warning: ‘-mcpu=’ is deprecated; use ‘-mtune=’ or ‘-march=’ instead gcc: error: unrecognized command line option ‘-mthumb’ gcc: error: unrecognized command line option ‘-mfloat-abi=hard’ gcc: error: unrecognized command line option ‘-mfpu=fpv4-sp-d16’ make: *** [Makefile:167: /home/rajah/workspace/interrupt/example/freertos-example- llvm/build/src/builtin_scanbuild_examples.o] Error 1 scan-build: Removing directory '/tmp/scan-build-2020-05-28-170744-12711-1' because it contains no reports. scan-build: No bugs found. ~/.../example/freertos-example-llvm >>>
I have installed clang 10 on arch and I also have arm-none-eabi-gcc installed. What am I missing? Thanks in advance for any pointers.
Under the hood scan-build works by searching for a compiler to use, overriding CC in the makefile, and then running a static analysis pass with Clang. In your case it looks like it found the wrong compiler (“gcc” instead of “arm-none-eabi-gcc” or “clang”) which is why you are seeing the error.
Can you try using the --use-cc argument with scan-build to tell it the compiler to exact compiler to use instead: i.e scan-build --use-cc=<path_to_clang>/clang make?
Thanks for the question, I’ll add a note to the article about it!
Hi Chris,
Thank you very much for the prompt response!!
I was able to get it working (mostly) with the -use-cc switch. After compile, I got a linker error.
Compiling freertos_kernel/portable/GCC/ARM_CM4F/port.c Compiling freertos_kernel/portable/MemMang/heap_1.c Linking library clang-10: error: unable to execute command: Executable "ld.lld" doesn't exist! clang-10: error: ld.lld command failed with exit code 1 (use -v to see invocation)
I got around this error by installing the the linker package (lld on arch). Once I installed this, I got a library related error:
Compiling freertos_kernel/portable/MemMang/heap_1.c Linking library ld.lld: error: unable to find library -lgcc clang-10: error: ld.lld command failed with exit code 1 (use -v to see invocation) make: *** [Makefile:148: /home/rajah/workspace/interrupt/example/freertos-example-``llvm/build/nrf52.elf] Error 1
When I just run make instead of scan-build make, an elf output is generated. However, even with this error, I can still run scan-view as all the errors have been captured as part of the compile process. I am very impressed with how the errors are presented. I will continue with rest of the blog post as scan-build is working now. Any idea why scan-build its not able to find the gcc library?
This is a very interesting post. I have tried to get scan-build to run in the past without success… That’s still the case, but I think I got a lot closer today.
Have you had any success running this on Windows? I can get LLVM installed no problem and scan-build runs, but fails at various points. The closest I got was specifying the analyzer, target, and compiler, but it still failed due to what appears to be a space in the path of ccc-analyzer… Anyway, has anyone run this on Windows with success? My makefile runs no problem.
Thanks for the response Chris. I tried that option too, still no luck. This is the console output.
~/.../example/freertos-example-llvm >>> COMPILER=clang scan-build --use-cc=/usr/bin/clang make
scan-build: Using '/usr/bin/clang-10' for static analysis
/usr/bin/../lib/clang/ccc-analyzer
===Clang Compiler Detected===
===GCC Compiler Detected===
Compiling src/builtin_scanbuild_examples.c
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/builtin_scanbuild_examples.c:11:13: warning: Dereference of null pointer (loaded from variable 'pointer')
result += *pointer;
^~~~~~~~
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/builtin_scanbuild_examples.c:18:12: warning: Division by zero
rv = 1 / denominator;
~~^~~~~~~~~~~~~
2 warnings generated.
Compiling src/main.c
Compiling src/memory_leak_examples.c
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/memory_leak_examples.c:11:3: warning: Attempt to free released memory
free(ptr);
^~~~~~~~~
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/memory_leak_examples.c:16:12: warning: Use of memory after it is freed
sum += ptr[i];
^~~~~~
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/memory_leak_examples.c:31:9: warning: Assigned value is garbage or undefined
sum += ptr[i];
^ ~~~~~~
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/memory_leak_examples.c:47:12: warning: Potential leak of memory pointed to by 'ptr'
return 1;
^
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/memory_leak_examples.c:65:5: warning: Attempt to free released memory
memory_pool_free(ptr);
^~~~~~~~~~~~~~~~~~~~~
/home/rajah/workspace/interrupt/example/freertos-example-llvm/include/example_project/memory_pool.h:13:26: note: expanded from macro 'memory_pool_free'
#define memory_pool_free free
^
/home/rajah/workspace/interrupt/example/freertos-example-llvm/src/memory_leak_examples.c:68:3: warning: Use of memory after it is freed
memset(ptr, 0x5e, size);
^~~~~~~~~~~~~~~~~~~~~~~
6 warnings generated.
Compiling src/memory_pool.c
Compiling src/mutex_examples.c
Compiling src/stub_functions.c
Compiling src/freertos_lock_port.c
Compiling src/startup.c
Compiling freertos_kernel/tasks.c
Compiling freertos_kernel/queue.c
Compiling freertos_kernel/list.c
Compiling freertos_kernel/timers.c
Compiling freertos_kernel/portable/GCC/ARM_CM4F/port.c
Compiling freertos_kernel/portable/MemMang/heap_1.c
Linking library
ld.lld: error: unable to find library -lgcc
clang-10: error: ld.lld command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:148: /home/rajah/workspace/interrupt/example/freertos-example-llvm/build/nrf52.elf] Error 1
scan-build: 8 bugs found.
scan-build: Run 'scan-view /tmp/scan-build-2020-06-05-165601-6412-1' to examine bug reports.
This is the console output when I just run make. Looks like arm-none-eabi-ld/gcc is able to find gcc library.
~/.../example/freertos-example-llvm >>> make
arm-none-eabi-gcc
===GCC Compiler Detected===
Linking library
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/libgcc.a(_udivmoddi4.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-aeabi_memclr.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-aeabi_memcpy.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-malloc.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-mallocr.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-mlock.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-sbrkr.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-freer.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-impure.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-lock.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
/usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/bin/ld: warning: /usr/lib/gcc/arm-none-eabi/10.1.0/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-reent.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail
Generated build/nrf52.elf
Does clang require a separate step to install compatible libraries? I wonder if this related to Arch/linux. Do you have a linux machine or Arch VM on your end?
Thanks for all your support and help. I was able to get past the gcc library issue. I added -v to linker flags in the Makefile to show the link invocation command (see below)
From the invocation, I was able to verify that libgcc.a can be found in /usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/libgcc.a
However, the -L flag to the linker only list the following search directories. -L/usr/lib/clang/10.0.0/lib/baremetal -L/usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard
The first path does not exist on my arch system and the second one exits, but does not have libgcc.a. I copied libgcc.a from /usr/lib/gcc/arm-none-eabi/10.1.0/thumb/v7e-m+fp/hard/ to /usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard. I am able to generate the elf file after this. However, I am still not sure how arm-none-eabi-gcc/ld is able to find gcc library without copying. I suspect it may have something to do with how scan-build hijacks CC in the Makefile. I hope this helps others facing similar issues.
Thanks,
Rajah
System details: Linux 5.6.15-1-MANJARO #1 SMP PREEMPT Wed May 27 20:38:56 UTC 2020 x86_64 GNU/Linux Clang compiler details: clang version 10.0.0 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin Clang linker details: LLD 10.0.0 (compatible with GNU linkers) arm-none-eabi-gcc details: arm-none-eabi-gcc (Arch Repository) 10.1.0 arm-none-eabi-ld details: GNU ld (GNU Binutils) 2.34
That’s great you were able to figure it out!! The path to libgcc is determined using gcc’s -print-libgcc-file-name command option described here in the article. It sounds like for your setup that may be what was failing.
Do note that the arm-none-eabi package available via pacman is not an officially supported release of ARM gcc and is usually a version ahead of the official ARM release. While it can be interesting to use that build to pre-test new compiler releases, there’s usually configuration issues and new errors that arise as a result. For projects, I’d recommend using one of the official releases available here instead.
Hi @Hyunyong-Park, you’re welcome to translate and re-post the content, but you will have to attribute it to us and link back to the original. Thank you!
Thank you for the great article!
May I ask a question regarding the freertos-example-llvm from the article ?
I get the following error when I run COMILER=clang make inside the freertos-example-llvm root.
/home/lonelyjoe/workspace/embedded/interrupt/example/freertos-example-llvm/src/main.c:5:10: fatal error: 'malloc.h' file not
found
#include <malloc.h>
^~~~~~~~~~
1 error generated.
Makefile:171: recipe for target '/home/lonelyjoe/workspace/embedded/interrupt/example/freertos-example-llvm/build/src/main.o' failed
make: *** [/home/lonelyjoe/workspace/embedded/interrupt/example/freertos-example-llvm/build/src/main.o] Error 1
I found out that my ARM_CORTEXM_MULTI_DIR(thumb/v7e-m/fpv4-sp/hard) neither contains libm.a nor libc.a. Still, running COMPILER=gcc make works without issues…
May I ask for tips on how to generate libm.a & libc.a for the cortex-m target ?
I setup a clean Linux install to debug this. Here’s what I found:
You need to install the arm-none-eabi-gcc build from ARM rather than from the Debian package archives. The latter is missing the sysroot, which we use to find the right header files. Head to ARM’s website to download the latest. Make sure it’s on your PATH, or set the ARM_GNU_CC make variable accordingly.
You haven’t run into it yet, but there’s an issue with compiler detection in our Makefile. I just fixed it here. Make sure to pull the latest.
With those two things sorted, I can build fine on Linux:
Thank you so much for your help! You’re a lifesaver!
After switching my arm-none-eabi-gcc to the one downloaded from theARM website, I can see the files libm.a and libc.a.
After that I faced an identical issue with @mcrajah (-L issue), but I was able to resolve it thanks to @mcrajah 's previous comments.
I’m just one foot away from succeeding cross-compilation with clang…
Currently my lld.ld fails due to the symbol COPY in the linker file (nrf52.ld).
I’m not sure what I need to do to fix this one…
$ COMPILER=clang make
error: /home/lonelyjoe/workspace/embedded/interrupt/example/freertos-example-llvm/nrf52.ld:76: symbol not found: COPY
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)
Makefile:154: recipe for target '/home/lonelyjoe/workspace/embedded/interrupt/example/freertos-example-llvm/build/nrf52.elf' failed
make: *** [/home/lonelyjoe/workspace/embedded/interrupt/example/freertos-example-llvm/build/nrf52.elf] Error 1
Looking at the log you posted, it appears it’s the COPY directive itself that the linker fails to recognize. Could you try updating clang and lld to their latest version? Here’s what I’ve got here:
root@fbo-dev:~# clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
root@fbo-dev:~# ld.lld --version
LLD 10.0.0 (compatible with GNU linkers)
Alternatively you should be able to change that section to NOLOAD rather than COPY at line 76 of nrf52.ld (though @chrisc can correct me if I’m wrong).
Edit: By the way, the libgcc issue @mcrajah was talking about is due to the compiler detection bug I fixed at Fix llvm example on Linux · memfault/interrupt@2bd1eb5 · GitHub. If you’re seeing both “GCC compiler detected” and “Clang compiler detected” in the output, there’s a problem!
I tried to implement this all as a CMake config as a cmake skill-builder & to explore the described benefits of transitioning to clang/llvm.
But I encountered a problem that it seems like no one else has mentioned: I was getting a lot of undefined symbols until I included explicit linking against crt0.o, crti.o, crtbegin.o, and crtend.o.
So, I must have an option or flag wrong or missing, given how roundabout my solution is. Doing the build “manually” at the command line needed the same objects added in.
Is this an expected pitfall?
Here’s my minimum working example: https://github.com/apullin/clang_min_fw
with the additions in ${CRT_SUPPORT_ROOT} and ${CRT_SUPPORT_LINK}.
Hi @apullin, one idea would be to try would be adding --ffunction-sections & --fdata-sections to your compiler flags. Without these flags, unused dependencies will get pulled into your build and could be the cause of the undefined symbol errors you were seeing.
I worked on LLVM professionally back when there was just llvm-gcc and no Clang, and for several years after Clang was released. LLVM has been quite capable of lots of things people don’t even attempt for years; llvm IR was originally meant to be cross-processor, and you can generally build a project with processor features disabled to prevent intrinsic generation as IR, then lower to machine code for any supported architecture with the same data sizes (it may have additional / different ones as long as it has the maximum sized integer and float that you built against) given a platform with a compatible C library. This isn’t recommended or necessarily a good idea, but I’ve taken C code compiled to IR built against armv5tej-linux-eabi and lowered it to all of windows-x86_64, darwin-ppc, android-arm, linux-x86, and ios-arm and it remained functional and ran without errors after forcibly lowering to the wrong platform / architecture… Not super useful but kinda neat. Apple requires app store MachO submissions to include bitcode as another multiarch so they can verify code more easily and presumably so they can do new optimized builds for minor arch changes and compiler updates.
A lot of times, due to compiler flags differing in behavior (as seen in previous posts here), people give up or assume LLVM is producing bad code… there are at least 3 bugs I saw on the dev list today complaining about bad optimization compared to GCC where the entire problem could be fixed using -Os or -Oz instead of -O3, because llvm O3 is like telling it, “the target machine has effectively unlimited RAM and icache, spew all the assembly you want if it has any benefit”, which often creates large bizarre looking constructs that execute quickly because of pipelining / processor rules that are non-obvious. This is one of those situations where assembly is kind of all or nothing, and unless you’ve read the thousands of pages of architecture guides and timing like me and similarly pedantic asses who have worked on or currently work on the backends, you’re better off not second guessing the compiler without profiling code at the very least.
One strange example is 3.7.2 in the intel optimization manual where instead of:
mov eax, [ebx +4]
mov ecx, 60
…to set up a loop scanning a list,
mov eax, [ebx +4]
mov eax, [ebx +4]
mov eax, [ebx +4]
mov ecx, 60
Is preferred in most cases on Core architectures because it triggers hardware L1 prefetch on the rest of the data. At first glance this code would look like a compiler error to most sane people, including me if I hadn’t read that manual before, but the 3x duplicated instruction forces insanely fast background prefetch and is safe to do 90% of the time. With constrained hardware (a different processor architecture with wider variance between the high end and embedded procs with a similar optimization, maybe), it might be more important to get rid of the extra instructions with -Oz because you’re working within 128k of flash and the extra speed during your hardware init sequence doesn’t matter. I saw a bug filed today about redundant loads that made me think of this. It was very likely an instance of this optimization or a related one.
Another example was a bug filed about REP MOVSB being selected instead of the wider versions (REP STOSD/Q) with GCC output being given as the example of doing it right… The problem is that GCC is wrong on Ivy Bridge and up; there’s a processor fast path for REP MOVSB and STOSB that makes them universally faster than STOSD and as fast or faster than AVX / AVX2 on copies over 128 bytes. Intel recommends never using rep movsd with movsb to finish mod 4 leftovers for memcpy, and only to use AVX for very short copies now. AVX is faster for those because enhanced rep movsb has startup overhead that isn’t amortized with avx register copying until the 128 byte range. Technically both compilers in the “bug” should have conditionally used AVX based on data size, but it has its own problems on Haswell-E / Broadwell-E / Skylake like dynamic TurboBoost upper speed limit dropping by 200mhz by default on the core or chip when executed that can make it more costly than expected. GCC either defaults to some ancient target processor or doesn’t know about this at all. Now if you didn’t read all that, you’d think copying data as bytes would be the slowest way to do things (and it would using mov reg, [mem]; mov [mem], reg loops for a couple of reasons) but processor architectures can be weird and you’ll have things like that.
There’s another where micro-op fusion occurs with test / jcc but not cmp / jcc, etc.
The whole point there is that even though I liked reading through Intel / ARM / PPC manuals at one point in time and would have contributed to an open source compiler if I had something to contribute, it never would have been to a GPL3 project. Getting paid wasn’t enough to make me submit an instruction encoding fix patch to GAS for ARM, I just flat-out refused (i could get away with a lot as the only person there who could read and write assembly and the compiler backends fluently for every architecture we supported) and then converted our arm-linux-eabi toolchain to clang in a few days instead and got the company to ditch gcc across every supported platform over the next several months after proving it would work in that one.
That was my initiative, not some corporate doesn’t want to release source thing. They’d have gladly submitted patches to gcc/gas forever instead, but I never wanted to have to look at GAS again after doing so once, and already disliked the GPL, so I made absolutely sure I wouldn’t be asked to and neither would anyone else there. We required and integrated with LLVM anyway, so switching wasn’t a hard sell, it’s just that nobody had thought it was possible at that point in time. We still relied on libstdc headers from the toolchain but LGPL doesn’t morally offend me as much and my idea of forcing customers to switch to a more permissively licensed embedded OS wasn’t going to fly (mostly because they may or may not exist).
So, I was happy to see this post because firmware is one of the last holdouts where not-really-free tools must be dealt with now that clang is able to build Linux itself more or less.
Lastly, and probably of more interest here than my uarch / anti-GPL rants, anyone interested in breaking that last part of the reliance on gcc within what you’re building should look at “llvm-libc” C Standard Library — LLVM 12 documentation (source-in-progress at llvm-project/libc at main · llvm/llvm-project · GitHub ) and see if you can contribute. They will accept pull requests from anyone after a well-defined review process. Somewhat ironically it looks as though LLVM-LIBC is being written in C++ (avoiding use of STL, it can be built standalone ), but that’s standard for the project overall aside from language bindings.
To be clear did anyone get AddressSanitzer to work using gcc on windows host with ARM Cortex M4 target.
Especially since there is a post on the official ARM site claiming they dont support AddressSanitizer>
Great walkthrough. Just have some probs with c++. figured it out to add -stdlib=libstdc++ to my cxx compile flags but run into issue with not finding <bits/c++config.h>. What am I missing. really appreciate any help
FAILED: Src/CMakeFiles/Application.dir/GuiTask.cpp.obj
/opt/homebrew/Cellar/llvm/17.0.6_1/bin/clang++ -DLV_CONF_INCLUDE_SIMPLE -DLV_LVGL_H_INCLUDE_SIMPLE -DSTM32G491xx -DUSE_FULL_LL_DRIVER -I/Users/***/git/projectXYZ/Src/Peripherals -I/Users/***/git/projectXYZ/Src/Devices -isystem /Users/***/git/projectXYZ/Src -isystem /Users/***/git/projectXYZ/ThirdParty/CMSIS/Include -isystem /Users/***/git/projectXYZ/ThirdParty/CMSIS/Device/ST/STM32G4xx/Include -isystem /Users/***/git/projectXYZ/ThirdParty/STM32G4xx_HAL_Driver/Inc -isystem /Users/***/git/projectXYZ/ThirdParty/STM32G4xx_HAL_Driver/Inc/Legacy -isystem /Users/***/git/projectXYZ/ThirdParty/lvgl-8.2.0 -isystem /Users/***/git/projectXYZ/ThirdParty/FreeRTOS-Kernel-10.4.6/include -isystem /Users/***/git/projectXYZ/ThirdParty/FreeRTOS-Kernel-10.4.6/portable/GCC/ARM_CM4F -isystem /Users/***/git/projectXYZ/ThirdParty/freertos-addons-1.6.0/c++/Source/include -fno-exceptions -fno-rtti -stdlib=libstdc++ -g -std=gnu++17 --target=arm-none-eabi -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 --sysroot=/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/arm-none-eabi -MD -MT Src/CMakeFiles/Application.dir/GuiTask.cpp.obj -MF Src/CMakeFiles/Application.dir/GuiTask.cpp.obj.d -o Src/CMakeFiles/Application.dir/GuiTask.cpp.obj -c /Users/***/git/projectXYZ/Src/GuiTask.cpp
In file included from /Users/***/git/projectXYZ/Src/GuiTask.cpp:1:
In file included from /Users/***/git/projectXYZ/Src/GuiTask.hpp:7:
In file included from /Users/***/git/projectXYZ/ThirdParty/freertos-addons-1.6.0/c++/Source/include/thread.hpp:54:
In file included from /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/arm-none-eabi/include/c++/13.2.1/string:38:
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/arm-none-eabi/include/c++/13.2.1/bits/requires_hosted.h:31:10: fatal error: 'bits/c++config.h' file not found
31 | #include <bits/c++config.h>
| ^~~~~~~~~~~~~~~~~~
1 error generated.
ninja: build stopped: subcommand failed.
Hi @chrisc, i modified makefile generated by stm32cubemx for clang by following this guide. I resolved all the issues and errors. Code compiled successfully using clang and linked all objects by lld. There is no error but when i programmed stm32 and tried to run, controller got stuck. I debugged and found it stuck in hardfault handler called from startupfile.s at bl __libc_init_array during stack constructors calls.
Do i missed some flag specific to clang or i need to re write .ld script? I am using default .ld script generated by stm32cubemx for gcc.