实验环境:MacOS 64位
- % uname -a
- Darwin MacBook-Pro.local 21.3.0 Darwin Kernel Version 21.3.0: Wed Jan 5 21:37:58 PST 2022; root:xnu-8019.80.24~20/RELEASE_ARM64_T8101 arm64
gcc版本
- % gcc -v
- Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/usr/include/c++/4.2.1
- Apple clang version 13.0.0 (clang-1300.0.27.3)
- Target: arm64-apple-darwin21.3.0
- Thread model: posix
- InstalledDir: /Library/Developer/CommandLineTools/usr/bin
在官网下载Miracl密码库源码,github上有Miracl的SDK源码。
1、根据linux64描述,将mirdef.h64 mirdef.h mrcore.c等文件全部拷贝一份到一个单独的文件目录下,这个文件目录将用于生成对应的静态库文件。
2、在新建的文件目录下,新建Makefile文件,用于管理所有的文件。(Makefile的应用参考上一篇案例)
从第一个文件mrcore.c 开始测试,Makefil文件如下
- #生成 MIRACL 密码库的静态库
- #操作环境:MacOS 64位
-
- #ar 维护链接编辑器使用的索引库
- #-c 屏蔽库创建时的正确消息提示
- #-r 替换已经存在的文件
- miracl.a : mrcore.o
- ar -cr miracl.a mrcore.o
-
- #-c 表示编译并生成目标文件
- #-m64 表示程序的宿主机器cpu架构是amd64
- #-O0 表示没有优化, -O1 为默认值,-O3 优化级别最高
- mrcore.o : mrcore.c
- gcc -c -o -m64 mrcore.o mrcore.c
-
- clean :
- rm -f *.o *.a
用make命令执行Makefile文件,出现如下错误提示
- % make
- gcc -c -o -m64 mrcore.o mrcore.c
- clang: error: no such file or directory: 'mrcore.o'
- make: *** [mrcore.o] Error 1
这是由于-m64不能被系统检测,为此,我们先去掉参数-m64。再次编译
- % make
- gcc -c -o mrcore.o mrcore.c
- In file included from mrcore.c:45:
- ./miracl.h:303:31: error: expected ';' after top level declarator
- typedef unsigned mr_dltype mr_large;
出现非常多的错误,首先指出
typedef unsigned mr_dltype mr_large;
按照定义,这本身是没有问题的,mr_dltype本身就是一个声明类型,导致这个错误的原因,肯定是没有声明mr_dltype。所以定义unsigned mr_dltype的别名为mr_large,是不可能的,后面还有很多关于mr_large的错误。现在需要知道mr_dltype在哪里定义?
在mirdef.h有对mr_dltype的定义,虽然miracl.h有对mirdef.h的包含,但是依然没有起作用。
- #include "mirdef.h"
- #define mr_dltype __int64
问题应该出在__int64的定义上,__int64为long long for Unix/Linux。
__int64为微软MSVC定义的数据类型,long long为C99定义的数据类型。
写一小段程序测试
- #include
-
- typedef long long __int64;
-
- int main(){
-
- __int64 a;
- printf("%lu\n", sizeof(a));//8
- //-9223372036854775808~+9223372036854775807
- printf("%lu\n", sizeof(long));//8
- printf("%lu\n", sizeof(long long));//8
- printf("%lu\n", sizeof(int));//4
- a = 9223372036854775806;
- printf("%lld\n", a);
-
- return 0;
- }
在本系统上,long类型和long long类型,都是8字节大小,所能够表示的数据范围为-9223372036854775808~+9223372036854775807
而且,在本系统上,long long类型是可用的。
现在,修改mirdef.h中关于__int64的定义
- // #define mr_dltype __int64 /* ... or long long for Unix/Linux */
- // #define mr_unsign64 unsigned __int64
- #define mr_dltype long long
- #define mr_unsign64 unsigned long long
在MacOS arm64上编译,与数据类型__int64相关,而__int64类型的原本定义是long long类型,在arm64上是支持的。
修改完成之后,再次用make编译,是可以成功编译的。
现在将其他的.c文件全部编译到静态库文件中。
- mrbuild.c mrflsh3.c mrmuldv.c mrsmall.c
- miracl.h mrcore.c mrflsh4.c mrsroot.c
- mirdef.h mrcrt.c mrfpe.c mrpi.c mrstrong.c
- mrcurve.c mrfrnd.c mrpower.c mrxgcd.c
- mraes.c mrdouble.c mrgcd.c mrprime.c mrzzn2.c
- mralloc.c mrebrick.c mrgcm.c mrrand.c mrzzn2b.c
- mrarth0.c mrec2m.c mrgf2m.c mrround.c mrzzn3.c
- mrarth1.c mrecn2.c mrio1.c mrscrt.c mrzzn4.c
- mrarth2.c mrfast.c mrio2.c mrsha3.c
- mrarth3.c mrflash.c mrjack.c mrshs.c
- mrbits.c mrflsh1.c mrlucas.c mrshs256.c
- mrbrick.c mrflsh2.c mrmonty.c mrshs512.c
问题又来了,在编译mrmuldv.c的时候,出现了这样的错误提示
error: use of undeclared identifier '_asm'
原因在于,gcc支持asm,但是不支持_asm,所以将mrmuldv.c对应的定义修改
- // #define ASM _asm
- #define ASM asm
现在出现新的错误
- error: expected 'volatile', 'inline', 'goto', or '('
- ASM mov eax,DWORD PTR a
到这里出现错误,属于汇编部分内容了。先不忙着去学习汇编,再次阅读文档发现,在mrmuldv.any中给出了各种环境的可能文件,例如选择mrmuldv.g64wen j文件,将mrmuldv.g64修改为mrmuldv.c,然后编译,将出现类似下面的错误。
- error: unknown register name 'rax' in asm
- : "rax","rbx","memory"
很明显,这是由于系统环境所导致的。如果选择mrmuldv.ccc,然后将mrmuldv.ccc修改为mrmuldv.c,再次编译应该不会出现上述问题了。
编译过程中,可能遇到的问题,可以参考GitHub上的问题解决。
https://github.com/miracl/MIRACL/issues/4
3、测试编译好的静态库
根据linux64的指导,测试ecsgen,同样的,利用Makefile管理项目。
- % ls
- Makefile big.o ecn.o miracl.a
- big.cpp ecn.cpp ecsgen.cpp miracl.h
- big.h ecn.h ecsgen.o mirdef.h
将第二步生成的静态库放在我们的项目中,并添加上面的文件。
- # 测试 ecsgen.cpp
-
- ecsgen : big.o miracl.a ecsgen.o ecn.o
- gcc -o ecsgen big.o miracl.a ecsgen.o ecn.o
-
- big.o : big.cpp
- gcc -c -o big.o big.cpp
-
- ecn.o : ecn.cpp
- gcc -c -o ecn.o ecn.cpp
-
- ecsgen.o : ecsgen.cpp
- gcc -c -o ecsgen.o ecsgen.cpp
-
- clean :
- rm -f *.o ecsgen
- Makefile中,我们还是用gcc来编译,却发生了下面的错误。
- Undefined symbols for architecture arm64:
- "std::__1::locale::use_facet(std::__1::locale::id&) const", referenced from:
- std::__1::ctype
const& std::__1::use_facet::__1::ctype >(std::__1::locale const&) in big.o - std::__1::ctype
const& std::__1::use_facet::__1::ctype >(std::__1::locale const&) in ecsgen.o - ...
在linux64的指导里面,用的是g++编译,gcc和g++是两个不同版本,查看版本,发现两者完全相同。
- % g++ -v
- Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX12.3.sdk/usr/include/c++/4.2.1
- Apple clang version 13.0.0 (clang-1300.0.27.3)
- Target: arm64-apple-darwin21.3.0
- Thread model: posix
- InstalledDir: /Library/Developer/CommandLineTools/usr/bin
为什么用gcc编译报错呢?
gcc是GNU开发的针对c的编译器,刚开始只支持编译c代码,随着gcc的发展愈发强大,后面gcc也支持编译c++、Objective-c和java等,在编译时需要通过设定参数指定编译的语言。所以后来,gcc默认编译的是c代码。把参数给用户设置显然没有那么友好,于是就专门针对c++ 开发了g++编译器。所以gcc是一个编译器集合,而g++是针对c++的编译器。因此,想要使用gcc编译c++的代码需要加上参数 -lstdc++ 指令即可。
- # 测试 ecsgen.cpp
-
- ecsgen : big.o miracl.a ecsgen.o ecn.o
- gcc -lstdc++ -o ecsgen big.o miracl.a ecsgen.o ecn.o
-
- big.o : big.cpp
- gcc -c -lstdc++ -o big.o big.cpp
-
- ecn.o : ecn.cpp
- gcc -c -lstdc++ -o ecn.o ecn.cpp
-
- ecsgen.o : ecsgen.cpp
- gcc -c -lstdc++ -o ecsgen.o ecsgen.cpp
-
- clean :
- rm -f *.o ecsgen
或者用g++编译,也是OK的。
很不幸,虽然能够正确编译了,但是在测试的时候,还是出现了下面的错误
- % ./ecsgen
- Enter 9 digit random number seed = 223434554
-
- MIRACL error from routine prepare_monty
- called from ecurve_init
- called from your program
- Illegal modulus
这必然是由于ecurve函数调用失败导致的,而导致这个错误的原因,就是因为没有添加common.ecs文件,将这个文件包含进项目,再次测试,就能够得到正确结果。
- % ./ecsgen
- Enter 9 digit random number seed = 323476589
- public key = 1 2900869870175004805769700703614563858361603331260179292807
最后,测试项目中包含的文件如下
- % ls
- Makefile common.ecs ecsgen miracl.h public.ecs
- big.cpp ecn.cpp ecsgen.cpp mirdef.h
- big.h ecn.h miracl.a private.ecs
4、Miracl库是一个非常强大的密码库,在构建这个项目的时候,最重要的是要生成SDK,这个过程就是生成静态库的过程,常常会遇到很多问题。
主要问题就是环境因素,在mrmuldv.any中给出了一系列的可能环境,根据自己的机器环境,选择不同的环境代码,才能够得到自己的静态库。我想这也是为什么没有给出一个固定的SDK的原因吧,毕竟每个人的应用环境是不同的。但是,不得不说,这个SDK的搭建,确实存在很大的挑战。所以,小编用Makefile来管理所有文件,希望读者在应用的时候,能够轻松掌握。
更多内容,欢迎关注公众号了解。