How to dllexport a value symbol within a windows binary executable with Go?

594 views
Skip to first unread message

Hakan Guleryuz

unread,
Jan 23, 2017, 11:13:30 AM1/23/17
to golang-nuts
In normal C/C++ SDL2 related app I write, adding the following code

extern "C" {

   _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}

causes the driver system with integrated and dedicated nvidia gpu, to auto select the dedicated nvidia gpu.

See here for some explanation of the mechanism->
https://github.com/urho3d/Urho3D/issues/139
http://stackoverflow.com/questions/16823372/forcing-machine-to-use-dedicated-graphics-card


I can view the exports of the final executable with "dumpbin /exports <executable name>"

[dumpbin is a tool installed with visual studio C++ tools]


How can I make my go executable export this value symbol?

I searched go link documentation but could not find something useful to achieve this.

I did some tests with cgo and "//export" command with a simple var, but that did not have any effect on "dumpbin /exports" output (no symbols exported)


I can see which GPU the executable is using by inspecting it with "process explorer" and its "dedicated GPU memory usage"


The go build "go-sdl2" app, by default, uses the CPU's embedded low performance integrated GPU, since I can not export this value with the executable.


Thanks for any help.



Hakan Guleryuz

unread,
Jan 30, 2017, 9:47:51 AM1/30/17
to golang-nuts
For anyone who wants to build a windows .exe with go-sdl2 and opengl, and has an optimus driver, and wants to ensure that
the high performance gpu is selected by default for their final product, I will document my findings here....

I found the followingsolution, which can be proven that it works by having this line in the go-sdl2 code:

var vendorString string = gl.GoStringUb(gl.GetString(gl.VENDOR))
fmt.Printf("Vendor String is %v \n", vendorString)

which outputs:
Vendor String is NVIDIA Corporation
instead of
Vendor String is Intel

Also process explorer shows that the gpu memory usage is only on the dedicated memory usage,
and also the opengl performance is much higher.

The first thing to do is to have an export on the created object file.
I did this by putting this in my main .go file

//__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
import "C"

The corresponding object file now has this symbol but the linker removes it, since it is building an .exe on windows,
and I guess GNU GCC tool chain by default removes all symbols (I did not try to switch the toolchain to Microsoft link.exe at this point)

Then to have this symbols (and unfortunately all other symbols) get exported in the final .exe I added this to the build options:
go install -ldflags "-v -extldflags -Wl,--export-all-symbols" pkgdnm/opengl3perftest

now dumpbin /export shows a huge number of exported symbols on the .exe and NvOptimusEnablement is one of them
This works, and optimus driver automatically selects the dedicated GPU when the executable is run,
but the down side is there are many more exported symbols.
There is another option which is

--dynamic-list=dynamic_symbol_table.txt

I put the contents of dynamic_symbol_table as just this
{
extern "C"
{
"NvOptimusEnablement";
};
};

but this did not work, meaning nothing was exported. The GNU GCC documentation is somewhat unclear
(https://sourceware.org/binutils/docs/ld/Options.html)
"This option is only meaningful on ELF platforms "

I could not find any option on gcc ld doc in section: "

Options Specific to i386 PE Targets"

to limit the exported symbols to only what needed, but as far as automatically selecting the dedicated GPU goal, goes, this works.

If anyone know a better/simpler way to export a symbol from .go file to the object file to be linked
or maybe know how to limit the exported symbols in the final executable using gnu ld PE target options
please comment.

First in my main package I have these lines

Hakan Guleryuz

unread,
Feb 20, 2017, 12:49:14 PM2/20/17
to golang-nuts
I found a much simpler and cleaner solution without involving any ldflags and without using
--export-all-symbols

In my main.go (or whatever main package that contains the main func):

/*
#cgo LDFLAGS: ${SRCDIR}/main.def

__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
*/
import "C"

and main.def contents are:
EXPORTS
NvOptimusEnablement @1 DATA
AmdPowerXpressRequestHighPerformance @2 DATA

I can verify that I have only these exports using either this build option:
go install -x -ldflags "-v -extldflags -Wl,--output-def,exports.def"

or using dumpin tool:
dumpbin /exports engine-conversion.exe
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file engine-conversion.exe

File Type: EXECUTABLE IMAGE

  Section contains the following exports for a.out.exe

    00000000 characteristics
    58AB2A03 time date stamp Mon Feb 20 20:40:19 2017
        0.00 version
           1 ordinal base
           2 number of functions
           2 number of names

    ordinal hint RVA      name

          2    0 00189220 AmdPowerXpressRequestHighPerformance
          1    1 00189224 NvOptimusEnablement
...
...
Reply all
Reply to author
Forward
0 new messages