cgo without the stub so files

15 views
Skip to first unread message

Russ Cox

unread,
Aug 25, 2010, 6:36:36 PM8/25/10
to Ian Lance Taylor, golang-dev
I have package net building and running
on Linux and OS X using the C library
getaddrinfo for name resolution. This
addresses a host of shortcomings in the
Go implementation and ensures parity
with other languages as new features
get added (for example, on OS X getaddrinfo
handles SRV records correctly).

Using cgo as it is now means that if you
use package net, your binary would not be
standalone anymore: it would depend on
finding libcgo.so and cgo_net.so, probably
in $GOROOT/pkg/$GOOS_$GOARCH, and
of course on the system libc and libpthread
libraries. I don't mind the system libraries
much - they're kind of the whole point of this
exercise - but I don't think I can stomach
the tiny stub libraries libcgo.so and cgo_net.so.
Having to drag those along is going to make
deploying Go binaries significantly harder.

Those stub .so files only exist because it was
quick: 6l didn't know how to deal with ELF objects
and it was easier to make it emit references to
.so files than to write the ELF importing code
(and s/ELF/Mach-O/ on the Mac). We need to
fix this. Somehow, those (or equivalent) objects
need to get linked into the actual binary directly.
Bonus points if the right debug info ends up
there too.

One possibility is to write the code to read these
objects in C and put it in 5l, 6l, 8l. Another is to
write the code in Go and have cgo translate the
object files to .5, .6, or .8. I am exploring now.

Separate from that, one possibility is to use the .o
directly and another is to use the .so. (In both
cases the object would not persist beyond the link
stage.) My question for Ian is: which of these would
make more sense? It looks like .so because the
information about which dynamic libraries to point
at has been computed and resolved.

Any suggestions or tips?

Russ

Ian Lance Taylor

unread,
Aug 25, 2010, 7:21:12 PM8/25/10
to r...@golang.org, golang-dev
Russ Cox <r...@golang.org> writes:

> Those stub .so files only exist because it was
> quick: 6l didn't know how to deal with ELF objects
> and it was easier to make it emit references to
> .so files than to write the ELF importing code
> (and s/ELF/Mach-O/ on the Mac). We need to
> fix this. Somehow, those (or equivalent) objects
> need to get linked into the actual binary directly.
> Bonus points if the right debug info ends up
> there too.
>
> One possibility is to write the code to read these
> objects in C and put it in 5l, 6l, 8l. Another is to
> write the code in Go and have cgo translate the
> object files to .5, .6, or .8. I am exploring now.
>
> Separate from that, one possibility is to use the .o
> directly and another is to use the .so. (In both
> cases the object would not persist beyond the link
> stage.) My question for Ian is: which of these would
> make more sense? It looks like .so because the
> information about which dynamic libraries to point
> at has been computed and resolved.

One possibility I didn't see above: change 6l to generate an ELF .o file
rather than an ELF executable. Then use the usual ELF linker to link
that with any necessary support code. Pro: reasonably simple. Con:
takes longer to link a program.

Whatever you start with, in order for 6l to do the final link, it's
going to need to do the usual ELF dynamic linking things. 6l already
does some of them, but it will additionally have to generate a PLT and a
GOT and the associated dynamic relocs. The current code imports dynamic
symbols as though they were variables, which is OK because it is written
to expect that. But obviously the any code generated by gcc will not
expect that. If we can restrict the generated code to calling functions
defined in other libraries--i.e., no references to global
variables--then we just need the PLT/GOT/relocs, which is fairly simple.
Referring to global variables defined in shared libraries is also not
too hard. In general if we can steer clear of any attempts to define a
symbol in the program which the shared library will see, that would be
simplest.

Aside from the dynamic linking issues, ELF linking is reasonably
straightforward: you copy in the sections, apply the relocs, and define
the symbols. There are certain complexities with stack unwind
information, but I think we can disregard that since stack unwinding
through the Go code won't work anyhow.

That said, converting the ELF .o into a .6 file has some obvious
attractions. If we could extend the .6 file format to direct 6l to
build a PLT entry (and we could somehow figure out which symbols needed
PLT entries) then it would just be a matter of ensuring that the .6
format can support all the relocations found in an ELF .o.

In any case, it does not make sense to me to try to make 6l read an ELF
.so rather than an ELF .o. A .so is already linked; it's basically an
executable which happens to be position independent. You can't in
general reverse engineer it back into something which you can link
statically into your program. Well, I suppose you can in principle, but
it's really not any easier. You would have to pull out the dynamic
relocs anyhow so that the dynamic linker can find them. The issue about
which shared libraries to look at is fairly simple in ELF, as the
dynamic linker takes care of all that anyhow.

I would have to read more about Mach-O to know what is involved there.
The model is definitely more complicated than the ELF model.


Anyhow, I think that the simplest approach for ELF will be to convert
the ELF .o file into a .6 file, and teach 6l how to generate a PLT.
That will keep most of the work out of 6l.

Ian

Reply all
Reply to author
Forward
0 new messages