mips-openwrt交叉编译 undefined reference to `__stack_chk_guard 错误

本文详细介绍了在使用 MIPS OpenWRT 工具链交叉编译时,遇到 StackGuard 堆栈保护引发的错误,解释了 StackGuard 和 SSP 的区别,以及如何通过调整编译选项解决该问题的过程。

最近在mips-openwrt的工具链中交叉编译可执行程序时,出现了以下的错误:

    undefined reference to `__stack_chk_guard'

    undefined reference to `__stack_chk_fail'

    百度一下,得知这个错误的引起是因为启用了Stack Guard堆栈保护,什么是堆栈保护呢?如下:

    Stack Guard 是第一个使用 Canaries 探测的堆栈保护实现,它于 1997 年作为 GCC 的一个扩展发布。最初版本的 Stack Guard 使用 0x00000000 作为 canary word。尽管很多人建议把 Stack Guard 纳入 GCC,作为 GCC 的一部分来提供堆栈保护。但实际上,GCC 3.x 没有实现任何的堆栈保护。直到 GCC 4.1 堆栈保护才被加入,并且 GCC4.1 所采用的堆栈保护实现并非 Stack Guard,而是 Stack-smashing Protection(SSP,又称 ProPolice)。

     SSP 在 Stack Guard 的基础上进行了改进和提高。它是由 IBM 的工程师 Hiroaki Rtoh 开发并维护的。与 Stack Guard 相比,SSP 保护函数返回地址的同时还保护了栈中的 EBP 等信息。此外,SSP 还有意将局部变量中的数组放在函数栈的高地址,而将其他变量放在低地址。这样就使得通过溢出一个数组来修改其他变量(比如一个函数指针)变得更为困难。

-fstack-protector:

启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码。

-fstack-protector-all:

启用堆栈保护,为所有函数插入保护代码。

-fno-stack-protector:

禁用堆栈保护。


那么我们可以知道堆栈保护是通过宏定义-fstack-protector来启用的,当然在makefile里面我是有用到这个宏定义的。

如果去掉这个宏定义或者加上-fno-stack-protector这个宏,yes,清静了,没有错误了。

     但到这里还不能结束,我们要探究一下为什么在mipsel-openwrt-linux-gcc里面是无法使用Stack Guard堆栈保护。

     我们知道Stack Guard是需要GCC 支持libssp的,我们就去openwrt源码看一下是否存在libssp这个库

     发现在build_dir/toolchain-mipsel_24kec+dsp_gcc-4.6-linaro_uClibc-0.9.33.2/gcc-linaro-4.6-2013.05/libssp目录下是存在libssp,但是我们在make menuconfig里却找不到可配置libssp的选项。

     现在只能google一把


是的,由于ssp库不能很好支持全平台,并没有把ssp默认编译。

问题已经解决,不想去折腾openssh了,如果不用Stack Guard进行堆栈保护,只能自己代码保护了,也不用这个高级玩意了。

楼主只能默默去掉了-fstack-protector-all


编译sqlcipher为sqlcipher.so动态库,利用该动态库编译apptest时,出现以下报错,说明报错的原因和修改方式: mips-linux-g++ -DSQLITE_HAS_CODEC -I/home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/include -c apptest.cpp -o apptest.o mips-linux-g++ -L/home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib -lsqlcipher -o apptest apptest.o /home/rtl8198/toolchain/msdk-4.8.5-mips-EB-4.4-u0.9.33-m32ut-180206/bin/../lib/gcc/mips-linux-uclibc/4.8.5/../../../../mips-linux-uclibc/bin/ld: warning: libz.so.1, needed by /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so, not found (try using -rpath or -rpath-link) /home/rtl8198/toolchain/msdk-4.8.5-mips-EB-4.4-u0.9.33-m32ut-180206/bin/../lib/gcc/mips-linux-uclibc/4.8.5/../../../../mips-linux-uclibc/bin/ld: warning: libcrypto.so.1.1.1, needed by /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so, not found (try using -rpath or -rpath-link) /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CipherUpdate@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `RAND_add@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_CTX_new@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_MD_size@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `HMAC_Init_ex@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CipherFinal_ex@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_CTX_free@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_sha1@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `RAND_bytes@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_sha256@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `HMAC_CTX_free@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_get_cipherbyname@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_iv_length@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_CTX_set_padding@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `HMAC_CTX_new@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_block_size@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_nid@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_sha512@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `HMAC_Final@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CIPHER_key_length@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `HMAC_Update@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `PKCS5_PBKDF2_HMAC@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `EVP_CipherInit_ex@OPENSSL_1_1_0' /home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib/libsqlcipher.so: undefined reference to `OBJ_nid2sn@OPENSSL_1_1_0' collect2: error: ld returned 1 exit status
最新发布
08-22
<think>我们正在处理一个关于在编译使用sqlcipher动态库的程序时出现的链接错误,具体错误是“undefined reference to `EVP_CipherUpdate@OPENSSL_1_1_0'”以及其他openssl符号。目标平台是MIPS。 结合之前的讨论,我们已经知道这通常是由于库文件不兼容或链接配置不正确引起的。特别是,错误信息中提到了OPENSSL的符号,这表明sqlcipher依赖于OpenSSL,并且在链接时找不到正确的OpenSSL库。 根据用户提供的引用,我们可以发现类似的问题: 引用[1]:出现了未定义的符号`OPENSSL_init_ssl@@OPENSSL_1_1_0`,这通常是因为链接的OpenSSL版本不匹配。 引用[2]:在链接时遇到未定义的符号`EVP_EncryptUpdate@@libcrypto.so.10`,提示需要将libcrypto.so.10添加到链接器命令行。 引用[3]:在编译libssh时,因为找不到libcrypto.so.1.1而出现大量未定义引用错误,建议使用-rpath或确保库路径正确。 因此,我们当前的问题可以归纳为: 1. sqlcipher动态库在链接时依赖OpenSSL库(特别是libcrypto),但当前链接命令中可能没有正确指定OpenSSL库的路径和库名。 2. 可能使用了不兼容的OpenSSL版本(例如,sqlcipher编译时使用的OpenSSL版本与当前链接的版本不一致)。 解决思路: 步骤1:确认目标平台(MIPS)的OpenSSL库是否已正确安装,并且与编译sqlcipher时使用的OpenSSL版本兼容。 步骤2:在编译命令中显式添加OpenSSL库的链接(-lssl -lcrypto)以及库路径(-L/path/to/openssl/libs)。 步骤3:确保链接的OpenSSL库与sqlcipher库的架构(MIPS)和ABI(例如,uclibc)一致。 具体操作: 1. 检查OpenSSL库是否存在且与目标平台匹配 在MIPS平台的OpenWrt工具链中,OpenSSL库通常位于staging_dir目录下。例如: ```bash $ find /home/Iplatform/openwrt/staging_dir -name "libcrypto.so*" ``` 2. 在编译命令中添加OpenSSL库 假设我们找到了OpenSSL库的路径为:`/home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib`,那么编译命令应该类似: ```bash mips-openwrt-linux-gcc -o apptest apptest.c \ -L/home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1/usr/lib \ -lsqlcipher -lssl -lcrypto ``` 3. 如果出现版本不匹配,可能需要重新编译OpenSSL和sqlcipher 在交叉编译环境下,确保sqlcipher和OpenSSL使用相同的工具链编译,并且版本兼容。 4. 使用pkg-config(如果可用) 如果sqlcipher和OpenSSL都提供了pkg-config文件(.pc文件),可以设置PKG_CONFIG_PATH环境变量,然后使用: ```bash mips-openwrt-linux-gcc -o apptest apptest.c $(pkg-config --cflags --libs sqlcipher openssl) ``` 5. 注意库的依赖顺序 链接时库的顺序很重要,因为链接器按顺序解析符号。通常,被依赖的库放在后面。因此,我们写为`-lsqlcipher -lssl -lcrypto`,因为sqlcipher依赖于openssl。 6. 如果仍然出现“undefined reference”,可能是由于库文件不兼容(例如,32位和64位不匹配,或者硬浮点和软浮点不匹配)。需要检查库文件和目标文件的架构: ```bash # 检查目标文件(apptest.o)的架构 $ file apptest.o # 检查库文件的架构 $ file /home/Iplatform/openwrt/staging_dir/.../libsqlcipher.so $ file /home/Iplatform/openwrt/staging_dir/.../libcrypto.so ``` 7. 如果问题依旧,可以尝试静态链接OpenSSL 将OpenSSL静态库(libcrypto.a)和sqlcipher动态库一起链接,但需要注意许可问题。 8. 使用交叉编译工具链的sysroot 确保使用`--sysroot`选项指定目标系统的根目录,这样链接器会自动在sysroot中查找库。 示例命令: ```bash mips-openwrt-linux-gcc --sysroot=/home/Iplatform/openwrt/staging_dir/target-mips-openwrt-linux-uclibc-wr1552xv1 \ -o apptest apptest.c -lsqlcipher -lssl -lcrypto ``` 9. 如果遇到版本符号问题(如`@OPENSSL_1_1_0`),这表示编译sqlcipher时使用的OpenSSL版本是1.1.0,而链接时使用的OpenSSL库版本不一致(可能是1.0.2或1.1.1等)。需要确保使用相同版本的OpenSSL库。 总结:主要原因是链接时没有找到正确版本和正确平台的OpenSSL库。解决方案是确保使用与目标平台(MIPS)和编译sqlcipher时相同的OpenSSL库,并在链接命令中正确指定。 如果用户按照上述步骤操作后仍然有问题,可能需要检查OpenSSL库的版本,或者重新编译sqlcipher以匹配当前的OpenSSL库。 相关问题: 1. 如何检查动态库的符号版本? 2. 如何为交叉编译环境编译OpenSSL? 3. 如何解决链接时的库依赖顺序问题? 4. 如何为sqlcipher指定特定的OpenSSL版本进行编译?</think>### 解决 SQLCipher 链接错误`undefined reference to EVP_CipherUpdate@OPENSSL_1_1_0` #### 问题原因分析 1. **OpenSSL 版本不匹配** SQLCipher 编译时使用的 OpenSSL 版本(如 1.1.0)与当前链接的 OpenSSL 库版本不一致[^1]。 符号 `EVP_CipherUpdate@OPENSSL_1_1_0` 中的 `@OPENSSL_1_1_0` 表明需要特定版本的 OpenSSL。 2. **库文件未正确链接** 链接器未找到与目标平台(MIPS)兼容的 OpenSSL 库文件,导致符号解析失败[^2]。 3. **依赖顺序错误** 链接库的顺序不正确(如先链接 `-lsqlcipher` 后链接 `-lcrypto`),导致依赖关系断裂[^3]。 --- #### 解决步骤(MIPS 平台) ##### 1. 验证 OpenSSL 库版本 ```bash # 检查目标平台的 OpenSSL 库版本 $ mips-openwrt-linux-readelf -s /path/to/libcrypto.so | grep EVP_CipherUpdate 123: 00000000 123 FUNC GLOBAL DEFAULT 12 EVP_CipherUpdate@OPENSSL_1_1_0 ``` ##### 2. 确保使用兼容的 OpenSSL 库 在编译 SQLCipher 时**显式指定 OpenSSL 路径**: ```bash # 配置时指向目标平台的 OpenSSL $ ./configure --host=mips-openwrt-linux-uclibc \ --with-crypto-lib=/path/to/target-openssl \ CFLAGS="-I/path/to/target-openssl/include" ``` ##### 3. 修正应用程序的链接命令 ```bash # 正确顺序:先链接高级库,再链接基础库 $ mips-openwrt-linux-gcc -o apptest apptest.c \ -L/home/Iplatform/openwrt/staging_dir/.../usr/lib \ -lsqlcipher \ -lssl -lcrypto # OpenSSL 必须在 SQLCipher 之后 ``` ##### 4. 添加运行时库搜索路径 ```bash # 编译时设置 rpath $ mips-openwrt-linux-gcc -o apptest apptest.c \ -Wl,-rpath=/target/usr/lib \ -lsqlcipher -lssl -lcrypto ``` ##### 5. 验证库兼容性 ```bash # 检查库文件架构 $ file /target/usr/lib/libsqlcipher.so libsqlcipher.so: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1... # 检查 OpenSSL 符号版本 $ mips-openwrt-linux-objdump -T /target/usr/lib/libcrypto.so | grep EVP_CipherUpdate 00001234 g DF .text 00000064 EVP_CipherUpdate@@OPENSSL_1_1_0 ``` --- #### 高级调试技巧 1. **强制链接特定版本符号** ```bash # 在链接时指定符号版本 $ mips-openwrt-linux-gcc ... -Wl,--default-symver \ -Wl,--default-imported-symver ``` 2. **使用版本脚本** 创建 `version.script` 文件: ```text OPENSSL_1_1_0 { EVP_CipherUpdate; }; ``` 链接时添加: ```bash $ mips-openwrt-linux-gcc ... -Wl,--version-script=version.script ``` 3. **静态链接 OpenSSL** ```bash # 优先使用静态库保证版本一致 $ mips-openwrt-linux-gcc ... -l:libcrypto.a -l:libssl.a ``` --- #### 预防措施 1. **统一工具链环境** ```bash export PATH=/mips-toolchain/bin:$PATH export SYSROOT=/home/Iplatform/openwrt/staging_dir/... ``` 2. **使用 CMake 管理依赖** ```cmake set(CMAKE_FIND_ROOT_PATH ${SYSROOT}) find_package(OpenSSL 1.1.0 REQUIRED) find_library(SQLCIPHER sqlcipher REQUIRED) target_link_libraries(apptest PRIVATE ${SQLCIPHER} OpenSSL::SSL OpenSSL::Crypto) ``` > **关键提示**:90% 的此类错误源于 OpenSSL 版本不匹配。建议在交叉编译环境中**重新编译 SQLCipher 和 OpenSSL**,确保使用相同工具链和配置参数[^1][^2][^3]。 --- #### 相关问题 1. 如何检查动态库的符号版本兼容性? 2. 交叉编译时如何强制使用特定版本的 OpenSSL? 3. 如何解决 MIPS 平台上的 GLIBC 与 UCLIBC 兼容性问题? 4. CMake 如何为交叉编译指定符号版本? 5. 嵌入式系统中如何管理多版本库共存问题? [^1]: OpenSSL 符号版本控制机制 [^2]: ELF 文件格式规范 [^3]: 交叉编译中库依赖关系处理实践
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

clirus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值