Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross platform linking to a shared object #4808

Open
Promaethius opened this issue Mar 15, 2025 · 2 comments
Open

Cross platform linking to a shared object #4808

Promaethius opened this issue Mar 15, 2025 · 2 comments

Comments

@Promaethius
Copy link

Promaethius commented Mar 15, 2025

I'm messing around with a pet project and getting segfaults when calling symbols from shared objects in CGO. Trying to determine if this is a limitation of TinyGo or I'm going around it the wrong way.

I'm cross compiling to aarch64-unknown-linux-gnu from x86_64, I have the requisite libs at /usr/aarch64-linux-gnu/lib.

The following is a rust cdylib crate with a linker config of aarch64-linux-gnu-gcc. This is my latest iteration where I thought adding a thin C wrapper to .so loading might help. I'm kind of stumped.

qemu-aarch64:

# export LD_LIBRARY_PATH=/lib
# ls /lib -lh
total 4M     
-rwxr-xr-x    1 root     root        1.6M Mar 15 23:51 libc.so.6
-rwxr-xr-x    1 root     root        5.7K Mar 15 23:51 libdl.so.2
-rwxr-xr-x    1 root     root        5.6K Mar 15 23:51 libtest_lib.so
...
# valgrind test_main
==178== Memcheck, a memory error detector
==178== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==178== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==178== Command: test_main
==178== 
==178== Jump to the invalid address stated on the next line
==178==    at 0x0: ???
==178==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==178== 
==178== 
==178== Process terminating with default action of signal 11 (SIGSEGV)
==178==  Bad permissions for mapped region at address 0x0
==178==    at 0x0: ???
==178== 
==178== HEAP SUMMARY:
==178==     in use at exit: 0 bytes in 0 blocks
==178==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==178== 
==178== All heap blocks were freed -- no leaks are possible
==178== 
==178== For lists of detected and suppressed errors, rerun with: -s
==178== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

.so

#[no_mangle]
pub extern "C" fn add(left: u8, right: u8) -> u8 {
    left + right
}

tinygo version 0.36.0 linux/amd64 (using go version go1.24.0 and LLVM version 19.1.2)
TinyGo flags: CGO_ENABLED=1 GOOS=linux GOARCH=arm64 ldflags "-extldflags '-L/usr/aarch64-linux-gnu/lib -lc -ldl'"

main.go

package main

/*
#cgo CFLAGS: -g -fno-omit-frame-pointer
#include <stdio.h>
#include <dlfcn.h>
#include <stdint.h>

static void *llvm_target_handle = NULL;

typedef uint8_t (*add_t)(uint8_t, uint8_t);


void load() {
	llvm_target_handle = dlopen("/lib/libtest_lib.so", RTLD_NOW | RTLD_GLOBAL);
    if (!llvm_target_handle) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return;
    }
}

uint8_t call_add(uint8_t a, uint8_t b) {
	add_t add;

	add = (add_t)dlsym(llvm_target_handle, "add");
	if (!add) {
        fprintf(stderr, "Error: Could not find symbol add: %s\n", dlerror());
        return 0;
    }

    return add(a, b);
}

void close_lib() {
    if (llvm_target_handle) {
        dlclose(llvm_target_handle);
        llvm_target_handle = NULL;
    }
}
*/
import "C"
import "fmt"

func main() {
	C.load()
	defer C.close_lib()

	fmt.Println(C.call_add(C.uint8_t(1), C.uint8_t(2)))
}
@Promaethius
Copy link
Author

afaict .so loading doesn't exist in TinyGo and the cgo pointer to the function is never populated. Converting the rust library to static, and passing static flags for LL allows the function to execute.

@aykevl
Copy link
Member

aykevl commented Mar 18, 2025

We use musl statically linked as our libc, and (if I remember correctly) musl doesn't support dlopen when statically linked.
I'm surprised no error gets printed, because I think dlopen is supposed to return NULL in this case.

(Also, linking object files with different libcs is likely going to go wrong at some point).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants