How to avoid linking to libc when using cgo ?

1,061 views
Skip to first unread message

Mildred Ki'Lya

unread,
Feb 13, 2015, 3:51:46 AM2/13/15
to golang-nuts
Hi,

I have some C code (that I want to access from Go) that does not use any
C library function. In fact, it just compute things. No external
libraries are needed, and no system calls are made.

I would like to link this C code against my Go code. And I would like
the resulting executable not to be linked against the libc. I don't need
it, and I don't use it.

Up until Go 1.4, it was possible to embed C code in packages, have it
comiled using the Plan9 C compiler (6c, 8c, ...) and call the code from
Go, assuming the code wouldn't use too much stack space. This is now
being removed.

How could I use cgo to perform the same task and not link against the
libc and other standard C libraries? I tried the following LDFLAGS but
it doesn't work:

#cgo LDFLAGS: -nostdlib --entry main

The error is:

/usr/lib/go/pkg/tool/linux_amd64/cgo -objdir
$WORK/github.com/mildred/ed25519/src/_obj/ -dynimport
$WORK/github.com/mildred/ed25519/src/_obj/_cgo_.o -dynout
$WORK/github.com/mildred/ed25519/src/_obj/_cgo_import.c
# github.com/mildred/ed25519/src
cannot load imported symbols from ELF file
$WORK/github.com/mildred/ed25519/src/_obj/_cgo_.o: no symbol section

And if I don't specify those linker flags, I get linked with the libc:

go install github.com/mildred/ed25519/cmd/ed25519
ldd ${GOPATH%%:*}/bin/ed25519
linux-vdso.so.1 (0x00007fff283e6000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fe934f85000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fe934be2000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe9351a1000)

Do you have a solution for that.

Alternatively, do you know of any way I could convert this C code to a
format that I could link using the native Go linker. Such as a
source-to-source compiler that would build this C code and output Go,
Plan9 assembler, any other language that the native Go linker could link
in ?

Thank you

Mildred

Mildred Ki'Lya

unread,
Feb 13, 2015, 8:54:04 AM2/13/15
to golan...@googlegroups.com
On 2015-02-13 09:51, Mildred Ki'Lya wrote:
>
> How could I use cgo to perform the same task and not link against the
> libc and other standard C libraries? I tried the following LDFLAGS but
> it doesn't work:
>
> #cgo LDFLAGS: -nostdlib --entry main
>
> The error is:
>
> /usr/lib/go/pkg/tool/linux_amd64/cgo -objdir
> $WORK/github.com/mildred/ed25519/src/_obj/ -dynimport
> $WORK/github.com/mildred/ed25519/src/_obj/_cgo_.o -dynout
> $WORK/github.com/mildred/ed25519/src/_obj/_cgo_import.c
> # github.com/mildred/ed25519/src
> cannot load imported symbols from ELF file
> $WORK/github.com/mildred/ed25519/src/_obj/_cgo_.o: no symbol section


I was looking into that, and found that cgo doesn't expect to have a
self-contained object file that doesn't link to external libraries. I
looked at the output from go build -x -work which prints the commands
used to build the files, and I found:

* gcc is used to build all the C files, this is notmal and expected

* gcc is used to aggregate all the .o objects that were built into a
master _cgo_.o object file that contains the code for all the .c files
of the module

* gcc inokes ld to generate this _cgo_.o file. Normally, ld will link
against the libc unless passed -nostdlib. In that case, the .o object
file will not contain reference to external symbols.

In my case, when gcc/ld links _cgo_.o against the libc, the only
external symbols that are unreferenced (found using nm -D) are :

w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
U __libc_start_main

These symbols are only necessary when we have a main function. In our
case this is not necessary. But the _init and _start functions generated
by gcc/ld make use of it.

When avoiding the link to libc (using -nostdlib) none of those symbols
appear and there is no undefined symbol.

* Later on, gco is run and open the _cgo_.o file to generate the list of
libraries to link against in the final link where the executable is
generated. In case we use the libc, it find references to libc functions
and write to a file (_cgo_import.6) that libc is necessary

If there is no external symbol required (beause we used -nostdlib),
gcc/ld will strip the .dynsym section completely because it empty.
because there is no section .dynsym, cgo will mistakenly interpret the
absence of this section as a read failure of the ELF object file.

The all stack looks like this:

https://github.com/golang/go/blob/3819907a5565c53457b826912a10b18eda708f38/src/cmd/cgo/out.go#L204
https://github.com/golang/debug/blob/512354eaded67146a256474f5f486c37fd6e5263/elf/file.go#L669
https://github.com/golang/debug/blob/512354eaded67146a256474f5f486c37fd6e5263/elf/file.go#L397
https://github.com/golang/debug/blob/512354eaded67146a256474f5f486c37fd6e5263/elf/file.go#L455

- dynimport()
- elf.Open(obj).ImportedSymbols()
- f.getSymbols(SHT_DYNSYM)
- f.getSymbols64(SHT_DYNSYM)

symtabSection := f.SectionByType(typ)
if symtabSection == nil {
return nil, nil, errors.New("no symbol section")
}

I filed an issue against the debug/elf package:
https://github.com/golang/debug/issues/1

Mildred

Aram Hăvărneanu

unread,
Feb 13, 2015, 8:57:38 AM2/13/15
to Mildred Ki'Lya, golang-nuts
It won't work. It doesn't matter that your object doesn't use libc, go
binaries, in cgo mode are always using libc. E.g. they use
pthread_create instead of clone(2) on Linux.

--
Aram Hăvărneanu

Ian Lance Taylor

unread,
Feb 13, 2015, 11:30:00 AM2/13/15
to Mildred Ki'Lya, golang-nuts
On Fri, Feb 13, 2015 at 12:51 AM, Mildred Ki'Lya <mil...@mildred.fr> wrote:
>
> I have some C code (that I want to access from Go) that does not use any C
> library function. In fact, it just compute things. No external libraries are
> needed, and no system calls are made.
>
> I would like to link this C code against my Go code. And I would like the
> resulting executable not to be linked against the libc. I don't need it, and
> I don't use it.
>
> Up until Go 1.4, it was possible to embed C code in packages, have it
> comiled using the Plan9 C compiler (6c, 8c, ...) and call the code from Go,
> assuming the code wouldn't use too much stack space. This is now being
> removed.

Yes, I'm afraid we've lost this feature.

You can still do it by writing assembler code, but I admit that
is ... inconvenient.

Ian
Reply all
Reply to author
Forward
0 new messages