Question on __retarget_lock function

sam.edge.newlib@gmx.com sam.edge.newlib@gmx.com
Sat Dec 7 11:03:56 GMT 2024


On 07/12/2024 08:58, Kedar Karandikar wrote:
> Hi
> I am trying to override the __retarget_lock* dummy functions that are 
> provided by NewLib lock.c in my baremetal environment.
> 
> I was trying not to touch the newlib source code, but rather implement 
> those functions in my framework.
> 
> However, the functions defined in lock.c do not have a “weak” attribute 
> next to the functions and this causes linker error when I try to define 
> them in my framework.
> 
> Any reason why they are not defined as weak? Is the expectation that I 
> update the functions directly in newlib lock.c and compile the newlib 
> after that?
> 
> Thanks for the help!
> 
> -Kedar K Karandikar

I had the same problem with the version of Newlib provided with the GCC 
toolchain with STM's STM32CubeIDE. (And the OpenSTM32 Workbench one as 
well.)

The problem is that 'struct _lock' and _LOCK_T (struct _lock *) are 
supposed to be defined by the target platform implementer. Because of 
this, the functions cannot be defined as weak so as to be overridable by 
the end user.

Newlib's lock.c is simply an example dummy implementation but STM in 
their stupidity chose to simply compile in this code which defines 
struct _lock as being a single byte structure.

That makes reimplementing for, say, FreeRTOS tricky. What I did was use 
GCC's symbol wrapper to reimplement all the __retarget_lock_xxxx() 
functions and overlay them in the linker. (See the GCC LD --wrap option.)

The functions can simply cast the _LOCK_T arguments to pointers to the 
real mutex objects (e.g. cast to SemaphoreHandle_t which is itself a 
pointer to an opaque mutex object) and do similar for the _LOCK_T 
pointer output parameters in the init functions after obtaining a mutex 
pointer from the threading library.

However all the wrapper functions check their  _LOCK_T arguments against 
a static lookup table mapping from pointers to the predefined library 
lock objects (e.g. &__lock___sinit_recursive_mutex) to actual mutex 
objects/object pointers values.

Before starting the main() and switching into multithreaded mode, I call 
an internal function that creates/initialized recursive or non-recursive 
mutexes as appropriate for all the NULL SemaphoreHandle_t values in the 
lookup table.

It's messy but it works.

Unfortunately, that's just the start of your problem if your vendor has 
compiled in the dummy lock.c. If they've compiled GCC single-threaded, 
the C++ STL, C & C++ atomics either aren't implemented or aren't thread 
safe either which has knock-on effects for everything else in the C++ 
libraries when using a pre-emptive threading library

A better approach to take if you have the time is to bite the bullet and 
create your own GCC & newlib toolchain, provide the required stubs for 
all newlib's locking and for POSIX threads using your threading library 
and compile GCC as POSIX-thread aware. That way all the C/C++ atomics 
and Newlib APIs are fully reentrant. But it's a much bigger job of course.

-- 
Sam Edge
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0xE6200DE0C92CEC06_and_old_rev.asc
Type: application/pgp-keys
Size: 1140 bytes
Desc: OpenPGP public key
URL: <https://sourceware.org/pipermail/newlib/attachments/20241207/a9213cc1/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 236 bytes
Desc: OpenPGP digital signature
URL: <https://sourceware.org/pipermail/newlib/attachments/20241207/a9213cc1/attachment.sig>


More information about the Newlib mailing list