Open cherrymui opened 6 years ago
cc @aclements
We use the system linker. We want the export data to be present in a shared library, but not in an executable. I don't know of a way to tell the linker to do that.
Perhaps we could have the go tool run objcopy --remove-section .go_export EXECUTABLE
.
Executable produced by gollvm doesn't have the export data. The .o and .a files have the .go_export sections, but they don't get linked into the final executable. Gollvm invokes the linker as
/usr/bin/ld.gold -o /tmp/go-build295362102/b001/exe/a.out --eh-frame-hdr -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/7.3.0/crtbegin.o -( --whole-archive /tmp/go-build295362102/b001/_pkg_.a --no-whole-archive -) --build-id=0x756b496c416977546553707855656f4d455539372f6d7a496b493163304963724574445653723442502f6f57667a39426869472d3133595a42556f5250452f756b496c416977546553707855656f4d45553937 -m elf_x86_64 -L/usr/local/google/home/cherryyz/w/gollvm/bin/../lib64 -lgobegin -Bstatic -lgo -Bdynamic -L/usr/lib/gcc/x86_64-linux-gnu/7.3.0 -L/usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../x86_64-linux-gnu -lpthread -lm --wrap=pthread_create -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/7.3.0/crtend.o /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../x86_64-linux-gnu/crtn.o
gccgo linking uses collect2, as
collect2 --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o /tmp/go-build236096397/b001/exe/a.out /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/local/google/home/cherryyz/w/gccgo2/lib/gcc/x86_64-pc-linux-gnu/9.0.0/crtbegin.o -L/usr/local/google/home/cherryyz/w/gccgo2/lib/gcc/x86_64-pc-linux-gnu/9.0.0 -L/usr/local/google/home/cherryyz/w/gccgo2/lib/gcc/x86_64-pc-linux-gnu/9.0.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/local/google/home/cherryyz/w/gccgo2/lib/gcc/x86_64-pc-linux-gnu/9.0.0/../../.. -( --whole-archive /tmp/go-build236096397/b001/_pkg_.a --no-whole-archive -) --build-id=0x5732536f5472715a564e36356b4d46326f42762d2f4a4961684b5f6e78615f2d64597278507a794a392f786d31684579334e452d383664597a596654474e2f5732536f5472715a564e36356b4d46326f42762d -lgobegin -Bstatic -lgo -Bdynamic -lpthread -lm --wrap=pthread_create -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/google/home/cherryyz/w/gccgo2/lib/gcc/x86_64-pc-linux-gnu/9.0.0/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o
The flags looks pretty similar. I don't know what makes the difference.
Does a shared library produced by gollvm have the export data?
I'm not sure what is the "right" way to produce a shared library with gccgo (or gollvm). I tried
$ gccgo -shared -o libp.so p.go
(where p.go is not main package)
This works, and libp.so contains the export data. I can then import it, like
$ gccgo -I. -c main.go
$ gccgo main.o libp.so
$ LD_LIBRARY_PATH=$PWD:$GCCGOINSTALLDIR/lib64 ./a.out
(where main.go import package p)
With gollvm, libp.so doesn't have the export data, and I cannot do the above.
$ llvm-goc -shared -o libp.so p.go
$ llvm-goc -I. -c main.go
main.go:3:9: error: ./libp.so exists but does not contain any Go export data
main.go:3:9: error: libp.so exists but does not contain any Go export data
main.go:3:9: error: import file 'p' not found
main.go:5:15: error: reference to undefined name 'p'
I looked into this. The reason is that when generating the object file, the .go_export section has the "e" (exclude) flag set. Gccgo doesn't set this flag. If I don't set this flag, shared libraries will have the export data, so will executables. Is there a way to instruct the linker to drop a section when we are linking executable?
In "normal" builds (i.e. using the go tool, instead of invoking gccgo or llvm-goc manually), does it need to look up the export data from shared libraries? When?
cc @thanm
I'm wondering how important it is to support this use case -- do people actually rely on this behavior?
I also don't know how important it is to put export information in a shared library. Historically it worked naturally with gccgo -o libpkg.so -shared PKGFILES
. This assumed that you built most of your packages that way. Then import "pkg"
would find libpkg.so
and pull the export data from the .go_export
section and everything would work smoothly. If we start adding SHF_EXCLUDE
to the .go_export
section, that approach would stop working.
But I don't know if anybody actually does that. Now that gccgo includes the Go tool, it should in principle work to use go install -buildmode=shared PKG
. That will install two different files: PKGPATH/libPKG.a
and libPKGPATH.so
. With this model, gccgo should find libPKG.a
and extract the export information from there.
My preference would be to keep the current behavior (not incorporate the export data when linking) -- perhaps as a fallback we could add a command line flag to enable it (in case someone really needs this)?
I guess a command line option would be consistent with the general GCC approach to these matters.
With gccgo,
Dumping out the .go_export section, it looks like indeed export data. I think it is not needed at run time. It probably should not be linked into the binary.
-static-libgo
is just for demonstration. The export data also present in the default dynamically linked binary, or completely-static
binary, though the size varies.With some big binaries, like kubernetes, the export data can be quite big (over 40% of the binary size).
cc @ianlancetaylor