Golang中glibc_version_header的使用与配置
Golang中glibc_version_header的使用与配置 对于C程序,我可以使用glibc_version_header来强制代码链接特定版本的GLIBC符号。这样我就能在一个系统上构建程序,然后在另一个使用不同glibc版本的系统上运行,这对C程序很有效。
现在我正尝试让这个方法适用于Go语言程序。 我已经修改了所有依赖代码,使其包含版本化的符号。 然而,当我运行Go程序时,出现了以下错误:
test22$ ./SDS/src/SDS_fabric/service/bin/x86/bare-metal/SDS_fabric
./SDS/src/SDS_fabric/service/bin/x86/bare-metal/SDS_fabric: /lib64/libc.so.6: version `GLIBC_2.28’ not found (required by ./SDS/src/SDS_fabric/service/bin/x86/bare-metal/SDS_fabric)
问题: 我是否需要在main.go函数中添加一些CGO指令? 如何找出是哪个符号导致了这个问题,以及它包含在哪个代码中?
更多关于Golang中glibc_version_header的使用与配置的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中glibc_version_header的使用与配置的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中使用glibc版本控制需要结合CGO和链接器选项。以下是解决方案:
1. 创建glibc版本头文件
首先创建glibc_version.h头文件:
// glibc_version.h
#ifndef GLIBC_VERSION_H
#define GLIBC_VERSION_H
#include <features.h>
// 定义你需要的GLIBC版本
#define GLIBC_VERSION "2.17"
// 版本化符号包装
#if defined(__GNUC__) && defined(__linux__)
#define GLIBC_COMPAT_SYMBOL(orig_func) \
__asm__(".symver " #orig_func "_compat, " #orig_func "@GLIBC_" GLIBC_VERSION);
#define GLIBC_DEFAULT_SYMBOL(orig_func) \
__asm__(".symver " #orig_func "_default, " #orig_func "@@GLIBC_" GLIBC_VERSION);
// 示例:memcpy的版本化
__asm__(".symver memcpy, memcpy@GLIBC_2.2.5");
__asm__(".symver memcpy_2_14, memcpy@GLIBC_2.14");
#else
#define GLIBC_COMPAT_SYMBOL(orig_func)
#define GLIBC_DEFAULT_SYMBOL(orig_func)
#endif
#endif // GLIBC_VERSION_H
2. 在Go中使用CGO
在main.go或需要的地方添加:
// main.go
package main
/*
// 包含glibc版本头
#include "glibc_version.h"
#include <string.h>
// 包装C函数
void* wrap_memcpy(void* dest, const void* src, size_t n) {
return memcpy(dest, src, n);
}
*/
import "C"
import "unsafe"
func main() {
// 使用C函数触发链接
src := []byte("hello")
dest := make([]byte, len(src))
C.wrap_memcpy(
unsafe.Pointer(&dest[0]),
unsafe.Pointer(&src[0]),
C.size_t(len(src)),
)
// 你的程序逻辑
}
3. 构建脚本
创建构建脚本build.sh:
#!/bin/bash
# build.sh
export CGO_ENABLED=1
export CC=gcc
export CXX=g++
# 设置glibc版本
export GLIBC_VERSION=2.17
# 编译命令
go build -ldflags="-linkmode=external -extldflags='-Wl,--version-script=version.script'" -o output main.go
4. 创建版本脚本
version.script文件:
GLIBC_2.17 {
global:
*;
local:
*;
};
5. 诊断符号问题
使用以下命令找出问题符号:
# 查看二进制文件中的GLIBC依赖
objdump -T your_program | grep GLIBC
# 查看特定版本的符号
objdump -T your_program | grep GLIBC_2.28
# 查看所有版本化符号
readelf -s your_program | grep GLIBC
# 查看动态段
readelf -d your_program | grep NEEDED
# 使用scanelf工具(如果可用)
scanelf -n your_program
6. 完整示例:强制使用旧版本glibc
// +build linux
// glibc_compat.go
package main
/*
#define _GNU_SOURCE
#include <features.h>
// 强制使用GLIBC_2.17
__asm__(".symver memcpy, memcpy@GLIBC_2.2.5");
__asm__(".symver pthread_create, pthread_create@GLIBC_2.2.5");
__asm__(".symver clock_gettime, clock_gettime@GLIBC_2.2.5");
#include <string.h>
#include <pthread.h>
#include <time.h>
// 包装函数
void* compat_memcpy(void* dest, const void* src, size_t n) {
return memcpy(dest, src, n);
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
// 触发链接
var buf1, buf2 [10]byte
C.compat_memcpy(
unsafe.Pointer(&buf1[0]),
unsafe.Pointer(&buf2[0]),
C.size_t(10),
)
fmt.Println("Running with compat GLIBC")
}
7. 构建命令
# 使用外部链接器
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \
go build -ldflags='-linkmode=external -extldflags="-Wl,--version-script=version.script -Wl,-z,now"' \
-o your_program main.go glibc_compat.go
8. 验证构建
# 检查glibc版本要求
objdump -p your_program | grep -A5 "Version References"
# 检查是否还有GLIBC_2.28依赖
strings your_program | grep GLIBC_2.28
# 使用ldd查看动态库
ldd your_program
通过以上配置,Go程序将链接到指定版本的GLIBC符号。使用objdump和readelf工具可以精确找出哪个符号导致了GLIBC_2.28的依赖问题。

