参考修改:https://github.com/tbuktu/libntru/pull/47/files 该仓库是纯C代码,构建工具是make. 但是代码直接下下来是无法编译通过的,它在poly.h中定义了多个函数指针,然后在poly.c中根据平台架构等区分给这几个函数指针不同的实现。
例如
// poly.h
uint8_t (*ntru_invert)(NtruPrivPoly *a, uint16_t mod_mask, NtruIntPoly *Fq);
// poly.c
void ntru_set_optimized_impl_poly() {
...
if (sizeof(void*) >= 8) /* 64-bit arch */
ntru_invert = ntru_invert_64;
else
ntru_invert = ntru_invert_32;
...
#if _LP64
ntru_invert = ntru_invert_64;
#else
ntru_invert = ntru_invert_32;
#endif
这样如果多个源文件包含poly.h,必然会存在重复定义的问题,违反ODR(one-definition-rule)。而解决方法首先想到在poly.h中为符号加上extern,改定义为声明。然后这样一来,引发的效果还是符号未定义。
$ gcc poly.c -c -o poly.o
$ nm poly.o | grep ntru_invert
U ntru_invert
0000000000005228 T ntru_invert_32
0000000000005bc9 T ntru_invert_64
该项目将函数指针的初始化放在一个init函数里,要求使用者先调用init函数,可这样导致其他依赖这个库的文件编译错误,报错找不到这个符号的定义。
而修改的方案也很简单,只需要在poly.c中再定义一次这个符号,那么该符号就变成了为初始化的全局数据(B)。
// poly.c
// 补一个定义即可
uint8_t (*ntru_invert)(NtruPrivPoly *a, uint16_t mod_mask, NtruIntPoly *Fq);
...
void ntru_set_optimized_impl_poly() {
...
if (sizeof(void*) >= 8) /* 64-bit arch */
ntru_invert = ntru_invert_64;
else
ntru_invert = ntru_invert_32;
...
#if _LP64
ntru_invert = ntru_invert_64;
#else
ntru_invert = ntru_invert_32;
#endif
$ nm poly.o | grep ntru_invert
0000000000000000 B ntru_invert
00000000000041f0 T ntru_invert_32
0000000000003b70 T ntru_invert_64
这样符号至少有定义,但未初始化。其他依赖单元编译时就不会报错。
参考PR:https://github.com/tbuktu/libntru/pull/47/files
这个项目还牵扯出一个问题,就是编译出的可执行文件在运行时报错,找不到编出来的动态库:
$ ./testham
./testham: error while loading shared libraries: libntru.so: cannot open shared object file: No such file or directory
$ ldd testham 127 19:44
linux-vdso.so.1 (0x00007ac6eec8a000)
libntru.so => not found
libm.so.6 => /usr/lib/libm.so.6 (0x00007ac6eeb5a000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ac6ee969000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007ac6eec8c000)
$ ls
changelog LICENSE Makefile.bsd Makefile.os2 Makefile.win README.md testham*
libntru.so* Makefile Makefile.linux Makefile.osx PATENTS src/ tests/
可见不会搜索当前目录,此时需要给链接器传额外参数,让他搜索当前目录,在makefile里加上
CFLAGS+=-Wl,-rpath,./
即可,参考:
$ ldd testham
linux-vdso.so.1 (0x000079365271f000)
libntru.so => ./libntru.so (0x00007936526d7000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007936525b9000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007936523c8000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x0000793652721000)
$ ./testham
Running tests...
test_ntruprime_inv_int ✓
test_ntruprime_inv_poly ✓
test_mult_int ✓
test_mult_tern ✓
test_mult_prod ✓
test_inv ✓
test_arr ✓
test_ntruprime_keygen ✓
test_ntru_keygen ✓
test_encr_decr ✓
test_idxgen ✓
test_bitstring ✓
test_key ✓
test_hash ✓
All tests passed
NM命令参考