2022-07-25 05:35 AM
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
Background: 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
2022-07-25 03:14 PM
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.
2022-07-27 04:56 AM
> 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.
2022-07-27 08:01 AM
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.
2022-07-27 08:34 AM
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.
2022-07-27 09:17 AM
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.
2022-07-28 03:57 PM
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.
2022-07-29 03:43 AM
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.
2022-07-29 04:00 AM
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.