Below is a working example in C. Once you have
that going, then add the CGO layer on top to call from Go.
Note I seem to recall you might have to mark your C function as //extern
...maybe, if
in a separate C file and not inline in the .go file... read the CGO docs
in full for details.
$ cat libexample.c
#include <stdio.h>
int multiply(int a, int b) {
return a * b;
}
$ gcc -shared -o libexample.so -fPIC libexample.c
$ cat dynamic_loading.c
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
int main() {
// Open the shared library
void* handle = dlopen("./libexample.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "Error loading library: %s\n", dlerror());
return 1;
}
// Get the function pointer by name
int (*multiply)(int, int) = dlsym(handle, "multiply");
if (!multiply) {
fprintf(stderr, "Error finding function: %s\n", dlerror());
dlclose(handle);
return 1;
}
// Call the function
int result = multiply(5, 7);
printf("5 * 7 = %d\n", result);
// Clean up
dlclose(handle);
return 0;
}
$ gcc -o user_of_library dynamic_loading.c
$ ./user_of_library
5 * 7 = 35
Go host, from AI but does run
package main /* #cgo LDFLAGS: -ldl #include <dlfcn.h> #include <stdlib.h>
#include <stdio.h> // Define the function type that matches our C function
typedef int (*multiply_func)(int, int); // Helper function to load and call
the multiply function int call_multiply(int a, int b) { void* handle =
dlopen("./libexample.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "Error
loading library: %s\n", dlerror()); return -1; } // not C, but you'll need
the moral equivalent of // defer dlclose(handle); // to clean up.
multiply_func multiply = (multiply_func)dlsym(handle, "multiply"); if
(!multiply) { fprintf(stderr, "Error finding function: %s\n", dlerror());
return -1; } return multiply(a, b); } */ import "C" import "fmt" func
main() { // Call the C function through our wrapper result :=
C.call_multiply(C.int(5), C.int(7)) if result == -1 { fmt.Println("Error
calling multiply function") return } fmt.Printf("5 * 7 = %d\n",
int(result)) }
$ go run user_of_lib_from_go.go
5 * 7 = 35
On Thursday, May 15, 2025 at 10:45:00 AM UTC+1 Bruno Albuquerque wrote:
> You can not directly call a C function pointer from Go. You will need a
> CGO wrapper that calls it and them you call that wrapper from Go.
>
> -Bruno
>
>
> On Thu, May 15, 2025, 5:20 AM rudeus greyrat <[email protected]>
> wrote:
>
>> Hello,
>>
>> Thanks for your answer.
>>
>> Three points to note:
>>
>> - I never asked how to create an so, I already have a given so :/
>> - No need to provide the code because the issue is simple to
>> describe: I have an address of a function in a Go variable, how to call
>> it ?
>> - AI is garbage (even though I use it)
>>
>> I thought about using assembly with a call instruction but I hoped
>> someone knowledgable would tell me there is a built in Go function for that.
>>
>> Regards,
>> Rudeus
>>
>>
>>
>> Le jeudi 15 mai 2025 à 02:46:18 UTC+2, Kurtis Rader a écrit :
>>
>>> On Wed, May 14, 2025 at 4:17 PM rudeus greyrat <[email protected]>
>>> wrote:
>>>
>>>> I am still a beginner in Linux internals so please bear with me.
>>>>
>>>> I have a ".so" that export "helloworld" function.
>>>>
>>>> I load the ".so" using CGO by:
>>>>
>>>> 1. Creating a file descriptor
>>>> 2. using ```write``` to write the so to it
>>>>
>>>> A shared library (".so" file) has a complex structure. You normally
>>> create one using a compiler and related tools. For example, the Go compiler
>>> can create a .so file from Go source code using a command like
>>>
>>> go build -buildmode=c-shared -o mylib.so
>>>
>>> It seems unlikely you are creating a valid .so file by opening an empty
>>> file and writing to it unless you are simply copying one .so file to
>>> another file.
>>>
>>>>
>>>> 1. Get a handle using ```dlopen```
>>>> 2. Get the address of ```helloworld``` symbol using ```dlsym```
>>>>
>>>> The address of "helloworld" is saved in a go variable called
>>>> ```address```
>>>>
>>>> How to call ```address``` ?
>>>>
>>>> On windows I am able to call address using ```syscall.SyscallN```. On
>>>> Linux I tried with
>>>> ```
>>>> r1, r2, err := syscall.Syscall(address, 0, 0, 0)
>>>> ```
>>>>
>>>> And I get "function not implemented" error.
>>>>
>>>
>>> I can't speak to Windows but on Unix like operating systems, such as
>>> Linux, a function in a shared library is a user space function, not a
>>> kernel entry point. A syscall is the way you call OS kernel functions, not
>>> user space functions. I wouldn't expect syscall.Syscall() to work on
>>> Windows when passed the address of a function in a DLL. Did you actually
>>> confirm that it does work when passed the address of a DLL user space
>>> function? In any case this definitely won't work on Linux.
>>>
>>> I searched for "how to call a function in a shared library in go" in
>>> Chrome and the results included an AI generated example of how to do this
>>> along with links to many articles and other sources such as StackOverflow.
>>> If you're still having problems ask again but show us the source code you
>>> wrote and the commands you ran to compile it.
>>>
>>> --
>>> Kurtis Rader
>>> Caretaker of the exceptional canines Junior and Hank
>>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> To view this discussion visit
>> https://groups.google.com/d/msgid/golang-nuts/6df9116e-d5dd-4b93-bd0d-45df42c24626n%40googlegroups.com
>>
>> <https://groups.google.com/d/msgid/golang-nuts/6df9116e-d5dd-4b93-bd0d-45df42c24626n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/golang-nuts/e29eac0a-6735-4e13-a90c-cc4e14572587n%40googlegroups.com.