cancel
Showing results for 
Search instead for 
Did you mean: 

Where is the .a file for the default printf family?

PHolt.1
Senior III

I believe it is in libc.a or some such, but I can't see the config in Cube (32F417) and gradually renaming all candidate files in c:\st\... has failed to locate it (by hopefully throwing up an error).

The project is in c:\xxxxxx\project1 but this library is a compiled one, with no .c source supplied, so it lives in c:\st\ where a new version gets loaded with each Cube installation.

The linker invocation is

arm-none-eabi-g++ -o "XXXXXX.elf" @"objects.list"  -mcpu=cortex-m4 -T"C:\XXXXXX\Project1\LinkerScript.ld" --specs=nosys.specs -Wl,-Map="XXXXXX.map" -Wl,--gc-sections -static -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -Wl,--start-group -lc -lm -lstdc++ -lsupc++ -Wl,--end-group

and the Cube settings are

0693W00000QM4FmQAL.pngBackground: I need to replace some symbols in there (with objcopy) because the printf, if used for float or long, is calling a malloc and then some mutex functions, but the mutex functions are just empty. But they were not compiled as "weak" so I get duplicate symbol linker errors.

I think I found the C source for this printf, which closely resembles what I found stepping through the assembler, but I can't tell which options it was compiled with

https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/stdio/vfprintf.c;h=6a198e2c657e8cf44b720c8bec76b1121921a42d;hb=HEAD#l866

17 REPLIES 17

Found one printf lib: https://github.com/mpaland/printf

DISCLAIMER: I haven't used this one (yet), but it was recommended/mentioned by people on this forum whom I trust.

Piranha
Chief II

https://www.eevblog.com/forum/microcontrollers/32f4-hard-fault-trap-how-to-track-this-down/msg4321477/#msg4321477

> vsnprintf(buf, sizeof(buf)-1, ...)

Of course, again not reading the documentation... As the name suggests, the bufsz parameter is a buffer size, not a number of maximum characters allowed.

PHolt.1
Senior III

Isn't that the same thing?

With uint8_t buf[128], calling vsnprintf with (buf, 127) will prevent the output overwriting something after the buffer.

https://www.ibm.com/docs/en/i/7.4?topic=functions-snprintf-print-formatted-data-buffer#snprintf

The snprintf() function is identical to the sprintf() function with the addition of the n argument, which indicates the maximum number of characters (including the ending null character) to be written to buffer.

Well, ok, the -1 is not needed.

On the main topic, I am still having problems with setting up the mutexes. In the end, I gave up on that. I am replacing the whole printf library with a thread-safe one.

Thank you Bob S for that link https://github.com/mpaland/printf. It works! And it avoids mutexes, so now I only need to mutex the heap, and since all usage of malloc and free takes place from C sources, I can mutex those two and edit the calls to them to e.g. malloc_m and free_m. Much better solution!

I am integrating it now. Just need to find a slick way to make existing code use it. Normally printf etc is defined in stdio.h. I can achieve this transparently by including #include "printf.h" in every .c file which is to use the new printf, and tracing the code shows this is working, but if somebody forgets to do this, they will be calling the old one. I can't just remove the old library because it has a load of other stuff in it. I have weakened all these symbols in it (using an objcopy script batch file) enabling the new printf to replace them, but can't remove them because while objcopy can weaken any symbol, it can't remove stuff which is defined in the library with actual code.

Piranha
Chief II

After these two posts about the C documentation I'm starting to have a suspicion of the real problem... You do know that in this forum the blue-colored text has a link attached to it? I mean, for example, you do see the link and can name this musician? That would at least explain not reading half of the given links...

The mpaland implementation is good, but, as I told in the other topic, one of the two recommended implementations by me in this topic, is based on it, but has evolved further.

PHolt.1
Senior III

OK - thanks. I looked up those two printf replacements. The 1st is incomplete (no scientific output etc). The 2nd (https://github.com/MaJerle/lwprintf) seems ok; are you saying it is better than https://github.com/mpaland/printf?

I have just implemented the mpaland one. It seems to work fine. I used 4 steps to integrate it:

1) make a local copy of the current libc.a (the full-everything hardware-float version)

2) run objcopy to weaken all symbols in it

3) linker options to include it (in preference to the default one in c:\st\...)

4) compiler option to avoid the need for #include "printf.h" in every source file

Looking at the MaJerle one, the main thing seems to be the b and k specifiers, which are nice but not essential, and making use of them would produce non-portable code. Maybe there is something else that is important but on a quick read I didn't see it.

It seems to work ok. The existing bloatware is still used for scanf stuff, and heap stuff, of course. I am tempted to replace the heap also.

Funnily enough, the total flash used is down by 1k, so it looks like the linker realised that some modules (.o I think) in libc.a contained wholly unreferenced functions, and removed them.

Piranha
Chief II

At last you are reading... ;)

Both of those implementations seem to be decent. I like that LwPRINTF needs only a single additional pointer for stream-like interface, but that is a minor advantage. Subjectively mpaland implementation seems to be more tested, but LwPRINTF also uses automated tests. Probably the eyalroz implementation suggested on EEVblog forum is the best choice for you.

I'm just using the non-standard APIs with prefixes and actually do not want the names to be mixed with standard APIs.

In the end I would recommend getting rid of a dynamic allocation at all. For FreeRTOS set configSUPPORT_DYNAMIC_ALLOCATION=0 and for lwIP set MEM_USE_POOLS=1 to use memory pools, which have constant sized blocks.

The GNU linker removes unused code and data sections if the "--gc-sections" option is enabled. If you remove the bloatware completely, you should gain some 10-40 KB. There is a nice tool Amap to look for memory usage details.

PHolt.1
Senior III

I looked up configSUPPORT_DYNAMIC_ALLOCATION. Currently I use 1. The RTOS gets a block of RAM (64k - the whole CCM) and within that it runs its own private heap. As each task is defined with e.g. xTaskCreate, this 64k gets gradually filled up. AFAICT FreeRTOS never frees any of this stuff so malloc() should be perfectly safe. Is there another reason to use static allocation? One concern I can see is if FR uses the heap for its message queues, which would be really dumb.

MEM_USE_POOLS and MEM_USE_CUSTOM_POOLS are both set to 0. Unfortunately I have not found any clear documentation on this stuff. The three main items are mem_size, pbuf_pool_size and pbuf_pool_bufsize, and there is a vast amount of conflicting info on the web about these. I think mem_size is used for tx buffers and the other two are for rx buffers, but this is probably wrong.

This is what I currently have and it works

// MEM_SIZE: the size of the heap memory. This is a statically allocated block.
// If MEMP_MEM_MALLOC=0, this holds just the PBUF_ stuff.
// If MEMP_MEM_MALLOC=1 (which is not reliable) this greatly expands and needs 16k+.
// Empirically this needs to be big enough for at least 4 x PBUF_POOL_BUFSIZE.
// 6k yields a good speed and going to 8k+ makes a minimal improvement. The main
// factor affecting speed is the poll period in ethernetif_input().
#define MEM_SIZE                (6*1024)
 
// MEMP_ structures. It has been impossible to find out how big these are individually.
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
   sends a lot of data out of ROM (or other static memory), this
   should be set high. */
#define MEMP_NUM_PBUF           5
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
   per active UDP "connection". */
#define MEMP_NUM_UDP_PCB        6
/* MEMP_NUM_TCP_PCB: the number of simultaneously active TCP
   connections. */
#define MEMP_NUM_TCP_PCB        5
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
   connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 5
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
   segments. */
#define MEMP_NUM_TCP_SEG        8
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
   timeouts. */
#define MEMP_NUM_SYS_TIMEOUT    10
 
 
/* ---------- Pbuf dynamically allocated buffer blocks - for both TX and RX data ---------- */
// Two basic ideas are shown. The 8x512 is supposedly better than the commented-out one.
// The 512 byte mode will hold a full size packet in 3 buffers. The concatenation is
// automatic in LWIP. These two settings make NO difference to ETH speed.
 
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE           8
 
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
// If small, set it so that say 3 of them hold a complete largest packet (1500+stuff)
#define PBUF_POOL_BUFSIZE        512  // 1500 + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN

and some of the comments are probably wrong.

Thanks for the AMAP tip. It looks like a good tool. Unfortunately to lose say 30k I would need to replace all the functions in libc.a, or at least enough functions so that a whole .o module (the libc.a contains a load of these) can then be dropped by the linker. I don't think the linker can remove a part of a .o file. A compiler will remove unreferenced or unreachable code but I don't have the .c source for that ST libc.a library. So I would need to replace the scanf family, and the heap stuff, but that is working ok. Tracing code suggests that scanf is not using mutexes, which suggests the writer did not feel it needs thread protection (unlike printf where mutexes were used even if not the heap - e.g. %d invoked mutexes but not heap, while %l and %f invoked both). And on malloc and free I replaced the empty mutex stubs with a real (ex FreeRTOS) mutex, non recursive because I can't see who the hell would want recursive mallocs, so that should work, especially as almost nothing uses the heap now, and the only use now is for malloc and no free, which is safe. The only free() is within the TLS private heap, so that remains non deterministic but nothing can be done, and that whole heap gets chucked away when that HTTPS connection is closed.

If you have ideas on the lwipopts.h stuff I am very interested but I have already spent many days on it, with negligible effects. By far the biggest optimisation would be interrupt driven ETH RX, but how do people deal with an installation scenario where the product sees loads of traffic at the RJ45, and grinds to a halt?

Has anyone implemented packet filtering (by IP) at the low level ETH interface? A sort of primitive but fast firewall. The vast majority of ETH products need to respond to rx packets with just one destination IP.

PHolt.1
Senior III

BTW I used AMAP to see which functions are still left in that libc.a library, and I think most of them (apart from the heap) are very small

../LIBC/LIBCW\libc-weakened.a	lib_a-strcmp.o	84	84	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strlen.o	39	39	2
../LIBC/LIBCW\libc-weakened.a	lib_a-atoi.o	112	112	3
../LIBC/LIBCW\libc-weakened.a	lib_a-calloc.o	104	104	3
../LIBC/LIBCW\libc-weakened.a	lib_a-callocr.o	206	206	3
../LIBC/LIBCW\libc-weakened.a	lib_a-errno.o	100	100	3
../LIBC/LIBCW\libc-weakened.a	lib_a-exit.o	128	128	3
../LIBC/LIBCW\libc-weakened.a	lib_a-gmtime.o	104	104	3
../LIBC/LIBCW\libc-weakened.a	lib_a-gmtime_r.o	448	448	3
../LIBC/LIBCW\libc-weakened.a	lib_a-init.o	172	172	3
../LIBC/LIBCW\libc-weakened.a	lib_a-itoa.o	164	164	4
../LIBC/LIBCW\libc-weakened.a	lib_a-malloc.o	136	136	4
../LIBC/LIBCW\libc-weakened.a	lib_a-mallocr.o	2300	2352	10
../LIBC/LIBCW\libc-weakened.a	lib_a-memcmp.o	128	128	3
../LIBC/LIBCW\libc-weakened.a	lib_a-memcpy-stub.o	122	122	3
../LIBC/LIBCW\libc-weakened.a	lib_a-memmove.o	148	148	3
../LIBC/LIBCW\libc-weakened.a	lib_a-memset.o	104	104	3
../LIBC/LIBCW\libc-weakened.a	lib_a-rand.o	168	168	3
../LIBC/LIBCW\libc-weakened.a	lib_a-sbrkr.o	132	132	3
../LIBC/LIBCW\libc-weakened.a	lib_a-sscanf.o	264	264	3
../LIBC/LIBCW\libc-weakened.a	lib_a-stdio.o	330	330	7
../LIBC/LIBCW\libc-weakened.a	lib_a-strcasecmp.o	152	152	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strcat.o	126	126	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strchr.o	114	114	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strcpy.o	104	104	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strncasecmp.o	168	168	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strncat.o	138	138	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strncmp.o	136	136	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strncpy.o	134	134	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strnstr.o	170	170	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strrchr.o	152	152	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strtol.o	440	440	5
../LIBC/LIBCW\libc-weakened.a	lib_a-strtoul.o	408	408	5
../LIBC/LIBCW\libc-weakened.a	lib_a-svfscanf.o	5119	5119	5
../LIBC/LIBCW\libc-weakened.a	lib_a-sysconf.o	122	122	3
../LIBC/LIBCW\libc-weakened.a	lib_a-time.o	152	152	3
../LIBC/LIBCW\libc-weakened.a	lib_a-utoa.o	297	297	4
../LIBC/LIBCW\libc-weakened.a	lib_a-vsprintf.o	180	180	4
../LIBC/LIBCW\libc-weakened.a	lib_a-writer.o	136	136	3
../LIBC/LIBCW\libc-weakened.a	lib_a-__call_atexit.o	356	356	6
../LIBC/LIBCW\libc-weakened.a	lib_a-atexit.o	100	100	3
../LIBC/LIBCW\libc-weakened.a	lib_a-closer.o	132	132	3
../LIBC/LIBCW\libc-weakened.a	lib_a-fini.o	152	152	3
../LIBC/LIBCW\libc-weakened.a	lib_a-freer.o	700	700	4
../LIBC/LIBCW\libc-weakened.a	lib_a-gettimeofdayr.o	136	136	3
../LIBC/LIBCW\libc-weakened.a	lib_a-iswspace.o	94	94	3
../LIBC/LIBCW\libc-weakened.a	lib_a-iswspace_l.o	108	108	3
../LIBC/LIBCW\libc-weakened.a	lib_a-locale.o	514	514	6
../LIBC/LIBCW\libc-weakened.a	lib_a-localeconv.o	128	128	3
../LIBC/LIBCW\libc-weakened.a	lib_a-lock.o	240	243	9
../LIBC/LIBCW\libc-weakened.a	lib_a-lseekr.o	136	136	3
../LIBC/LIBCW\libc-weakened.a	lib_a-mbrtowc.o	181	181	4
../LIBC/LIBCW\libc-weakened.a	lib_a-mbtowc_r.o	164	164	3
../LIBC/LIBCW\libc-weakened.a	lib_a-memchr-stub.o	124	124	3
../LIBC/LIBCW\libc-weakened.a	lib_a-memmem.o	168	168	3
../LIBC/LIBCW\libc-weakened.a	lib_a-readr.o	136	136	3
../LIBC/LIBCW\libc-weakened.a	lib_a-realloc.o	104	104	3
../LIBC/LIBCW\libc-weakened.a	lib_a-reallocr.o	992	992	3
../LIBC/LIBCW\libc-weakened.a	lib_a-sccl.o	212	212	3
../LIBC/LIBCW\libc-weakened.a	lib_a-sf_nan.o	100	100	3
../LIBC/LIBCW\libc-weakened.a	lib_a-sprintf.o	228	228	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strnlen.o	120	120	3
../LIBC/LIBCW\libc-weakened.a	lib_a-strtod.o	3582	3582	9
../LIBC/LIBCW\libc-weakened.a	lib_a-strtoll.o	472	472	4
../LIBC/LIBCW\libc-weakened.a	lib_a-strtoull.o	476	476	4
../LIBC/LIBCW\libc-weakened.a	lib_a-svfiscanf.o	536	536	5
../LIBC/LIBCW\libc-weakened.a	lib_a-svfprintf.o	5284	5284	6
../LIBC/LIBCW\libc-weakened.a	lib_a-ungetc.o	258	258	3
../LIBC/LIBCW\libc-weakened.a	lib_a-wctomb_r.o	142	142	3
../LIBC/LIBCW\libc-weakened.a	lib_a-__atexit.o	244	244	3
../LIBC/LIBCW\libc-weakened.a	lib_a-dtoa.o	3575	3575	5
../LIBC/LIBCW\libc-weakened.a	lib_a-fflush.o	506	506	4
../LIBC/LIBCW\libc-weakened.a	lib_a-findfp.o	612	612	9
../LIBC/LIBCW\libc-weakened.a	lib_a-fwalk.o	202	202	3
../LIBC/LIBCW\libc-weakened.a	lib_a-gdtoa-gethex.o	1655	1655	6
../LIBC/LIBCW\libc-weakened.a	lib_a-gdtoa-hexnan.o	560	560	5
../LIBC/LIBCW\libc-weakened.a	lib_a-mprec.o	3276	3276	24
../LIBC/LIBCW\libc-weakened.a	lib_a-s_frexp.o	212	212	3
../LIBC/LIBCW\libc-weakened.a	lib_a-s_nan.o	104	104	3
../LIBC/LIBCW\libc-weakened.a	lib_a-svfiprintf.o	426	426	3
../LIBC/LIBCW\libc-weakened.a	lib_a-assert.o	240	240	4
../LIBC/LIBCW\libc-weakened.a	lib_a-fclose.o	290	290	3
../LIBC/LIBCW\libc-weakened.a	lib_a-fiprintf.o	192	192	3
../LIBC/LIBCW\libc-weakened.a	lib_a-vfiprintf.o	2898	2898	8
../LIBC/LIBCW\libc-weakened.a	lib_a-wsetup.o	276	276	3
../LIBC/LIBCW\libc-weakened.a	lib_a-abort.o	110	110	3
../LIBC/LIBCW\libc-weakened.a	lib_a-fputwc.o	390	390	4
../LIBC/LIBCW\libc-weakened.a	lib_a-fvwrite.o	776	776	3
../LIBC/LIBCW\libc-weakened.a	lib_a-makebuf.o	360	360	4
../LIBC/LIBCW\libc-weakened.a	lib_a-signal.o	358	358	4
../LIBC/LIBCW\libc-weakened.a	lib_a-signalr.o	156	156	4
../LIBC/LIBCW\libc-weakened.a	lib_a-wbuf.o	266	266	3
../LIBC/LIBCW\libc-weakened.a	lib_a-wcrtomb.o	168	168	3
../LIBC/LIBCW\libc-weakened.a	lib_a-fstatr.o	136	136	3
../LIBC/LIBCW\libc-weakened.a	lib_a-isattyr.o	132	132	3
../LIBC/LIBCW\libc-weakened.a	lib_a-ctype_.o	313	313	2
../LIBC/LIBCW\libc-weakened.a	lib_a-impure.o	1128	1128	4
../LIBC/LIBCW\libc-weakened.a	lib_a-lnumeric.o	105	105	5

 FWIW I noticed that a lot of the Size values are obviously meaningless for some modules. They look about right for some others. MbedTLS is 150k in the final build but AMAP shows the total size of it as some megabytes.

I also see that svfprintf is still in the old lib above, at 5k+, so that replacement printf didn't replace it. Indeed it doesn't have an svfprintf. In fact I struggle to see what svfprintf actually does... But I made one crucial discovery: vsprintf is still in the old lib, still using the heap etc (just verified by tracing code) so I need a replacement for that. I have just one instance of vsprintf in the whole project.