This is unfortunate, but unavoidable. The reason is that gallium calls out to various Cocoa functions in order to create and manage OSX UI elements, and many of these are required to be called from the first thread created by the process (the so-called 'main thread' in Cocoa parlance). But the Go runtime creates many threads and any one piece of Go code could end up running on any thread.
The solution is runtime.LockOSThread, which tells the Go scheduler to lock the current goroutine so that it will only ever run on the current thread. Since the main function always starts off in a goroutine that is running on the main thread, this guarantees that the later call to gallium.Loop will also be on the main thread. At this point gallium takes ownership of this thread for its main event loop and calls the OnReady callback in a separate goroutine. From this point forward it is safe to call gallium functions from any goroutine. I don't think runtime.LockOSThread could go in gallium.init since it only guarantees that the current goroutine will stay on the current thread, but there is no guarantee that the goroutine that runs init is the same one that runs main (since other init functions might create goroutines). The reason runtime.LockOSThread can't go at the top of gallium.Loop is that by this time the main function may already have created goroutines, and hence may have been swapped onto a different thread. It would work if the very first statement in main was always gallium.Loop, but that seems too onerous of a requirement to me.
What is the easiest way to create GUI for a desktop application in golang? Update Cancel. Ad by Toptal. Hire the top 3% of UX/UI designers. If you are targeting the Windows platform specifically and would like to have massive features, try WPF with C#. Trust me, you can pull stunning animations in few seconds. Then you can build your.
Notably, the recently published is using buildmode=shared, and thus doesn't currently support Windows natively. This is a very cool use case, adding a REPL-like live coding feature to the Go ecosystem, thus it would be really awesome if someone tried to start work on buildmode=shared on Windows to support this use case. Similar to, I'm quite interested in some hints as to what is missing for this to work on Windows?
I'm especially curious what extra work is needed given that c-shared is already implemented on Windows? There doesn't seem to be a huge amount to it in the src: My completely naive guess would be figuring the windows equivalents to the C-bindings in plugindlopen.go. The main functions I can see there are:.: The function dlopen loads the dynamic library file named by the null-terminated string filename and returns an opaque 'handle' for the dynamic library.: The function dlsym takes a 'handle' of a dynamic library returned by dlopen and the null-terminated symbol name, returning the address where that symbol is loaded into memory. Googling for 'dlopen equivalent windows' led me to the following:.: an implementation of a dlopen-like API for Windows.
'FlexDLL implements mostly the usual dlopen POSIX API, without trying to be fully conformant though (e.g. It does not respect the official priority ordering for symbol resolution).
This should make it easy to port applications developped for Unix.' . LoadLibrary: And 'dlsym equivalent windows':. 'Windows uses LoadLibrary and GetProcAddress instead.'
. GetProcAddress:. 'Both Linux and Windows provide routines (such as dlopen and dlsym in Linux, and LoadLibrary,GetProcAddress in Windows)'. 'On windows, I believe LoadLibrary dlopen, GetProcAddress dlsym, and FreeLibrary dlclose' So from that, it sounds like we have the following premise to work from:.
dlopen in.nix roughly maps to LoadLibrary in windows. dlsym in.nix roughly maps to GetProcAddress in windows The main definitions in FlexDLL don't look too complex. But there is quite a bit of extra code around those that may be required too:.
Hopefully this helps scope out what will be required/start pointing in the right direction:). I've been hacking on this issue for a while and it seems to be going well for now. I've managed to load a dll built with -buildmode=c-shared and call its init function. The only limitation of this is that the plugin needs to have a main function or it won't compile. I'm developing on Linux using GCC and Wine. Just a few questions if anyone could clarify: What exactly is going on in this function? The dlopen implementation calls this function and apparently returns the symbols; it doesn't work with Windows's shared objects.
Secondly, I couldn't find any consistent guidelines for using wide strings with CGO so I ended up depending on unicode/utf16 and unicode/utf8. However, go/build/depstest.go has pretty strict restrictions on which packages you can import. Is this a problem?
Edit: I guess this isn't so straightforward as I thought.buildmode=plugin adds some metadata that is needed to find the exported symbols. Reading the PE data (using pev's readpe) doesn't show any of the functions that the plugin is meant to export, only init and main. When loading it, the init function is run implicitly.
I've been hacking on this issue as well as far as getting functioning on windows. As gave insight into, LoadLibrary & GetProcAddress are the two equivalent we're looking for.
As far as suggestion to automatically generate a DllMain, I think this may be our best option. While we could use something similar to how does it by using either DONTRESOLVEDLLREFERENCES or LOADLIBRARYASDATAFILE in LoadLibraryEx I think it may just cause more work as on top of not invoking DllMain it also does not load any references to dependencies and would be quite tedious to implement manually.
It shouldn't be necessary to do strange things around generating the DLL entry point, GCC takes care of the wiring up for that mostly implicitly. If you adjust go to export go.link.addmoduledata in on windows as an external you can you use the '-e' flag when linking with gcc to have it call into the right initialization function for plugins. The underlying init calls that LdrpCallInitRoutine makes and the related CRTINIT are all handled by GCC. The bigger issue seems to be with relocations and the GOT/PLT. With some small modifications it seems like I can get.TEXT symbols looking okay, but the stuff in.DATA is seems to be getting clobbered by GCC (specifically local.moduledata is trashed, but it looks like that's just the start of the structure data that gets completely hosed). I suspect that go is outputting these somewhere or in such a way that GCC is co-mingling the data and stuff either isn't getting relocated correctly or tables are getting partially overwritten/corrupted. If there is someone who has good knowledge the PE format and by some miracle with GCC-Windows as well that would probably be extremely helpful here, otherwise I'll keep trying to muddle through.
Not claiming to have answers, and not sure if that might be in any way helpful, but some years ago I managed to emit some PE/COFF.o files with gcc-accepted.RSRC sections in; I faintly recall having to write relocations for it, so it may or may not help you in some way. I remember that my approach was generally to try to emit something based on what I understood from various resources on the Internet, then try to build identical.o with GCC's windres. Inevitably there were some differences, so then I opened both files in some hex editor and tried to understand what's wrong, and what's irrelevant (dates, etc.; and more often than I'd want, if couldn't understand, copy blatantly.:/) Rinse and repeat until I got I think a byte-perfect copy, which would thus pass gc/gcc linkage. Maybe a similar approach could be possible with c-shared? Based on some minimal.s file compiled with gc vs.
An ugly twin in gcc? Not sure if that's at all possible, or makes sense (esp. Given the whole Go runtime needing to be linked). I'm afraid I might not remember anything about PE anymore now; just wanted to say, that if by any chance this could be helpful to you in any way, I seem to be calculating some relocations (though maybe somewhere else too?). I seem to remember that the 'formula' for calculating relocations seemed to be described in a somewhat confusing/misleading way on MSDN, at least for me; when I finally got it to work I believe I felt happy and satisfied, but also annoyed and cheated. Anyway, keeping fingers crossed for you super hard! Binary hacking on Windows certainly requires stalwart dedication:).
I think anything helps at this point:) So here is what I believe is happening. There are some symbols local.moduledata that are supposed to end up in.noptrdata. At somepoint (I think maybe gcc is doing it, but it could be pe.go) the stuff is supposed to be in.noptrdata is getting stuffed into.data (which by itself isn't necessarily a bad thing, depending on other things like whether or not the garbage collector sees this other data). During this time the symbols in relation to the actual data structures that are there are getting offset (I don't know why or how). So when local.addmoduledata tries to grab the address for local.moduledata it's getting an address that has a bunch of the utf8 static data in it.
I'm wondering if this is a relocation problem but I'm not sure.obviously this isn't happening in ELF partially because.noptrdata doesn't get folded into.data. I also can't actually find out where in the linker the symbol binary data is written out (I can see where the symbols themselves are written in pe.go but not sym.P) so if someone knows where that is it might be helpful. There are some symbols local.moduledata that are supposed to end up in.noptrdata.
![Mac Mac](/uploads/1/2/5/6/125632498/984998006.png)
At somepoint (I think maybe gcc is doing it, but it could be pe.go) the stuff is supposed to be in.noptrdata is getting stuffed into.data Are you talking about pe sections named.noptrdata and.data? Because I do not remember that Go linker generates.noptrdata pe section in the object file to be used for external linker. As far as I remember whatever symbol named as.noptrdata endup in either.text,.rdata or.data pe section. But, regardless, relocations should be correct, because they apply to the whole pe section. Maybe Go linker does not align some symbols or sections properly. It is hard for me to advise here. If you have some repro for me to play with, I might be able to help.
Okay some additional follow up, it actually looks like the output assembly and symbols are fine there may not be corruption, I think what I was seeing was slight differences in how the memory is represented in ELF vs PE, but doing more thorough checking of the memory at runtime things might be okay. What appears to be happening is that in a functional example (.nix) runtime.addmoduledata loads lastmoduledatap which I guess should have a pointer to firstmoduledata. Whats happening on windows is that lastmoduledatap has a pointer to local.moduledata which is apparently not correct. I'm not sure where lastmoduledatap is getting set to firstmoduledata as I can't seem to find it in code.
The code I've found shows that it should have the address of local.moduledata. What appears to be happening is that in a functional example (.nix) runtime.addmoduledata loads lastmoduledatap which I guess should have a pointer to firstmoduledata. I see about the same. I could not stop gdb in the DLL loading code - I do not know how to do it. I tried breakpoint and rwatch.
Thanks So my suspicion has been that what we are seeing is there is a runtime. in the plugin dll and a runtime. in the host executable. Which would explain why the memory for lastmoduledatap is not correct from the perspective of the plugin. I had forgot about but that ticket also pretty much confirms that suspicion. It looks like what we need to replicate is the -rdynamic gcc flag.
Which I don't believe gcc on windows supports. So where do we go from here. What I'm trying to work on is having the host executable (though really we just need the base go internals) export all of its symbols (-Wl,-export-all-symbols) then using those via dlltool to build a library file that plugins link against (this is where I am now).
Once we're linking against an external library for the 'shared' go runtime I'm hoping we'll see some forward movement. I haven't gotten it to work quiet yet and I suspect it's because I need to stuff all of the go runtime symbols into.idata (windows import table) vs where it normally lives (.data.text) for the plugin dll. Right now the whole thing is a lot of manual process and it may require that the plugin host be externally linked on windows for plugins to work (not the end of the world, I suspect that when building a host executable we can check for usage of the plugin symbols and switch to external linking automatically) My bigger concern is whether or not we can link against a general go runtime in the plugin vs linking against the go runtime provided by the plugin host executable. I suspect we can, I don't really see any reason this shouldn't work, but I fear the plugin host may also have to be linked against the same general runtime.unsure though. So my suspicion has been that what we are seeing is there is a runtime. in the plugin dll and a runtime.
in the host executable. Which would explain why the memory for lastmoduledatap is not correct from the perspective of the plugin.
![Golang Build For Windows On Mac Golang Build For Windows On Mac](/uploads/1/2/5/6/125632498/684536620.png)
I had forgot about but that ticket also pretty much confirms that suspicion. I am not sure what you are saying here. As far as I understand runtime. variables in executable and dll do not share the same addresses - they are independent of each other. The problem described in is different - both executable and dll use the same TLS register ( ).
It looks like what we need to replicate is the -rdynamic gcc flag. Which I don't believe gcc on windows supports. I am not familiar with gcc enough to comment. But from what I can gather, -rdynamic gcc flag provides support for dlopen. But all Windows DLLs can be loaded 'dynamically' using LoadLibrary Windows API. So I am not sure we need -rdynamic gcc flag. I haven't gotten it to work quiet yet and I suspect it's because I need to stuff all of the go runtime symbols into.idata (windows import table) vs where it normally lives (.data.text) for the plugin dll.idata always contains very specific data - it is effectively relocations that Windows uses when it loads / initialises executable or DLL.idata lists all DLL names / function names used by executable or DLL and some refs for Windows to write these function addresses during load.
I would not be surprised if existing Go DLLs already has all functions exported - so you could call them via LoadLibrary / GetProcAddress already. You just need to pass parameters correctly to them. And that is what I expect plugin mode achieves. But I could be wrong. B go.link.addmoduledata then si from there to step forward until I know where the segfault occurs. If this is not working you may try b link.addmoduledata which is what the symbol is showing up for me as on.nix. I'm not sure why there are different.
This is what I do c: Users Alex dev src github.com cchamplin plugintestgdb plugintest.exe GNU gdb (GDB) 7.8 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type 'show copying' and 'show warranty' for details. This GDB was configured as 'x8664-w64-mingw32'. Type 'show configuration' for configuration details.
For bug reporting instructions, please see:. Find the GDB manual and other documentation resources online at:. For help, type 'help'.
Type 'apropos word' to search for commands related to 'word'. Reading symbols from plugintest.exe.done. (gdb) b go.link.addmoduledata Function 'go.link.addmoduledata' not defined. Make breakpoint pending on future shared library load? (y or n) y Breakpoint 1 (go.link.addmoduledata) pending. (gdb) b link.addmoduledata Function 'link.addmoduledata' not defined. Make breakpoint pending on future shared library load?
(y or n) y Breakpoint 2 (link.addmoduledata) pending. (gdb) r Starting program: c: Users Alex dev src github.com cchamplin plugintest plugintest.exe New Thread 6200.0xe2c warning: Can not parse XML library list; XML support was disabled at compile time New Thread 6200.0x858 New Thread 6200.0x1f8c New Thread 6200.0x25d8 New Thread 6200.0x420 New Thread 6200.0x2be4 New Thread 6200.0x24a0 Starting Module Path: c: Users Alex dev src github.com cchamplin plugintest eng eng.so Program received signal SIGSEGV, Segmentation fault. 0x000000006fdf7f4c in?? (gdb) bt #0 0x000000006fdf7f4c in?? Backtrace stopped: previous frame identical to this frame (corrupt stack?) (gdb) disas No function contains program counter for selected frame.
(gdb) I do not see how I can use si command. Should I break on 'main.main' first, and then use si? That would take forever. And, like said, you should replace your C code with single syscall.LoadLibrary call. For the purpose of your debugging, it does the same thing. I am not sure what you are saying here. As far as I understand runtime.
variables in executable and dll do not share the same addresses - they are independent of each other. The problem described in is different - both executable and dll use the same TLS register ( (comment) ). This is not what I am seeing on.nix. This is not what I am seeing on.nix. Here is a GDB run-through.
I am, probably, wrong, but imagine you have runtime.addmoduledata function in your Go program. When you compile Go executable, the function code endup somewhere in.text section of PE executable.
When executable runs, Windows loads executable file starting at some fixed address (that is hardcoded in the Go linker). So.text section will always starts at the same address (.text section is first section), and runtime.addmoduledata will starts somewhere after that address. Similarly when Go DLL is built, Go linker puts runtime.addmoduledata somewhere in.text section of an object file and passes it to GCC. GCC copies runtime.addmoduledata code into.text section of DLL file.
When.DLL file is loaded by any executable, Windows loads file at some random address - it has to be random, otherwise different DLLs will conflict with each other. So, similarly to executable,.DLL file.text section will endup at fixed offset after that random.DLL address. And runtime.addmoduledata will apears some offset after that. So if Go executable loads Go DLL, we will have 2 copies of runtime.addmoduledata loaded at different addresses. But, I don't see how this is relevant to our conversation. If you look at the values of R15 and RAX you see the addresses match. I think the difference you see between Linux and Windows, is that R15 in runtimeaddmoduledata is set to 0.
See this comment about R15. // This is called from.initarray and follows the platform, not Go, ABI. TEXT runtimeaddmoduledata(SB),NOSPLIT, $0- 0 PUSHQ R15 // The access to global variables below implicitly uses R15, which is callee-save MOVQ runtimelastmoduledatap(SB), AX MOVQ DI, moduledatanext(AX) MOVQ DI, runtimelastmoduledatap(SB) POPQ R15 RET I do not know how R15 is used to access global variables.
And who sets R15. Maybe others will help. I'm not sure why your experience is different than mine. I've provided a gist the debugging on windows if that helps here: It does help. I downloaded later gdb version, and it works similarly to yours. Thank you very much.
So if Go executable loads Go DLL, we will have 2 copies of runtime.addmoduledata loaded at different addresses. But, I don't see how this is relevant to our conversation. It's not so much runtime.addmoduledata but runtime.lastmoduledatap and runtime.firstmoduledata.