Golang在Alpine Linux上使用ctypes loadlibrary()失败:OSError: ./cc.so重定位错误 - 初始exec TLS解析为动态定义

Golang在Alpine Linux上使用ctypes loadlibrary()失败:OSError: ./cc.so重定位错误 - 初始exec TLS解析为动态定义 我正在基于Alpine的容器中,在Python脚本(使用ctypes加载库)中使用Go构建的共享库。

/usr/src/app # go build -o cc.so -buildmode=c-shared main.go
/usr/src/app # readelf -d cc.so

动态段位于偏移量0x10cd10处,包含22个条目:

标签 类型 名称/值 0x0000000000000001 (NEEDED) 共享库: [libc.musl-x86_64.so.1] 0x0000000000000010 (SYMBOLIC) 0x0 0x000000000000000c (INIT) 0x42000 0x000000000000000d (FINI) 0x92ed9 0x0000000000000019 (INIT_ARRAY) 0xa2078 0x000000000000001b (INIT_ARRAYSZ) 8 (字节) 0x000000006ffffef5 (GNU_HASH) 0x270 0x0000000000000005 (STRTAB) 0xa50 0x0000000000000006 (SYMTAB) 0x378 0x000000000000000a (STRSZ) 1026 (字节) 0x000000000000000b (SYMENT) 24 (字节) 0x0000000000000003 (PLTGOT) 0x10deb0 0x0000000000000002 (PLTRELSZ) 720 (字节) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x41a00 0x0000000000000007 (RELA) 0xe58 0x0000000000000008 (RELASZ) 265128 (字节) 0x0000000000000009 (RELAENT) 24 (字节) 0x000000000000001e (FLAGS) SYMBOLIC BIND_NOW STATIC_TLS 0x000000006ffffffb (FLAGS_1) 标志: NOW NODELETE 0x000000006ffffff9 (RELACOUNT) 11040 0x0000000000000000 (NULL) 0x0

/usr/src/app # python test.py

回溯(最近一次调用): 文件"test.py",第2行,在 lib = ctypes.cdll.LoadLibrary(’./cc.so’) 文件"/usr/lib/python2.7/ctypes/init.py",第444行,在LoadLibrary return self.dlltype(name) 文件"/usr/lib/python2.7/ctypes/init.py",第366行,在__init_ self._handle = _dlopen(self._name, mode) OSError: 重定位./cc.so时出错:initial-exec TLS解析为./cc.so中的动态定义

但如果我使用ubuntu16.04镜像并安装Go和Python进行相同的测试,它可以正常工作。

main.go和test.py的内容如下:

//main.go
package main

import "C"

//export add
func add(left, right int) int {
return left + right
}

//export minus
func minus(left, right int) int {
return left - right
}

//export multiply
func multiply(left, right int) int {
return left * right
}

//export divide
func divide(left, right int) int {
return left / right
}

//export testPrint
func testPrint(){
print("test")
}

func main() {
}
// test.py
import ctypes
lib = ctypes.cdll.LoadLibrary('./cc.so')
if lib is not None:
print ("can load so")

有没有人建议如何指定Go构建命令行来解决这个问题?

谢谢


更多关于Golang在Alpine Linux上使用ctypes loadlibrary()失败:OSError: ./cc.so重定位错误 - 初始exec TLS解析为动态定义的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang在Alpine Linux上使用ctypes loadlibrary()失败:OSError: ./cc.so重定位错误 - 初始exec TLS解析为动态定义的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个典型的Alpine Linux与Go共享库的TLS(线程局部存储)兼容性问题。Alpine使用musl libc,而Ubuntu使用glibc,它们在处理TLS时有所不同。

问题在于Go默认构建的共享库使用了initial-exec TLS模型,但musl要求使用local-exec模型。可以通过设置CGO标志来指定TLS模型:

CGO_LDFLAGS="-Wl,-z,nostart-stop-gc -Wl,-z,relro,-z,now" go build -o cc.so -buildmode=c-shared main.go

或者更直接地设置TLS模型:

CGO_LDFLAGS="-Wl,-z,relro,-z,now -Wl,-z,nodump" go build -o cc.so -buildmode=c-shared main.go

另一种方法是使用-extldflags明确指定链接器标志:

go build -o cc.so -buildmode=c-shared -ldflags="-extldflags '-Wl,-z,relro,-z,now -Wl,-z,nodump'" main.go

如果上述方法仍然不行,可以尝试强制使用local-exec TLS模型:

CGO_LDFLAGS="-Wl,-z,relro,-z,now -Wl,-z,nodump -Wl,-z,nostart-stop-gc" go build -o cc.so -buildmode=c-shared main.go

在Alpine环境中,还需要确保安装了必要的开发工具:

apk add --no-cache gcc musl-dev

验证构建后的库:

readelf -d cc.so | grep FLAGS

应该能看到TLS相关的标志已经正确设置。构建成功后,Python脚本应该能正常加载共享库:

import ctypes
lib = ctypes.cdll.LoadLibrary('./cc.so')
print("Library loaded successfully")

# 测试函数调用
result = lib.add(10, 5)
print(f"add(10, 5) = {result}")

这些方法通过调整链接器标志和TLS模型来解决musl libc与Go共享库的兼容性问题。

回到顶部