Re: [go-nuts] [PATCH] RFC: go shared libraries support (Linux/x64)

Skip to first unread message

Patrick Mylund Nielsen

Nov 3, 2012, 12:37:31 PM11/3/12
to Elias Naur, golang-dev
- golang-nuts
+ golang-dev

On Sat, Nov 3, 2012 at 5:27 PM, Elias Naur <> wrote:

Eventually, I’d like to write shared libraries in go, in particular I want my go code callable from the android dalvik virtual machine. So, after a long and intense staring contest with the tools and the go runtime, I have a proof of concept running under linux/x64. I know that your contribution guide mentions that I should write my design before coding, but in this case I chose to do the experiments myself first to get a feel of the go code and to figure out if it was even possible for me to implement.

With the two CLs applied, building the runtime with PIC support is done with

GO_FLAGS=-lib ./make.bash

after which you can run the attached test case like this:

./ && LD_LIBRARY_PATH=. ./main

which should give the following output:

Main, calling cgo
From test, calling go
Go callback!
C main, calling Go_callback
Go callback!
C main exiting

The test case demonstrates a C main program loading a go shared library (, which in turn loads a C shared library ( The test case calling sequence is as follows:

1. DT_INIT is run by the dynamic linker. Go is initialized and main.main() is run. In this case, is called from main.main through cgo.
2. main.main() returns and instead of exiting, control is relinquished back to the dynamic linker which in turn calls the C main().
3. C main() calls back into through cgo and exits.

The tool changes ( adds the new “-lib” flag to the go tool and the -U flags to 6l, 6g and 6c. With -U the 6g and 6c tools outputs code compatible with position independent code. 6l in turn outputs the necessary relocations and uses RIP-relative addressing in the resulting machine code. It also sets up DT_INIT to initialize the library and it marks the resulting elf file as a shared library instead of a regular executable. The resulting file is an elf shared library (ET_DYN) and can be used both as a executable and as a shared library. When run as an executable, there is the added benefit of activating ASLR since the file is recognized as position independent.

The runtime changes ( adds runtime support for go shared libraries. In particular:

1. Assembler changes to allow 6l to output RIP-relative addressing on x64.
2. Scheduler changes to allow the main go routine to exit cleanly and relinquish control back to the main program (proc.c).
3. Changes to the stack unwinding code to compensate for the runtime relocations (symtab.c).
4. Changes the VDSO loader to use /proc/maps instead of the ancillary vector which is not available from the library init (vdso_linux_amd64.c and runtime.c)

I don’t expect the changes to go in as is, but I would very much welcome reviews, comments etc., to allow for go shared library support, eventually on the other platforms and archs too.

 - elias


Florian Weimer

Nov 4, 2012, 7:46:46 AM11/4/12
* elias naur:

> However I would suspect that, primarily by hiding the go shared
> library symbols from each other (not marking the global), two go
> shared libraries could be loaded simultaneously, blissfully unaware
> of each other.

Won't the GC bitmap conflict? Or isn't it stored at a fixed address
Reply all
Reply to author
0 new messages