GNU ld --wrap limitations

Chris Johns chrisj at rtems.org
Mon Jan 14 22:33:49 UTC 2019


On 14/1/19 8:22 pm, Sebastian Huber wrote:
> 
> while testing the event recording with the libbsd I noticed a GNU ld --wrap
> limitation:
> 
> https://www.sourceware.org/ml/binutils/2018-12/msg00210.html
> 

I have been watching the thread. There is a limit to what binutils or any method
can do as compiler technology improves.

An example we currently build RTEMS with a single C file on the command line, I
wonder what RTEMS's score would look like if all C files are passed to the
compiler at once and it can optimise over all files as if included in a single
source file. A number of externals we current have would not be visible and
traceable using this method.

> It turned out that the wrapping doesn't work for references internal to a
> translation unit.

The reach for this issue is changing as the push to better optimise the
generated code. If the compiler can remove or optimise an external call as an
internally reference it will.

> My hope was that the RTEMS Trace Linker doesn't have this
> limitation, but the documentation says (user manual):
> 
> "The trace linker’s major role is to wrap functions in the existing executable
> with trace code. The
> directions on how to wrap application functions is provided by the generator
> configuration. The
> wrapping function uses a GNU linker option called –wrap=symbol."
> 

https://devel.rtems.org/wiki/Developer/Tracing/Trace_Linker#Limitation

... highlights the need for an external reference.

> In the libbsd a lot of things are done through function pointer assignments, e.g.
> 
> static struct netisr_handler ip_nh = {
>     .nh_name = "ip",
>     .nh_handler = ip_input,
>     .nh_proto = NETISR_IP,
> #ifdef    RSS
>     .nh_m2cpuid = rss_soft_m2cpuid_v4,
>     .nh_policy = NETISR_POLICY_CPU,
>     .nh_dispatch = NETISR_DISPATCH_HYBRID,
> #else
>     .nh_policy = NETISR_POLICY_FLOW,
> #endif
> };
> 
> or
> 
> /*
>  * Perform common duties while attaching to interface list
>  */
> void
> ether_ifattach(struct ifnet *ifp, const u_int8_t *lla)
> {
>     int i;
>     struct ifaddr *ifa;
>     struct sockaddr_dl *sdl;
> 
>     ifp->if_addrlen = ETHER_ADDR_LEN;
>     ifp->if_hdrlen = ETHER_HDR_LEN;
>     if_attach(ifp);
>     ifp->if_mtu = ETHERMTU;
>     ifp->if_output = ether_output;
>     ifp->if_input = ether_input;
> 
> This makes the tracing quite ineffective in this area.
> 

I suspect the compiler is using a local offset to the code in the file. There
are other cases, for example C++.

I have recently been considering the role libdl can place in hooking trace code
and the effect of deferring the ability to wrap to the target. I suspect it
would not resolve the problem you face because there are no reloc records to the
internal offsets being used but I have not checked. If the DWARF info holds call
or block data maybe hot patching the code might be possible. This would need
host processing to extract the hot patch data.

I consider the wrap method of tracing as a low cost portable API tracer that is
useful for things like malloc/free. It is not like a hardware trace device that
can see everything so I consider there exists a cost/functionality curve.

Chris


More information about the devel mailing list