|
Description
|
[ahl 8.18.2005]
As Bryan Cantrill wrote:
Hey Rich,
On Tue, Aug 16, 2005 at 10:59:44PM -0400, Richard Lowe wrote:
> I spent a while earlier adding an SDT provider to ruby (purely to learn
> how to do it.)
Spicey!
> Ruby puts most of the interpreter in a static library
> (libruby-static.a), unless configured --enable-shared.
>
> If my probe is in this static library, it is not visible after linking
> the ruby executable (I'm running Nevada b19, i86pc/i386)
>
> However, if I configure it with --enable-shared, the probe is visible.
> Also, if I hack the makefile such that rather than linking
> libruby-static.a into the executable, it links the objects directly, the
> probe is also visible.
This is actually a symptom of some larger strangeness with respect to
archives and .init processing. The key is that archives are not like shared
objects -- they are really more a collection of objects that happen to be
represented as a single file in the file system. (That is, ar(1) and tar(1)
are closer in spirit than you might realize.) And in particular, when you
link against an archive, it _only_ pulls in the _object files_ that you
need. This means that if you need a symbol found in some object, that whole
object gets linked into the resulting object -- .init section and all. If
an object isn't needed, that object isn't linked at all -- and any .init and
.fini sections in that object are silently ignored. The Linkers and
Libraries manual actually warns about this (if opaquely) in "Initialization
and Termination Sections":
Initialization and termination code, spread throughout several
relocatable objects, can result in different behavior when included in
an archive library or shared object. The link-edit of an application
that uses this archive might extract only a fraction of the objects
contained in the archive. These objects might provide only a portion
of the initialization and termination code spread throughout the
members of the archive. At runtime, only this portion of code is
executed. The same application built against the shared object will
have all the accumulated initialization and termination code executed
when the dependency is loaded at runtime.
(See http://docs.sun.com/app/docs/doc/817-1984/6mhm7pl17?q=init&a=view)
And that, in a nutshell, is what's nailing you here. When we generate the
.o with the probe definition in it (testprovider.o in your case), we very
much rely on the .init section for that object being currectly processed and
run. (That's how your probes make themselves known to the system.) But
when you toss testprovider.o in an archive, there is no reason for that
object to be pulled out of the archive for linking against main.o -- so it
never goes along for the ride, the .init section in testprovider.o is never
run, and your probes are never created. Fortunately, solving this problem
isn't too bad: when you generate the .o that contains the provider, turn
around and link that new object right back against the object(s) that you
passed to dtrace(1M) to form a new, larger glommed object. Then use _that_
object to create the archive. To put this in terms of your test case,
you want to change the build procedure for libtestcase.a to be:
dtrace -G -32 -o testprovider.o -s testprovider.d testfunc.o
ld -r -o glommedobj.o testprovider.o testfunc.o
ar rcu libtestcase.a glommedobj.o
Doing this yields a libtestcase.a that can be correctly used as an archive.
So it's actually not so bad -- but oh boy does it need to be documented...
- Bryan
|