Failed to load dll. Specified module could not be found - windows

I have some code that I wrote in golang (on ubuntu) and tried to package as a windows exe but unfortunately, due to some cgo dependencies from a github project, I ended up having to build my package as a dll as per this answer https://stackoverflow.com/a/49079049/4750381 because it would not compile as a runnable exe file for windows (even using MinGw).
My compile line was:
GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -buildmode=c-shared -o main.dll main.go
My main package code looks like this:
package main
import (
"C"
"fmt"
console "github.com/AsynkronIT/goconsole"
"github.com/AsynkronIT/protoactor-go/actor"
"path/to/repo"
)
const cfgPath string = "./config.json"
func main() {
fmt.Println("from main")
}
func dllRun() {
// Used for running the test and various other operations, thus generally all lines except 1 will be commented out
ctx := actor.EmptyRootContext
props := actor.PropsFromProducer(testmachine.NewTestMachine(cfgPath))
pid, err := ctx.SpawnNamed(props, "tm")
if err != nil {
panic(err)
}
defer func() { // run after the read line fucntion executes and terminates the program
ctx.Poison(pid)
}()
console.ReadLine()
}
I wrote another go script (using windows this time) to try to load and read that DLL file:
import (
"syscall"
)
func main() {
myDLL := syscall.NewLazyDLL("C:/Users/konyenso/Documents/DLLOpener/main.dll")
mainCall := myDLL.NewProc("dllRun")
ret, _, err := mainCall.Call()
if err != nil {
panic(err) // calling myDLL.mainCall failed
}
if ret == 0 {
print("Could not set the desired attributes")
// TODO: call GetLastError to get more information
}
print("OK")
}
But now I always get the error below even though my file path is ok:
panic: Failed to load C:/Users/konyenso/Documents/DLLOpener/main.dll: The specified module could not be found.
goroutine 1 [running]:
syscall.(*LazyProc).mustFind(0x13019400)
c:/go/src/syscall/dll_windows.go:311 +0x42
syscall.(*LazyProc).Call(0x13019400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4623e0)
c:/go/src/syscall/dll_windows.go:327 +0x21
main.main()
C:/Users/konyenso/Documents/DLLOpener/main.go:11 +0xa5
Please could someone tell me what I'm doing wrong? I've been tweaking this all day with little success. Ideally I would want to build an exe straight from ubuntu without the dll but if that's not feasible, I would at least like to be able to run my dll from another exe file.
Thanks for any assistance.
********** EDIT****************************
So I wrote some C++ code to try to open the dll file (made 64 and 32 bit versions of both)
#define UNICODE
#include <windows.h>
#include <iostream>
/* Define a function pointer for our imported
* function.
* This reads as "introduce the new type f_funci as the type:
* pointer to a function returning an int and
* taking no arguments.
*
* Make sure to use matching calling convention (__cdecl, __stdcall, ...)
* with the exported function. __stdcall is the convention used by the WinAPI
*/
typedef int (__stdcall *f_funci)();
int main()
{
HINSTANCE hGetProcIDDLL = LoadLibrary((LPCWSTR)"C:\\Users\\konyenso\\Documents\\DLLOpener\\main.dll");
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
// resolve function address here
f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "dllRun");
if (!funci) {
std::cout << "could not locate the function" << std::endl;
return EXIT_FAILURE;
}
std::cout << "funci() returned " << funci() << std::endl;
return EXIT_SUCCESS;
}
Same issue:
Screenshot showing could not load
As you can see from this below screenshot, the file path matches so I have no idea what's going on.
Screenshot showing paths confirmed

First,you need export dll method like this:
// export dllRun
func dllRun() {
There is a simple example,
https://github.com/whtiehack/checkdll_log
Second,
Go main program could not load Go dll correct because
https://github.com/golang/go/issues/34168
https://github.com/golang/go/issues/22192
In summary, in Windows, there can not have more than two go runtimes in a main program.

Related

How do I call a function from the main application from a plugin?

I have recently looked into Go plugins instead of manually loading .so files myself.
Basically, I have a game server application, and I want to be able to load plugins (using plugins package) when the server starts. Then, in the plugin itself, I want to be able to call exported functions that are a part of the server.
Say I have this plugin, which is compiled to example_plugin.so using go build -buildmode=plugin:
package main
import "fmt"
func init() {
fmt.Println("Hello from plugin!")
}
Then say I have this server application, which loads the plugin (and ultimately calls the "init" function under the hood):
package main
import (
"fmt"
"plugin"
)
func main() {
fmt.Println("Server started")
if _, err := plugin.Open("example_plugin.so"); err != nil {
panic(err)
}
}
// some API function that loaded plugins can call
func GetPlayers() {}
The output is:
Server started
Hello from plugin!
This works as expected, however I want to be able to call that GetPlayers function (and any other exported functions in the server application, ideally) from the plugin (and any other plugins.) I was thinking about making some sort of library consisting of interfaces containing API functions that the server implements, however I have no idea where to start. I know I will probably need to use a .a file or something similar.
For clarification, I am developing this application for use on Linux, so I am fine with a solution that only works on Linux.
Apologies if this is poorly worded, first time posting on SO.
As mentioned in the comments, there is a Lookup function. In the documentation for the module they have the following example:
// A Symbol is a pointer to a variable or function.
// For example, a plugin defined as
//
// var V int
//
// func F() { fmt.Printf("Hello, number %d\n", V) }
//
// may be loaded with the Open function and then the exported package
// symbols V and F can be accessed
package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("plugin_name.so")
if err != nil {
panic(err)
}
v, err := p.Lookup("V")
if err != nil {
panic(err)
}
f, err := p.Lookup("F")
if err != nil {
panic(err)
}
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
}
I think the most confusing lines here are
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
The first one of them performs a type assertion to *int to assert that v is indeed a pointer to int. That is needed since Lookup returns an interface{} and in order to do anything useful with a value, you should clarify its type.
The second line performs another type assertion, this time making sure that f is a function with no arguments and no return values, after which, immediately calls it. Since function F from the original module was referencing V (which we've replaced with 7), this call will display Hello, number 7.

Is there a way to execute functions in a compiled golang binary from another binary without needing any special setup?

I have a RPC type of setup where one binary (binaryA) is requesting work to be done from another binary (binaryB). They're both compiled the same way and are on the same system. I can't shell out to binaryA because the task involved involves a lot of data which would take too long to serialize and I can't use a golang plugin because the I want to be able to call functions without needing to create a special binary.
This is roughly the setup I'm trying to achieve:
binaryA compiled with go build mainA.go. Somewhere in that binary, this file is compiled:
package demo
import "fmt"
func TestFn(){
fmt.Println("binaryA")
func(){ someFn() }()
}
I want to be able to call TestFn() and that anonymous function with binaryB.
Here's what I have so far.
import (
"debug/macho"
"fmt"
"os"
"reflect"
"unsafe"
)
func main() {
filename := "binaryA"
f, _ := os.Open(filename)
defer f.Close()
mf, _ := macho.NewFile(f)
sym2Addr := make(map[string]uintptr)
for _, sym := range mf.Symtab.Syms {
if int(sym.Sect-1) >= len(mf.Sections) ||
mf.Sections[sym.Sect-1].Seg != "__TEXT" { continue }
value := uintptr(sym.Value)
sym2Addr[sym.Name] = value
}
funcType := reflect.TypeOf(func() {})
if testFnPtr, ok := sym2Addr["main.TestFn"]; ok {
TestFn := reflect.New(funcType).Elem()
p := new(uintptr)
*p = testFnPtr
*(*unsafe.Pointer)(unsafe.Pointer(TestFn.Addr().Pointer())) = unsafe.Pointer(p)
TestFn.Call([]reflect.Value{})
}
}
Using the code above I'm able to find the symbol main.TestFn but it ultimately fails with:
unexpected fault address 0x210d0fb1
fatal error: fault
[signal SIGBUS: bus error code=0x2 addr=0x210d0fb1 pc=0x210d0fb1]
goroutine 1 [running]:
runtime.throw(...)
.asdf/installs/golang/1.15/go/src/runtime/panic.go:1116
runtime.sigpanic()
.asdf/installs/golang/1.15/go/src/runtime/signal_unix.go:717
runtime.call32(...)
.asdf/installs/golang/1.15/go/src/runtime/asm_amd64.s:540
reflect.Value.call(...)
.asdf/installs/golang/1.15/go/src/reflect/value.go:475
reflect.Value.Call(...)
.asdf/installs/golang/1.15/go/src/reflect/value.go:336
main.main()
plugin_demo.go:106
runtime.main()
.asdf/installs/golang/1.15/go/src/runtime/proc.go:204
runtime.goexit()
.asdf/installs/golang/1.15/go/src/runtime/asm_amd64.s:1374
exit status 2
EDIT:
I can recompile binaryA with any build flags I want.
Is there a way to execute functions in a compiled golang binary from another binary without needing any special setup?
No, that simply is not how compiled (to machine code) programs work (in any language).

cgo calling share library: cannot find lib or function?

I'm using the sample code of chapter 13 of The Go Programming Language as below:
$ cat bzip2.c
#include <bzlib.h>
int bz2compress(bz_stream *s, int action,
char *in, unsigned *inlen, char *out, unsigned *outlen) {
s->next_in = in;
s->avail_in = *inlen;
s->next_out = out;
s->avail_out = *outlen;
int r = BZ2_bzCompress(s, action);
*inlen -= s->avail_in;
*outlen -= s->avail_out;
s->next_in = s->next_out = NULL;
return r;
}
$ cat usebzip2.go
// Package bzip provides a writer that uses bzip2 compression (bzip.org).
package main
import "C"
import (
"io"
"log"
"os"
"testing"
"unsafe"
)
type writer struct {
w io.Writer // underlying output stream
stream *C.bz_stream
outbuf [64 * 1024]byte
}
// Close flushes the compressed data and closes the stream.
// It does not close the underlying io.Writer.
func (w *writer) Close() error {
if w.stream == nil {
panic("closed")
}
defer func() {
C.BZ2_bzCompressEnd(w.stream)
C.bz2free(w.stream)
w.stream = nil
}()
for {
inlen, outlen := C.uint(0), C.uint(cap(w.outbuf))
r := C.bz2compress(w.stream, C.BZ_FINISH, nil, &inlen,
(*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
return err
}
if r == C.BZ_STREAM_END {
return nil
}
}
}
// NewWriter returns a writer for bzip2-compressed streams.
func NewWriter(out io.Writer) io.WriteCloser {
const blockSize = 9
const verbosity = 0
const workFactor = 30
w := &writer{w: out, stream: C.bz2alloc()}
C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
return w
}
func main() {
w := NewWriter(os.Stdout)
if _, err := io.Copy(w, os.Stdin); err != nil {
log.Fatalf("bzipper: %v\n", err)
}
if err := w.Close(); err != nil {
log.Fatalf("bzipper: close: %v\n", err)
}
}
First I compile the .c file:
gcc -I/usr/include -L/usr/lib -lbz2 --shared bzip2.c -fPIC -o libbzip2.so
The linux environment LD_LIBRARY_PATH contains ".", and then go build fails:
go build usebzip2.go
# command-line-arguments
/tmp/go-build677611698/b001/_x002.o: In function `_cgo_22d5d7fabfe4_Cfunc_bz2compress':
/tmp/go-build/cgo-gcc-prolog:118: undefined reference to `bz2compress'
collect2: error: ld returned 1 exit status
So how to fix it? I'm using ubuntu 18.04 LTS. Thanks a lot.
Don't run:
go build usebzip2.go
but rather:
go build
(and you don't need to invoke gcc directly on bzip2.c). When you use this process, you'll get many more (but different) errors because you have not put in the right directives before the:
import "C"
line. You need a comment (or series of comments) telling cgo about the functions you intend to provide, or providing those functions inline, and to direct the link phase to use -lbz2. In particular, you will need to:
#include <bzlib.h>
provide a bz2alloc function
provide a bz2free function
provide a declaration for your bz2compress function
set the LDFLAGS to include -lbz2
The actual bz2alloc and bz2free are short and simple and therefore can be included directly in this header block:
package main
/*
#cgo LDFLAGS: -lbz2
#include <bzlib.h>
#include <stdlib.h>
bz_stream *bz2alloc() { return calloc(1, sizeof(bz_stream)); }
int bz2compress(bz_stream *s, int action,
char *in, unsigned *intlen, char *out, unsigned *outlen);
void bz2free(bz_stream* s) { free(s); }
*/
import "C"
If you insert this and run go build you will now see a different and more useful error:
./usebzip2.go:60:2: cannot use w (type *writer) as type io.WriteCloser in return argument:
*writer does not implement io.WriteCloser (missing Write method)
which is of course because type writer does not implement Write.
(There's a completed version of exercise 13.3—not mine—at https://github.com/torbiak/gopl/tree/master/ex13.3. Note that they have augmented theirs to use locking as well, making it safe to call the write function from multiple goroutines simultaneously.)

Go Fails to Find Procedure in DLL

Why Go fails to find the specified procedure in dll?
I have a my.dll library compiled for Windows x86 (The OS is Windows 7 x64; but I am using Go x86 binary - with LiteIDE - and the C# code is also explicitly compiled for x86 architecture). And I use it from C# and it works:
[DllImport("my.dll", EntryPoint = "my_function")]
public static extern double my_function(double x);
But when I try to use it (here I am trying just to find it) from Go by:
var (
dllMine = syscall.NewLazyDLL("my.dll")
my_function = dllMine.NewProc("my_function")
)
func main() {
err := my_function.Find()
if err != nil {
fmt.Println(err)
return
}
//...
}
It says Failed to find my_function procedure in my.dll: The specified procedure could not be found.. The my.dll file resides at the same directory with the generated .exe file. The entry point name ("my_function") does exists because it's working fine when is imported in C# and it does not say Failed to load my.dll: The specified module could not be found..
Actual pieces: The library I am trying to call is swedll32.dll which is the core library of Swiss Ephemeris (can be downloaded here - GNU) and just for testing this scenario the function to be called is swe_julday; for reproducing the error, with this signature:
double swe_julday(
int year, int month, int day, double hour,
int gregflag); /* Gregorian calendar: 1, Julian calendar: 0 */
Another thing is my GOROOT environment parameter is actually a NTFS junction point (so I can switch between x86 and x64 versions) - but I do not think it's relevant, because the output .exe app is being generated without any problem (just for the sake of confessing all my sins!).
I have downloaded your dll from http://www.astro.com/ftp/swisseph/sweph.zip to see if swe_julday function is in there:
C:\foo>dumpbin /exports swedll32.dll | find "swe_julday"
74 49 0000C440 _swe_julday#24
75 4A 0000D4A0 _swe_julday_d#24
And I don't see swe_julday function in there. Instead I see _swe_julday#24 function. So if I change your program to:
C:\foo>type foo.go
package main
import (
"syscall"
"fmt"
)
var (
dllMine = syscall.NewLazyDLL("swedll32.dll")
my_function = dllMine.NewProc("_swe_julday#24")
)
func main() {
err := my_function.Find()
if err != nil {
fmt.Println(err)
return
}
//...
}
it runs without any errors:
C:\foo>go run foo.go
C:\foo>

Printing output to a command window when golang application is compiled with -ldflags -H=windowsgui

I have an application that usually runs silent in the background, so I compile it with
go build -ldflags -H=windowsgui <gofile>
To check the version at the command line, I wanted to pass a -V flag to the command line to get the string holding the version to be printed to the command prompt then have the application exit. I added the flag package and code. When I test it with
go run <gofile> -V
...it prints the version fine. When I compile the exe, it just exits, printing nothing. I suspect it's the compilation flag causing it to not access the console and sending my text into the bit bucket.
I've tried variations to print to stderr and stdout, using println and fprintf and os.stderr.write, but nothing appears from the compiled application. How should I try printing a string to the command prompt when compiled with those flags?
The problem is that when a process is created using an executable which has the "subsystem" variable in its PE header set to "Windows", the process has its three standard handles closed and it is not associated with any console—no matter if you run it from the console or not. (In fact, if you run an executable which has its subsystem set to "console" not from a console, a console is forcibly created for that process and the process is attached to it—you usually see it as a console window popping up all of a sudden.)
Hence, to print anything to the console from a GUI process on Windows you have to explicitly connect that process to the console which is attached to its parent process (if it has one), like explained here for instance. To do this, you call the AttachConsole API function. With Go, this can be done using the syscall package:
package main
import (
"fmt"
"syscall"
)
const (
ATTACH_PARENT_PROCESS = ^uint32(0) // (DWORD)-1
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procAttachConsole = modkernel32.NewProc("AttachConsole")
)
func AttachConsole(dwParentProcess uint32) (ok bool) {
r0, _, _ := syscall.Syscall(procAttachConsole.Addr(), 1, uintptr(dwParentProcess), 0, 0)
ok = bool(r0 != 0)
return
}
func main() {
ok := AttachConsole(ATTACH_PARENT_PROCESS)
if ok {
fmt.Println("Okay, attached")
}
}
To be truly complete, when AttachConsole() fails, this code should probably take one of these two routes:
Call AllocConsole() to get its own console window created for it.
It'd say this is pretty much useless for displaying version information as the process usually quits after printing it, and the resulting user experience will be a console window popping up and immediately disappearing; power users will get a hint that they should re-run the application from the console but mere mortals won't probably cope.
Post a GUI dialog displaying the same information.
I think this is just what's needed: note that displaying help/usage messages in response to the user specifying some command-line argument is quite often mentally associated with the console, but this is not a dogma to follow: for instance, try running msiexec.exe /? at the console and see what happens.
One problem with the solutions already posted here is that they redirect all output to the console, so if I run ./myprogram >file, the redirection to file gets lost. I've written a new module, github.com/apenwarr/fixconsole, that avoids this problem. You can use it like this:
import (
"fmt"
"github.com/apenwarr/fixconsole"
"os"
)
func main() {
err := fixconsole.FixConsoleIfNeeded()
if err != nil {
fmt.Fatalf("FixConsoleOutput: %v\n", err)
}
os.Stdout.WriteString(fmt.Sprintf("Hello stdout\n"))
os.Stderr.WriteString(fmt.Sprintf("Hello stderr\n"))
}
Answer above was helpful but alas it did not work for me out of the box. After some additional research I came to this code:
// go build -ldflags -H=windowsgui
package main
import "fmt"
import "os"
import "syscall"
func main() {
modkernel32 := syscall.NewLazyDLL("kernel32.dll")
procAllocConsole := modkernel32.NewProc("AllocConsole")
r0, r1, err0 := syscall.Syscall(procAllocConsole.Addr(), 0, 0, 0, 0)
if r0 == 0 { // Allocation failed, probably process already has a console
fmt.Printf("Could not allocate console: %s. Check build flags..", err0)
os.Exit(1)
}
hout, err1 := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
hin, err2 := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
if err1 != nil || err2 != nil { // nowhere to print the error
os.Exit(2)
}
os.Stdout = os.NewFile(uintptr(hout), "/dev/stdout")
os.Stdin = os.NewFile(uintptr(hin), "/dev/stdin")
fmt.Printf("Hello!\nResult of console allocation: ")
fmt.Printf("r0=%d,r1=%d,err=%s\nFor Goodbye press Enter..", r0, r1, err0)
var s string
fmt.Scanln(&s)
os.Exit(0)
}
The key point: after allocating/attaching the console, there is need to get stdout handle, open file using this handle and assign it to os.Stdout variable. If you need stdin you have to repeat the same for stdin.
You can get the desired behavior without using -H=windowsgui; you'd basically create a standard app (with its own console window), and hide it until the program exits.
func Console(show bool) {
var getWin = syscall.NewLazyDLL("kernel32.dll").NewProc("GetConsoleWindow")
var showWin = syscall.NewLazyDLL("user32.dll").NewProc("ShowWindow")
hwnd, _, _ := getWin.Call()
if hwnd == 0 {
return
}
if show {
var SW_RESTORE uintptr = 9
showWin.Call(hwnd, SW_RESTORE)
} else {
var SW_HIDE uintptr = 0
showWin.Call(hwnd, SW_HIDE)
}
}
And then use it like this:
func main() {
Console(false)
defer Console(true)
...
fmt.Println("Hello World")
...
}
If you build a windowless app you can get output with PowerShell command Out-String
.\\main.exe | out-string
your build command may look like:
cls; go build -i -ldflags -H=windowsgui main.go; .\\main.exe | out-string;
or
cls; go run -ldflags -H=windowsgui main.go | out-string
No tricky syscalls nor kernel DLLs needed!

Resources