1
0
mirror of https://github.com/rfivet/stm32bringup.git synced 2025-10-15 07:24:01 -04:00
Files
stm32bringup/docs/36_update.html
2025-10-03 14:23:32 +08:00

180 lines
5.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3.6 Toolchain Update</title>
<link type="text/css" rel="stylesheet" href="style.css">
</head>
<body>
<h1>3.6 Toolchain Update</h1>
When a new release of GNU ARM Embedded Toolchain comes out, I have to do some
adaptations when switching to it.
<p>
By example, to switch from release 9 update to release 10 major, I made three
changes to <b>Makefile</b>.
<p>
● Update the Linux base directory location:
<pre>
#GCCDIR = $(HOME)/Packages/gcc-arm-none-eabi-9-2020-q2-update
GCCDIR = $(HOME)/Packages/gcc-arm-none-eabi-10-2020-q4-major
</pre>
● Update the Windows base directory location:
<pre>
#GCCDIR = D:/Program Files (x86)/GNU Arm Embedded Toolchain/9 2020-q2-update
GCCDIR = D:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major
</pre>
● Update the library subdirectory location:
<pre>
#LIBDIR = $(GCCDIR)/lib/gcc/arm-none-eabi/9.3.1/thumb/v6-m/nofp
LIBDIR = $(GCCDIR)/lib/gcc/arm-none-eabi/10.2.1/thumb/v6-m/nofp
</pre>
In the case of release 10 major, unfortunately while doing some regression
testing by recompiling the projects so far, I found that the new release
optimizes further the C startup clearing of BSS data by calling
<code>memset()</code> from the distribution libraries.
<pre>
$ make
f030f4.elf from startup.txeie.o adc.o adcmain.o
D:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2020-q4-major\bin\arm-none-
eabi-ld.exe: startup.txeie.o: in function `Reset_Handler':
D:\Renau\Documents\Projects\stm32bringup\docs/startup.txeie.c:126: undefined ref
erence to `memset'
make: *** [mk8:61: f030f4.elf] Error 1
</pre>
So I had to add <b>libc.a</b> and its location on top of <b>libgcc.a</b>
to the list of libraries.
<pre>
LIBS = -l$(LIBSTEM) -lc -lgcc
LIB_PATHS = -L. -L$(GCCDIR)/arm-none-eabi/lib/thumb/v6-m/nofp -L$(LIBDIR)
</pre>
with <b>libc.a</b> the link phase complete successfully.
<pre>
f030f4.elf from startup.txeie.o adc.o adcmain.o
text data bss dec hex filename
2644 0 16 2660 a64 f030f4.elf
</pre>
<p>
As I don't want to turn off size optimization and I am not willing to
always pay the full 180 bytes for a production ready <code>memset()</code>
when it is called only once at startup to clear a few bytes, I ended up adding
my own version of <code>memset()</code> to my local library.
<pre>
#include &lt;string.h>
void *memset( void *s, int c, size_t n) {
char *p = s ;
while( n--)
*p++ = c ;
return s ;
}
</pre>
<pre>
LIBOBJS = printf.o putchar.o puts.o memset.o
</pre>
Link succeed with a reduction of 152 bytes of code.
<pre>
f030f4.elf from startup.txeie.o adc.o adcmain.o
text data bss dec hex filename
2492 0 16 2508 9cc f030f4.elf
</pre>
<h2>GCC front end handling the libraries selection</h2>
As I was investigating the compilation flags to find if there was a
better way to solve this issue, I figure out I could let <b>gcc</b> handle
the distribution libraries selection and their location based on the CPU
type. So I changed the linker invocation accordingly and got rid of LD,
LIBDIR and LIB_PATHS definitions.
<pre>
# $(LD) -T$(LD_SCRIPT) $(LIB_PATHS) -Map=$(PROJECT).map -cref -o $@ $(OBJS) $(LIBS)
$(CC) $(CPU) -T$(LD_SCRIPT) -L. -Wl,-Map=$(PROJECT).map,-cref \
-nostartfiles -o $@ $(OBJS) -l$(LIBSTEM)
</pre>
As the compiler front end is now controlling the libraries selection it is
possible to give it a hint how to select a better optimized memset(). The
libc library comes in two flavors: regular and nano.
<pre>
OBJS = $(SRCS:.c=.o)
LIBOBJS = printf.o putchar.o puts.o # memset.o
CPU = -mthumb -mcpu=cortex-m0 --specs=nano.specs
</pre>
<code>memset()</code> included in the nano version of libc occupies the same
space as my own implementation.
<pre>
f030f4.elf from startup.txeie.o adc.o adcmain.o
text data bss dec hex filename
2492 0 16 2508 9cc f030f4.elf
</pre>
<h2>PATH based command selection</h2>
Finally, I revised the way I specify the commands location by updating the
PATH environment variable in the Makefile instead of giving the full path of
each command.<br>
On Windows, I make sure that drive specification matches the development
environment in use (Cygwin, MSYS2 and other).
<pre>
### Build environment selection
ifeq (linux, $(findstring linux, $(MAKE_HOST)))
INSTALLDIR = $(HOME)/Packages
#REVDIR = gcc-arm-none-eabi-10-2020-q4-major
REVDIR = arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi
else
DRIVE = d
ifeq (cygwin, $(findstring cygwin, $(MAKE_HOST)))
OSDRIVE = /cygdrive/$(DRIVE)
else ifeq (msys, $(findstring msys, $(MAKE_HOST)))
OSDRIVE = /$(DRIVE)
else
OSDRIVE = $(DRIVE):
endif
INSTALLDIR = $(OSDRIVE)/Program Files (x86)
#REVDIR = GNU Arm Embedded Toolchain/10 2020-q4-major
REVDIR = GNU Arm Embedded Toolchain/arm-gnu-toolchain-14.2.rel1-mingw-w64-i686-arm-none-eabi
endif
GCCDIR = $(INSTALLDIR)/$(REVDIR)
export PATH := $(GCCDIR)/bin:$(PATH)
BINPFX = @arm-none-eabi-
AR = $(BINPFX)ar
CC = $(BINPFX)gcc
OBJCOPY = $(BINPFX)objcopy
OBJDUMP = $(BINPFX)objdump
SIZE = $(BINPFX)size
</pre>
Switching back to latest version of the toolchain at the time of writing this,
the link shows further improvement of the code size. The optimization via
<code>memset()</code> has been skipped by the compiler.
<pre>
f030f4.elf from startup.txeie.o adc.o adcmain.o
text data bss dec hex filename
2464 0 16 2480 9b0 f030f4.elf
</pre>
<h2>Checkpoint</h2>
Invoking the compiler instead of the linker gives more flexibility in
case the toolchain directory structure changes or if I target a
different core. The compiler is aware of the location of the toolchain
libraries while the linker need explicit parameters to handle those
changes.
<p>
<a href="37_inram.html">Next</a>, I will (re)build to execute code in RAM
instead of FLASH.
<hr>© 2020-2025 Renaud Fivet
</body>
</html>