Golang C (.so) 在调用时出现分段错误

huangapple go评论96阅读模式
英文:

Golang C (.so) imports segmentation violation on call

问题

你好,以下是你提供的代码的翻译:

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"

	// 加载 .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")
	}

	// 查找函数地址
	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)
	}

	// 协商数据类型
	// 从 C 库描述中得知:double sqrt(double x);
	sqrt := *(*(func(float64) float64))(func_pointer)

	// 调用函数
	sqrt(4)

}

当运行这段代码时,你总是得到段错误(segmentation violation):

/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 本地函数的函数指针时(例如在这里 https://stackoverflow.com/questions/22933169/go-convert-unsafe-pointer-to-function-pointer-and-vice-versa),一切都正常工作。但是导入失败。

英文:

Hello I'm going to work with thirdparty library (.so file) with golang in linux environment. So I tried to practice a bit with something trivial, like importing functions from linux native libs. And got stuck on importing and calling sqrt function. Here is my code:

package main
    	// #cgo LDFLAGS: -ldl
    	// #include &lt;dlfcn.h&gt;
    	// #include &lt;stdio.h&gt;
    	import &quot;C&quot;
    	import &quot;fmt&quot;
    
    	func main() {
    
    	
    		export_name := &quot;sqrt&quot;
    		lib_path := &quot;/lib/libm.so.6&quot;
    
    		//Loading .so
    		handle := C.dlopen(C.CString(lib_path), C.RTLD_LAZY)
    		if handle == nil {
    			fmt.Println(lib_path+&quot;:\tNOT FOUND&quot;)
    			return
    		} else {
    			fmt.Println(lib_path+&quot;:\tSUCCESS&quot;)
    			}
    
    		//looking for function address
    		func_pointer := C.dlsym(handle, C.CString(export_name ))
    		if func_pointer == nil {
    			fmt.Println(export_name+&quot;:\tNOT FOUND&quot;)
    			return
    		} else {
    			fmt.Println(export_name+&quot;:\t&quot;, func_pointer)
    			}
    
    		//negotiating datatypes
            //From c lib description: double sqrt(double x);
    		sqrt  := *(*(func(float64)float64))(func_pointer)

    		//Calling function
    		sqrt(4)
    
    	}

when I run it, I always get segmentation violation:

/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

What is the problem ?
Thank you in advance.

P.S.
When I'm redefining function pointers of native Go functions (like here https://stackoverflow.com/questions/22933169/go-convert-unsafe-pointer-to-function-pointer-and-vice-versa) everything works fine. But import fails.

答案1

得分: 2

这是解决方案。我必须使用桥接的 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))

}
英文:

Here is solution. I had to use bridge C function:

package main

// #cgo LDFLAGS: -ldl
// #include &lt;dlfcn.h&gt;
// #include &lt;stdio.h&gt;
//
// 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 &quot;C&quot;
import &quot;fmt&quot;

func main() {

	export_name := &quot;sqrt&quot;
	lib_path := &quot;/lib/libm.so.6&quot;

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

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

	fmt.Printf(&quot;%f&quot;, C.my_sqrt_bridge(func_pointer, 2))

}

答案2

得分: 0

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

package main

/*
#cgo LDFLAGS: -lm
#include <math.h>
*/
import "C"
import "fmt"

func main() {
    fmt.Printf("%g\n", C.sqrt(2))  //打印结果为1.4142135623730951
}

对于第三方库/some/lib/dir/libxxx.so,可以使用以下方式链接:

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

Would it be possible in your case to let cgo link the library for you? Eg:

package main

/*
#cgo LDFLAGS: -lm
#include &lt;math.h&gt;
*/
import &quot;C&quot;
import &quot;fmt&quot;

func main() {
	fmt.Printf(&quot;%g\n&quot;, C.sqrt(2))  //prints 1.4142135623730951
}

For a third party library /some/lib/dir/libxxx.so:

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

huangapple
  • 本文由 发表于 2016年12月26日 17:23:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/41328972.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定