【问题标题】:Golang C (.so) imports segmentation violation on callGolang C (.so) 在调用时导入分段违规
【发布时间】:2026-02-24 13:20:05
【问题描述】:

您好,我将在 linux 环境中使用 golang 使用第三方库(.so 文件)。所以我试着用一些琐碎的东西来练习一下,比如从 linux 原生库中导入函数。并被困在导入和调用 sqrt 函数上。这是我的代码:

package main
        // #cgo LDFLAGS: -ldl
        // #include <dlfcn.h>
        // #include <stdio.h>
        import "C"
        import "fmt"

        func main() {


            export_name := "sqrt"
            lib_path := "/lib/libm.so.6"

            //Loading .so
            handle := C.dlopen(C.CString(lib_path), C.RTLD_LAZY)
            if handle == nil {
                fmt.Println(lib_path+":\tNOT FOUND")
                return
            } else {
                fmt.Println(lib_path+":\tSUCCESS")
                }

            //looking for function address
            func_pointer := C.dlsym(handle, C.CString(export_name ))
            if func_pointer == nil {
                fmt.Println(export_name+":\tNOT FOUND")
                return
            } else {
                fmt.Println(export_name+":\t", func_pointer)
                }

            //negotiating datatypes
            //From c lib description: double sqrt(double x);
            sqrt  := *(*(func(float64)float64))(func_pointer)

            //Calling function
            sqrt(4)

        }

当我运行它时,我总是遇到分段违规:

/lib/libm.so.6: SUCCESS
sqrt:    0x7f37117ea270
unexpected fault address 0x0
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x80 addr=0x0 pc=0x4019fa]

goroutine 1 [running]:
runtime.throw(0x4a6643, 0x5)
        /usr/lib/go/src/runtime/panic.go:566 +0x95 fp=0xc42004be00 sp=0xc42004bde0
runtime.sigpanic()
        /usr/lib/go/src/runtime/sigpanic_unix.go:27 +0x288 fp=0xc42004be58 sp=0xc42004be00
main.main()
        /home/afx/goc/so.go:37 +0x2ba fp=0xc42004bf48 sp=0xc42004be58
runtime.main()
        /usr/lib/go/src/runtime/proc.go:183 +0x1f4 fp=0xc42004bfa0 sp=0xc42004bf48
runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2086 +0x1 fp=0xc42004bfa8 sp=0xc42004bfa0

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        /usr/lib/go/src/runtime/asm_amd64.s:2086 +0x1
exit status 2

有什么问题? 提前谢谢你。

附: 当我重新定义本机 Go 函数的函数指针时(比如这里 Go: convert unsafe.Pointer to function pointer and vice versa),一切正常。但是导入失败。

【问题讨论】:

标签: c linux go shared-libraries


【解决方案1】:

这是解决方案。我不得不使用桥 C 函数:

package main

// #cgo LDFLAGS: -ldl
// #include <dlfcn.h>
// #include <stdio.h>
//
// double
// my_sqrt_bridge(void *f, double x)
// {
//  //description: ((return_data_type (*)(input_data_type))bridge_input_function_pointer) (bridge_input_value)
//  return ((double (*)(double))f)(x);
// }
import "C"
import "fmt"

func main() {

    export_name := "sqrt"
    lib_path := "/lib/libm.so.6"

    //Loading .so
    handle := C.dlopen(C.CString(lib_path), C.RTLD_LAZY)
    if handle == nil {
        fmt.Println(lib_path + ":\tNOT FOUND")
        return
    } else {
        fmt.Println(lib_path + ":\tSUCCESS")
    }

    //looking for function address
    func_pointer := C.dlsym(handle, C.CString(export_name))
    if func_pointer == nil {
        fmt.Println(export_name + ":\tNOT FOUND")
        return
    } else {
        fmt.Println(export_name+":\t", func_pointer)
    }

    fmt.Printf("%f", C.my_sqrt_bridge(func_pointer, 2))

}

【讨论】:

    【解决方案2】:

    在您的情况下,是否可以让 cgo 为您链接库?例如:

    package main
    
    /*
    #cgo LDFLAGS: -lm
    #include <math.h>
    */
    import "C"
    import "fmt"
    
    func main() {
        fmt.Printf("%g\n", C.sqrt(2))  //prints 1.4142135623730951
    }
    

    对于第三方库/some/lib/dir/libxxx.so:

    LDFLAGS: -L/some/lib/dir -lxxx
    

    【讨论】: