实验环境: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 <stdio.h>
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<char> const& std::__1::use_facet<std::__1::ctype<char> >(std::__1::locale const&) in big.o
std::__1::ctype<char> const& std::__1::use_facet<std::__1::ctype<char> >(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来管理所有文件,希望读者在应用的时候,能够轻松掌握。
更多内容,欢迎关注公众号了解。