"undefined reference" while using cgo -buildmode=c-shared

1,370 views
Skip to first unread message

Tommy Knowlton

unread,
May 18, 2016, 5:58:42 PM5/18/16
to golang-nuts
I'm trying to build additional "filter" shared libs for ulogd. The (Linux) ulogd daemon reads its .conf file, which specifies the filesystem location of shared libs, then according to how configured, it dynamically loads the shared libs. There isn't a "callback" function that the shared lib is supposed to export, but all of the working (c-lang) examples of such shared libraries simply declare an initializer function (called before dlopen(...) returns) that itself calls ulogd_register_plugin(...), which is a symbol defined in the ulogd daemon (main process which causes the shared libs to be loaded).

All of that is to say, my shared lib needs to be able to call (from C code) a function whose definition is available at the time my shared lib will be loaded. Where golang comes into the equation is that in the plugin struct that I'm passing to the host register function, I'm setting callbacks that are golang functions. I want to be able to write this ulogd filter plugin mostly in golang, with just the small c-lang shim I've already described.

I've got a .c file which declares the initializer function, which itself directly calls the ulogd_register_plugin function. That .c file sits adjacent to a .go file which declares a main package, as well as //export'ed cgo functions that are referenced in the plugin struct.

I think I've got everything that is needful, but I end up with:

# go.myorg.org/cf/ulog-dropsonde-output

/tmp/go-build604363162/go.myorg.org/cf/ulog-dropsonde-output/_obj/dropsonde.o: In function `init':

dropsonde.c:(.text+0xc): undefined reference to `ulogd_register_plugin'

collect2: error: ld returned 1 exit status


when trying to build via the command:
env CGO_CFLAGS="-I${PWD}/ulogd-source/include -I${PWD}/ulogd-source" GOPATH="${PWD}" /usr/lib/go-1.6/bin/go build -work -buildmode=c-shared -x go.myorg.org/cf/ulog-dropsonde-output

(all relevant files, including a copy of ulogd.h from ulogd source distribution can be found here).

I'm assuming that I'm missing some linker option (CGO_LDFLAGS) to make this work, but I don't know enough about the linker or cgo to know what I'm missing. Basically, I just want to tell it to leave the symbol undefined in the .so, so that at load time the linkage will be fixed-up by the time dlopen() calls the library initialization function. I'm pretty sure this is more to do with how the linker is getting invoked than cgo in particular, but I don't know enough about the workings of the linker to know what I'm wanting to tell it.

~ Tommy K

Ian Lance Taylor

unread,
May 18, 2016, 7:44:38 PM5/18/16
to Tommy Knowlton, golang-nuts
It would probably work to add a line to your .go file that uses import
"C": `#cgo LDFLAGS: -Wl,-unresolved-symbols=ignore-all`. See
https://golang.org/issue/14985 for an example.

Another approach that should work would be to change your .c file to
declare `ulogd_register_plugin` as weak.

Ian
Message has been deleted

Tommy Knowlton

unread,
May 19, 2016, 6:56:12 PM5/19/16
to golang-nuts, ia...@golang.org
Both of those approaches ended up working; I preferred the `weak` attribute approach, because it leaves the possibility of getting an error in case I inadvertently leave some other symbol undefined.

Thanks again for your help.
~ Tk

On Wednesday, May 18, 2016 at 8:54:23 PM UTC-6, Tommy Knowlton wrote:
Thanks for those recommendations, I'll give those a try. I did end up kludging it by replacing the static linkage to "ulogd_register_plugin" with manually resolving the symbol using dlopen() and dsym(), but either of your recommendations, if they work, will be better than that. Again, thanks. 
Reply all
Reply to author
Forward
0 new messages