编译动态库时遇到relocation R_X86_64_32 against `a local symbol'的错误

本文详细解析了使用GCC编译器时遇到的与-fPIC参数相关的问题,特别是当尝试创建共享对象时出现的错误。通过实际案例,阐述了如何正确地在编译过程中应用-fPIC参数,以避免定位符号的重定位错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

$gcc -c hello.c

$gcc -c main.c

$gcc -shared -fPIC -o hello hello.o main.o

… relocation R_X86_64_32 against `a local symbol’ can not be used when making a shared object; recompile with -fPIC

… could not read symbols: Bad value

解决办法编译器已经提示了:recompile with -fPIC

但是我们应该重新编译谁带上这个参数呢?经过我几番折腾,发现如下情况:

1、编译.o文件的时候,没有加参数-fPIC,(网友说这样的问题在gcc version 3.4.6版本没有发生,即该版本编译器默认加上了-fPIC,未验证过),本人在出现问题时查看了当前系统的gcc版本,为下面红色标记部分。

/home/gateway/priv/yzj/union_183>gcc -v

Using built-in specs.
Target: x86_64-redhat-linux
Configured with: …/configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=x86_64-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-48))

2、当前程序中有用到某个静态库,那个静态库编译.o文件的时候没有加上-fPIC(静态库其实就是.o文件打包)。补充一点:我发现手写Makefile时即使不加-fPIC也没有这个问题,这一点很郁闷,这个只在用automake工具编译出.a文件时才出现过。

原因:某些版本的gcc默认没加-fPIC参数

解决办法:保证你编译.o文件的时候,都加上-fPIC,这样你才能编译出动态库来。

$gcc-fPIC -c hello.c

$gcc-fPIC -c main.c

$gcc -shared -fPIC -o hello hello.o main.o

这样能顺利生成hello.
补充说明:以上问题的出现是基于看到“红黑联盟网站上的一篇关于链接及库讲解”文章中列举出的案例,文中作者在论述时是用本文开头的方法来编译且能成功,但本人在做测试时发现存在问题故而写下此篇,该文章链接地址如下。

file:///H:/%E5%8F%82%E8%80%83%E7%AC%94%E8%AE%B0/%E7%8B%AC%E7%AB%8B%E6%80%A7%E8%B5%84%E6%96%99/%E7%BE%A4%E9%87%8C%E8%B5%84%E6%96%99%E6%94%B6%E9%9B%86/%E5%8A%A8%E6%80%81%E5%BA%93%E7%B3%BB%E5%88%97/[Linux]%E9%93%BE%E6%8E%A5%EF%BC%8C%E9%9D%99%E6%80%81%E5%BA%93%E5%92%8C%E5%8A%A8%E6%80%81%E5%BA%93%20-%20%E5%85%B6%E4%BB%96%E7%BB%BC%E5%90%88%20-%20%E7%BA%A2%E9%BB%91%E8%81%94%E7%9B%9F.htm

程序清单

1.main.c

int main() 

hello(“everyone”); 
return 0; 
}

2.hello.c

#include <stdio.h> 
void hello(const char *name) 
{
printf(“Hello %s!/n”, name); 
}

3.hello.h

#ifndef HELLO_H 
#define HELLO_H 
 
void hello(const char *name); 
 
#endif //HELLO_H

作者:usbdrivers
来源:优快云
原文:https://blog.youkuaiyun.com/USBdrivers/article/details/8854256
版权声明:本文为博主原创文章,转载请附上博文链接!

<think>我们正在解决使用静态链接编译Python出现的relocation R_X86_64_32 against hidden symbol '__TMC_END__'错误。这个错误通常与位置无关代码(PIC)和静态链接的冲突有关。在静态链接,我们需要确保所有对象文件都使用-fPIC(位置无关代码)选项编译,以避免此类重定位错误。 根据错误信息,它涉及一个隐藏符号'__TMC_END__',这通常与TLS(线程局部存储)或C++运行有关。但Python主要是用C写的,所以可能是在链接C++库(如libstdc++)出现的问题,或者是Python中使用了C++扩展(如_ctypes模块)?实际上,即使Python解释器本身是C,但构建过程中可能会链接到C++库(例如,如果使用了C++编译编译某些部分,或者链接了C++写的扩展模块)。然而,在静态链接,我们通常使用`musl-gcc`,它默认是C编译器,所以我们需要确保在构建Python正确处理C++依赖(如果存在的话)。 但是,请注意,我们正在使用Musl libc,并且尝试静态链接。错误中提到的`crtbeginT.o`是gcc用于静态链接的C运行初始化文件,与C++相关?实际上,`crtbeginT.o`是用于支持C++的静态链接的(特别是用于处理静态构造和析构)。因此,这个错误可能表明我们在静态链接涉及C++代码,而Python的某些部分可能依赖于C++(例如,通过扩展模块)。 然而,Python官方发行版主要是用C写的,但有些扩展可能使用C++(如`_decimal`模块)。不过,默认情况下,Python的构建系统使用C编译器。因此,我们可能需要显式地避免C++相关的内容,或者确保使用正确的标志。 错误信息中的`relocation R_X86_64_32`表明在64位系统上尝试使用32位绝对地址重定位,这在位置相关的代码中是不允许的,尤其是在生成共享库或PIE(位置无关可执行文件)。但是,我们正在构建静态可执行文件,所以按理说应该允许绝对地址重定位?然而,在64位系统中,即使是静态链接,由于地址空间布局随机化(ASLR)的要求,现代系统也倾向于使用位置无关的可执行文件(PIE)。而PIE要求所有代码都是位置无关的(即使用-fPIC编译)。 因此,解决这个问题的关键可能是确保在编译所有对象文件使用`-fPIC`选项,即使对于静态链接也是如此。因为静态链接的可执行文件如果被构建为PIE(这是现在很多系统的默认设置),那么就需要位置无关代码。 具体步骤: 1. 在配置Python,确保在CFLAGS中添加`-fPIC`。 2. 同,在链接使用`-static`,并且可能需要指定一些额外的链接选项来避免动态链接。 但是,我们之前已经设置了`CFLAGS="-fPIC -I/usr/local/musl/include"`,所以应该已经包含了`-fPIC`。那么为什么还会出现这个错误呢? 可能的原因:某些文件(特别是C++文件)没有使用`-fPIC`编译。然而,Python源码中几乎没有C++文件。所以我们需要检查是否在链接过程中引入了外部静态库(如libstdc++)而没有使用`-fPIC`编译。 由于我们使用的是Musl,并且使用`musl-gcc`,它默认不会链接C++库。因此,如果Python构建过程中没有使用C++,那么就不会链接libstdc++。但错误中提到了`crtbeginT.o`,这通常是由g++驱动程序链接的,而不是gcc。所以,可能是我们在构建过程中意外地使用了g++?或者构建系统在检测到某些扩展需要C++使用了g++? 实际上,在Python的配置过程中,我们可以通过设置`CXX`环境变量来指定C++编译器,但我们没有设置,所以可能构建系统没有使用C++。 但是,错误信息中明确提到了`crtbeginT.o`,这让我们怀疑是否在链接使用了C++的启动文件。因此,我们需要检查链接命令,确保没有引入C++的运行。 另一种可能性:这个错误可能是由于在链接静态可执行文件,链接器要求所有对象文件都使用`-fPIC`编译,但某些对象文件(可能是来自C运行的启动文件)不是用`-fPIC`编译的。而Musl的静态库通常是支持静态链接的,但gcc的启动文件(crt*.o)可能不是用`-fPIC`编译的。 解决方案:尝试使用`-static-pie`选项(如果支持),或者显式地禁用PIE(但这不是推荐的做法,因为这会降低安全性)。然而,在静态链接,PIE是可选的。我们可以尝试在链接禁用PIE。 但是,在配置Python,我们可以通过设置`LDFLAGS`来传递链接选项。我们可以尝试: LDFLAGS="-static -no-pie" `-no-pie`选项告诉链接器生成非位置无关的可执行文件。这样,就不需要所有对象文件都是PIC的,从而避免这个重定位错误。 然而,在64位系统上,使用绝对重定位的非PIE可执行文件可能无法在启用了ASLR的系统上运行(但通常静态链接的非PIE可执行文件还是可以运行的,只是没有地址随机化)。所以,我们可以尝试这种方法。 但是,请注意,Musl libc的静态链接是否支持非PIE?实际上,Musl本身是支持静态链接的,而且不要求PIE。所以,我们可以尝试禁用PIE。 步骤调整: 在配置Python,添加`LDFLAGS="-static -no-pie"`。另外,确保`CFLAGS`包含`-fPIC`(因为即使非PIE,有些情况也需要,但这里我们为了解决问题,可以尝试不用,但错误是发生在链接阶段,所以可能还是要用?) 实际上,错误是链接阶段的重定位错误,所以可能是链接器在尝试创建PIE可执行文件(因为现在gcc默认创建PIE),遇到了非PIC的代码。因此,我们有两个选择: a) 让所有代码都是PIC(通过-fPIC),包括启动文件(但启动文件不是我们编译的,所以可能无法控制) b) 禁用PIE。 由于我们使用的是静态链接,并且使用的是Musl,我们可以尝试禁用PIE。 具体修改配置步骤: 将之前的`./configure`命令中的`LDFLAGS`改为`-static -no-pie`,同保留`CFLAGS`中的`-fPIC`(因为有些模块可能需要,比如如果以后要作为共享库使用,但这里我们构建的是静态可执行文件,所以严格来说不需要,但为了安全,保留)。 修改后的配置命令: ```bash ./configure \ --prefix=/usr/local/python-musl \ --enable-optimizations \ --with-lto \ --disable-shared \ --enable-static \ CC="musl-gcc" \ LDFLAGS="-static -no-pie" \ CFLAGS="-I/usr/local/musl/include" ``` 注意:这里我们移除了`CC="musl-gcc -static"`,因为我们在`LDFLAGS`中已经指定了`-static`。同,我们添加了`-no-pie`。 但是,`-no-pie`是一个链接器选项,我们需要确保它被传递给链接器。另外,有些旧版本的gcc可能不支持`-no-pie`,那么可以尝试使用`-nopie`(但更常见的是使用`-no-pie`)。 如果上述方法无效,我们还可以尝试在链接移除对C++的依赖。因为错误可能由于链接器尝试链接C++的启动代码,但实际上我们并没有使用C++。我们可以通过设置`LDFLAGS`来避免链接C++标准库: LDFLAGS="-static -no-pie -nostdlib++" 但是,`-nostdlib++`不是标准选项,我们可以使用`-nostdlib`,但这会移除所有的标准库,包括C库,所以不行。我们可以使用`-nodefaultlibs`,但同样会移除所有默认库,需要手动指定所有需要的库,比较复杂。 另一种方法:显式指定链接器为`ld`,并手动链接,但这会非常复杂。 因此,我们优先尝试使用`-no-pie`。 如果问题仍然存在,我们可以尝试重新编译gcc的启动文件(crt*.o)使其支持PIC,但这很复杂,通常不推荐。 另外,参考引用[1]中提到了Windows安装Cygwin,但我们的问题是在Linux上使用Musl,所以可能不直接相关。但错误信息类似,都是关于`crtbeginT.o`的重定位错误。在引用[1]中,解决方案可能是使用正确的静态链接选项。在Linux环境下,我们可以尝试使用`gcc`的`-static`选项配合`-fPIE`和`-pie`,但这样就需要所有对象文件都是PIC。而我们现在使用的是`-no-pie`,所以不需要PIC。 总结步骤: 1. 确保已安装Musl和必要的静态库(如zlib、openssl的静态库)。 2. 设置环境变量,使用Musl的编译器。 3. 在配置Python,使用上面的配置命令(包含`-no-pie`)。 4. 如果出现其他错误,可能需要调整其他选项。 如果上述方法无效,我们可以尝试在配置之前设置环境变量`export _POSIX2_VERSION=199209`,这有可以避免一些与标准相关的问题。 另外,我们也可以尝试升级gcc和binutils,因为旧版本可能有bug。 最后,如果问题仍然存在,我们可以考虑使用Alpine Linux的交叉编译环境来构建静态Python,因为Alpine默认使用Musl,并且其工具链已经为静态链接做好了准备。 生成相关问题: 1. 如何在静态链接Python避免使用C++运行? 2. 如何为Musl libc构建一个完全静态的Python可执行文件? 3. 在静态链接Python如何解决其他常见的链接器错误? 4. 如何验证静态链接的Python二进制文件是否真正独立? 5. 静态链接的Python二进制文件在不同Linux发行版之间的兼容性如何?</think>## 解决静态链接编译Python出现的 relocation R_X86_64_32 错误 ### 问题分析 错误 `relocation R_X86_64_32 against hidden symbol '__TMC_END__'` 通常发生在使用 `-static` 选项进行静态链接,主要原因是**位置相关的代码与位置无关代码(PIC)的冲突**。当编译器尝试将非PIC代码与静态库链接,会导致这种重定位错误[^1]。 ### 解决方案步骤 #### 1. 确保所有代码使用位置无关编译 ```bash # 在Python配置前设置CFLAGS export CFLAGS="-fPIC -static" export LDFLAGS="-static" ``` #### 2. 配置Python添加关键选项 ```bash ./configure \ --prefix=/usr/local/python-musl \ --disable-shared \ --enable-static \ --without-ensurepip \ --with-system-ffi=no \ CC="musl-gcc" \ CFLAGS="-fPIC -static" \ LDFLAGS="-static -Wl,--exclude-libs,ALL" ``` #### 3. 修改Makefile解决特定错误编译前编辑生成的Makefile: ```diff # 在Makefile中找到并修改 - BUILD_LDFLAGS = + BUILD_LDFLAGS = -no-pie # 找到并添加 - LINKFORSHARED = + LINKFORSHARED = -static -no-pie ``` #### 4. 强制使用静态链接库 ```bash # 创建libc_musl.a的符号链接 sudo ln -s /usr/lib/x86_64-linux-gnu/libc.a /usr/lib/x86_64-linux-gnu/libc_musl.a # 配置添加 ./configure ... --with-libs='-l:libc_musl.a -l:libpthread.a' ``` ### 关键选项说明 | 选项 | 作用 | 必要性 | |------|------|--------| | `-fPIC` | 生成位置无关代码 | 必需 | | `-static` | 强制静态链接 | 必需 | | `-no-pie` | 禁用位置无关可执行文件 | 推荐 | | `--exclude-libs,ALL` | 排除所有隐式库链接 | 推荐 | | `--without-ensurepip` | 禁用pip安装器 | 可选 | ### 验证解决方案 ```bash # 编译后检查链接类型 readelf -d ./python | grep 'FLAGS' # 应显示: STATIC_TLS (指示静态线程局部存储) file ./python # 应显示: ELF 64-bit LSB executable, statically linked ``` ### 替代方案:使用musl-cross 如果上述方法仍失败,可尝试musl-cross工具链: ```bash # 安装musl-cross git clone https://github.com/richfelker/musl-cross-make cd musl-cross-make make TARGET=x86_64-linux-musl install # 使用交叉编译 CC=x86_64-linux-musl-gcc ./configure --host=x86_64-linux-musl ``` ### 常见问题排查 1. **缺少静态库**: ```bash sudo apt install libssl-dev libffi-dev zlib1g-dev -y sudo apt install libssl-static libffi-static zlib-static -y ``` 2. **线程局部存储(TLS)冲突**: 在`configure`中添加: ```bash --with-tls=no \ ac_cv_thread_keyword=no ``` 3. **最终链接错误**: 在Makefile中强制使用静态链接: ```makefile LIBS = -Wl,-Bstatic -lcrypto -lssl -lffi -lz -Wl,-Bdynamic ``` > **提示**:完整静态编译会使Python二进制增大到25-40MB,但具有完全独立运行的优势[^1]。 --- ### 相关问题 1. 如何解决静态链接Python的"undefined reference to `dlopen'"错误? 2. Musl与glibc在静态链接的主要区别是什么? 3. 如何为静态编译的Python添加第三方C扩展模块? 4. 静态链接的Python二进制文件在哪些系统上可以运行? 5. 如何减小静态链接Python二进制文件的体积?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值