赞
踩
在工作过程中,编译并使用libgnutls.a静态库时出现如下报错:
./lib/libs/libgnutls.a(provable-prime.o): In function `st_provale_prime_small`:
/root/gnutls-3.6.4/lib/nettle/int/provable-prime.c:1026: undefined reference to `mpz_init`
……
问题现象为:没有 mpz_init()
接口的定义,即链接时没有找到这个符号的定义。
mpz_init
格式$ nm -A ./libgnutls.a | grep mpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:dsa-keygen-fips186.o: Umpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:dsa-validate.o: Umpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:lt18-mpi.o: Umpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:lt19-pk.o: Umpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:provable-prime.o: Umpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:rsa-keygen-fips186.o: Umpz_init
mpz_init
$ nm -A /usr/lib/x86_64-linux-gnu/libgmp.a | grep mpz_init
/usr/lib/x86_64-linux-gnu/libgmp.a:bin_ui.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgmp.a:bin_ui.o: U__gmpz_init_set_ui
/usr/lib/x86_64-linux-gnu/libgmp.a:mfac_uiui.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgmp.a:lt22-init.o:0000000000000000 T__gmpz_init
/usr/lib/x86_64-linux-gnu/libgmp.a:lt23-init2.o:0000000000000000 T__gmpz_init2
/usr/lib/x86_64-linux-gnu/libgmp.a:lt24-inits.o:0000000000000000 T__gmpz_inits
/usr/lib/x86_64-linux-gnu/libgmp.a:lt26-iset.o:0000000000000000 T__gmpz_init_set
/usr/lib/x86_64-linux-gnu/libgmp.a:lt27-iset_d.o:0000000000000000 T__gmpz_init_set_d
/usr/lib/x86_64-linux-gnu/libgmp.a:lt28-iset_si.o:0000000000000000 T__gmpz_init_set_si
/usr/lib/x86_64-linux-gnu/libgmp.a:lt29-iset_str.o:0000000000000000 T__gmpz_init_set_str
/usr/lib/x86_64-linux-gnu/libgmp.a:lt30-iset_ui.o:0000000000000000 T__gmpz_init_set_ui
/usr/lib/x86_64-linux-gnu/libgmp.a:remove.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgmp.a:remove.o: U__gmpz_init_set
/usr/lib/x86_64-linux-gnu/libgmp.a:randlc2s.o: U__gmpz_init_set_str
/usr/lib/x86_64-linux-gnu/libgmp.a:randlc2x.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgmp.a:randlc2x.o: U__gmpz_init2
/usr/lib/x86_64-linux-gnu/libgmp.a:randlc2x.o: U__gmpz_init_set
/usr/lib/x86_64-linux-gnu/libgmp.a:randmts.o: U__gmpz_init2
/usr/lib/x86_64-linux-gnu/libgmp.a:randmts.o: U__gmpz_init_set
注意这一行:
/usr/lib/x86_64-linux-gnu/libgmp.a:lt22-init.o:0000000000000000 T __gmpz_init
根据上面的内容,可以确定libgmp.a
中,符号格式为__gmpz_init
。
问题原因初步可以确定:
请求的符号格式与 静态库提供的符号内容不一致,在链接的时候没有找到函数定义,从而编译失败了。
源文件/lib/nettle/int/provable-prime.c
包含头文件内容如下:
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <nettle/memxor.h>
#include <nettle/bignum.h> //注意这一行,该文件包含头文件 gmp.h
#include <dsa-fips.h>
#include <nettle/macros.h>
继续查看头文件 <nettle/bignum.h>
: /usr/include/nettle/bignum.h
#ifndef NETTLE_BIGNUM_H_INCLUDED #define NETTLE_BIGNUM_H_INCLUDED #include "nettle-meta.h" #include "nettle-types.h" /* For NETTLE_USE_MINI_GMP */ #include "version.h" #if NETTLE_USE_MINI_GMP # include "mini-gmp.h" // 注意该行 # define GMP_NUMB_MASK (~(mp_limb_t) 0) /* Function missing in older gmp versions, and checked for with ifdef */ # define mpz_limbs_read mpz_limbs_read /* Side-channel silent powm not available in mini-gmp. */ # define mpz_powm_sec mpz_powm #else # include <gmp.h> // 注意该行 #endif
头文件中通过宏开关NETTLE_USE_MINI_GMP
来指明包含哪个头文件。
mini-gmp.h
和 gmp.h
文件中 函数的声明mini-gmp.h
中内容摘取如下:
……
void mpz_init (mpz_t);
void mpz_init2 (mpz_t, mp_bitcnt_t);
……
gmp.h
中内容摘取如下:
……
#define mpz_init __gmpz_init
__GMP_DECLSPEC void mpz_init (mpz_ptr) __GMP_NOTHROW;
#define mpz_init2 __gmpz_init2
__GMP_DECLSPEC void mpz_init2 (mpz_ptr, mp_bitcnt_t);
……
当调用 gmp.h
头文件,在预编译阶段会将所用的 mpz_init
字段替换为 __gmpz_init
,结合第2步骤中查看的 libgmp.a
静态库符号表,可以确定 编译 libgmp时包含的头文件时gmp.h
。
根据上面内容进而可以判断出:
在编译
libgnutls.a
静态库时调用的头文件是mini-gmp.h
。
证明该结论可以在头文件/usr/include/nettle/bignum.h
添加error打印来确定:
…… /* For NETTLE_USE_MINI_GMP */ #include "version.h" #if NETTLE_USE_MINI_GMP # error "use mini-gmp.h" //添加的error打印 # include "mini-gmp.h" # define GMP_NUMB_MASK (~(mp_limb_t) 0) /* Function missing in older gmp versions, and checked for with ifdef */ # define mpz_limbs_read mpz_limbs_read /* Side-channel silent powm not available in mini-gmp. */ # define mpz_powm_sec mpz_powm #else # error "gmp.h" //添加的error打印 # include <gmp.h> #endif ……
重新编译libgnutls.a
,根据编译错误打印可以证明前面所述的结论成立。
临时解决方法:在头文件/usr/include/nettle/bignum.h
中,取消宏定义开关NETTLE_USE_MINI_GMP
,如下:
…… #undef NETTLE_USE_MINI_GMP // 取消宏定义开关 #if NETTLE_USE_MINI_GMP # include "mini-gmp.h" # define GMP_NUMB_MASK (~(mp_limb_t) 0) /* Function missing in older gmp versions, and checked for with ifdef */ # define mpz_limbs_read mpz_limbs_read /* Side-channel silent powm not available in mini-gmp. */ # define mpz_powm_sec mpz_powm #else # include <gmp.h> // 此时会包含该头文件 #endif
再次编译 libgnutls.a
静态库,编译好后查看静态库中需要的符号格式内容如下:
$ nm -A /usr/lib/x86_64-linux-gnu/libgnutls.a | grep mpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:dsa-keygen-fips186.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:dsa-validate.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:lt18-mpi.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:lt19-pk.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:provable-prime.o: U__gmpz_init
/usr/lib/x86_64-linux-gnu/libgnutls.a:rsa-keygen-fips186.o: U__gmpz_init
继续项目编译,问题解决
!
正规解决方法: 在编译 libnettle.a
静态库,在nettle项目中执行 命令:
./configure
时,添加选项参数 --enable-mini-gmp=no
, 重新编译 libgmp.a
,并重新安装 libgmp*(没有测试确认)*
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。