C-shared библиотки

40 views
Skip to first unread message

Александр Воробьёв

unread,
Mar 24, 2018, 4:26:04 PM3/24/18
to Golang Russian
Добрый день уважаемым участникам. Продолжаю потихоньку ковыряться с Golang, и захотелось странного. Есть некий программный продукт, который умеет плагины. Плагины можно писать на FPC,C,C++. С последнего релиза Golang научился в библиотеки с нормальным экспортом. Вполне себе дергаются функции из собранной в Go библиотеке из Lazarus и т.д. Так вот, программный продукт требует на вход следующее(С++):
static char* exports[] =
{
    (char*)"Add",(char*)"procedure Add(a, b :integer; var result : integer);"
};

extern "C" void __declspec(dllexport) Add (int a, int b , int & res)
{
     res = a + b;    

}

extern "C" int __declspec(dllexport) GetPluginABIVersion()
{
    return 2;
}

extern "C" int __declspec(dllexport) GetFunctionCount()
{
    return NumExports;
}

extern "C" int __declspec(dllexport) GetFunctionInfo(int index, void* &address, char* &def)
{
    if (index < NumExports)
    {
        #if defined _WIN32 || defined _WIN64
        address = (void*)GetProcAddress(dllinst, exports[index * 2]);
        #else
        address = dlsym(RTLD_DEFAULT, exports[index * 2]);
        #endif
        strcpy(def, exports[index * 2 + 1]);
        return index;
    }
    return -1;
}

Прога загружая плагин, получает из GetFunctionCount количество функций плагина. Затем вызывает n раз GetFunctionCount, из которой получает указатель на функцию, которую надо пробросить из дебрей библиотеки и текстовое определение оной. Мне хочется странного, написать плагин подобного рода на Go. Описательная часть экспортируется, всё замечательно. Текстовая часть тоже пробрасывается и из проги получается. А вот указатель на функцию в библиотеке - никак. Тоесть нет, указатель на функцию то я получить могу, только его нельзя использовать из вне. Сейчас попытка выглядит так: 

import "C"
import "fmt"
import "unsafe"
import "reflect"
import "runtime"

func GetFunc(outFuncPtr interface{}, name string) error {
	codePtr, err := FindFuncWithName(name)
	if err != nil {
		return err
	}
	CreateFuncForCodePtr(outFuncPtr, codePtr)
	return nil
}

type Func struct {
	codePtr uintptr
}

func CreateFuncForCodePtr(outFuncPtr interface{}, codePtr uintptr) {
	outFuncVal := reflect.ValueOf(outFuncPtr).Elem()
	newFuncVal := reflect.MakeFunc(outFuncVal.Type(), nil)
	funcValuePtr := reflect.ValueOf(newFuncVal).FieldByName("ptr").Pointer()
	funcPtr := (*Func)(unsafe.Pointer(funcValuePtr))
	funcPtr.codePtr = codePtr
	outFuncVal.Set(newFuncVal)
}

func FindFuncWithName(name string) (uintptr, error) {
	for moduleData := &Firstmoduledata; moduleData != nil; moduleData = moduleData.next {
		for _, ftab := range moduleData.ftab {
			f := (*runtime.Func)(unsafe.Pointer(&moduleData.pclntable[ftab.funcoff]))
			if f.Name() == name {
				return f.Entry(), nil
			}
		}
	}
	return 0, fmt.Errorf("Invalid function name: %s", name)
}

var Firstmoduledata Moduledata

type Moduledata struct {
	pclntable    []byte
	ftab         []Functab
	filetab      []uint32
	findfunctab  uintptr
	minpc, maxpc uintptr

	text, etext           uintptr
	noptrdata, enoptrdata uintptr
	data, edata           uintptr
	bss, ebss             uintptr
	noptrbss, enoptrbss   uintptr
	end, gcdata, gcbss    uintptr

	
	typelinks []interface{}

	modulename string
	
	modulehashes []interface{}

	gcdatamask, gcbssmask Bitvector

	next *Moduledata
}

type Functab struct {
	entry   uintptr
	funcoff uintptr
}

type Bitvector struct {
	n        int32 // # of bits
	bytedata *uint8
}

func GetStrFromDLL(str *C.char) *C.char {
	return C.CString(fmt.Sprintf("From DLL: %s!\n", C.GoString(str)))
}


func GetIntFromDLL() int32 {
	return 42
}


//export GetPluginABIVersion
func GetPluginABIVersion () int32 {
	return 2
}
//export GetFunctionCount
func GetFunctionCount () int32 {
    return 2
}
//export GetFunctionInfo
func GetFunctionInfo(x int32,  ProcAddr *uintptr,  ProcDef **C.char) int32{
	var s string
	
	switch x {
	case 0: {
	 s = "function GetStrFromDLL(P: Pchar):Pchar;"
	 *ProcDef = C.CString(fmt.Sprintf("%s", s))
	 //var GetStrFromDLLFunc func(*C.char) *C.char
	// GetFunc(&GetStrFromDLLFunc, "libGoPlugin.GetStrFromDLL")
	 *ProcAddr = reflect.ValueOf(GetStrFromDLL).Pointer()
	 
	}
	case 1: {
	s = "function GetIntFromDLL():integer;"
	 *ProcDef = C.CString(fmt.Sprintf("%s", s))
	 //var GetIntFromDLLFunc func() int32
	// GetFunc(&GetIntFromDLLFunc, "libGoPlugin.GetIntFromDLL")
	 *ProcAddr = reflect.ValueOf(GetIntFromDLL).Pointer()
	 
	}
	}
	return x;
}



func main() {
	// Need a main function to make CGO compile package as C shared library
}

Собственно вопрос заключается в том, можно ли пробросить указатель на Go функцию из библиотеки и использовать её в приложении на другом языке? Или же это не возможно средствами Go?

PS: ProcDef Приложение получает, а указатель роняет его и всё.

 

Aln Kapa

unread,
Sep 20, 2018, 2:15:48 AM9/20/18
to gola...@googlegroups.com
Добрый день, хотелось бы узнать как продвигается, есть решение?

сб, 24 мар. 2018 г. в 23:26, Александр Воробьёв <cyni...@gmail.com>:
--
Вы получили это сообщение, поскольку подписаны на группу "Golang Russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес golang-ru+...@googlegroups.com.
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages