【a64 vs x64】用汇编语言编程实现256位无符号整数乘法(上)

a64汇编语言是armv8架构64位汇编语言的缩写,更多的时候被称为Aarch64汇编语言。几年用x64汇编语言实现了256位、384位和521位无符号整数乘法,最近弄了个树莓派4b当玩具,学了三天a64汇编语言,就用a64编程实现了256位无符号整数乘法。老实讲,这个事情并不算什么蛋疼无聊之举,然而可供吐槽之处仍旧远超程序代码本身。

用64位汇编语言编写256位无符号整数乘法非常简单,简单到比C语言还要简单的程度,无论是a64还是x64。编写对应的测试代码(C程序)才是更加需要上心的事情。然后,请对程序运行结果疯狂吐槽吧。

首先是头文件,如果是x64平台,命名为ecc-x64.h,如果是Aarch64平台,则命名为ecc-a64.h,其内容完全相同,就是一条函数声明:

uint64_t mp_mul_256(uint64_t c[8], uint64_t a[4], uint64_t b[4]);

然后是测试自编函数的测试程序,命名为mp_test.c,除了引用上述头文件的文件名不同之外,其它内容完全相同:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <stdint.h>
#include "ecc-a64.h"//when Aarch64
#include "ecc-x64.h"//when x86_64

void hex_out(uint64_t data[], uint64_t size)
{
        uint64_t        i;
        for(i = 0; i < size; i++) fprintf(stdout, "%016lx", data[size - i - 1]);
}

int main(int argc, char *argv[])
{
        uint64_t        c[8], a[4], b[4];
        uint64_t        i, j;

        //init
        a[3] = 0x32C4AE2C1F198119;
        a[2] = 0x5F9904466A39C994;
        a[1] = 0x8FE30BBFF2660BE1;
        a[0] = 0x715A4589334C74C7;
        b[3] = 0xBC3736A2F4F6779C;
        b[2] = 0x59BDCEE36B692153;
        b[1] = 0xD0A9877CC62A4740;
        b[0] = 0x02DF32E52139F0A0;

        //process
        j = 0x8000000;
        for(i = 0; i < j; i++) mp_mul_256(c, a, b);

        //output
        hex_out(c, 8);

        exit(EXIT_SUCCESS);
}

只测自己编写的实现代码纯属自嗨,所以还得拉大旗做虎皮,而且得是两只老虎,一个是libGMP,命名为 mpz_test.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#include <gmp.h>

int main(int argc, char *argv[])
{
        mpz_t   a, b, c;
        int     i = 0;

        //init
        mpz_init2(a, 256);
        mpz_init2(b, 256);
        mpz_init2(c, 512);

        //input
        mpz_init_set_str(a, "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
        mpz_init_set_str(b, "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);

        //process
        for(i = 0; i < 0x8000000; i++) mpz_mul(c, a, b);

        //output
        mpz_out_str(stdout, 16, c); fprintf(stdout, "\n");

        //free
        mpz_clear(c);
        mpz_clear(b);
        mpz_clear(a);

        exit(EXIT_SUCCESS);
}

另一个就是OpenSSL,命名为 bn_test.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#include <openssl/bn.h>

char *Gx = "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7";
char *Gy = "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0";

int main(int argc, char *argv[])
{
        BIGNUM  *a, *b, *c;
        BN_CTX  *ctx;
        char    *hex = NULL;
        int     i = 0;

        //init
        a = BN_new();
        b = BN_new();
        c = BN_new();
        ctx = BN_CTX_new();

        //input
        BN_hex2bn(&a, Gx);
        BN_hex2bn(&b, Gy);

        //process
        for(i = 0; i < 0x8000000; i++) BN_mul(c, a, b, ctx);//c = a * b

        //output
        hex = BN_bn2hex(c);
        fprintf(stdout, "%s\r\n", hex);
        OPENSSL_free(hex);

        //free
        BN_free(a);
        BN_free(b);
        BN_free(c);
        BN_CTX_free(ctx);

        exit(EXIT_SUCCESS);
}

这三个测试程序干得都是同一件事情:给定两个256位无符号整数,计算其乘积0x8000000次,输出作为结果的512位无符号整数。测试者需要记录对比两种平台各个测试程序的运行耗时,对测试总体结果做出主观评价。

喵喵喵,我是不是忘了什么?对了,Makefile差点忘了贴出来,两个平台的Makefile是一模一样的

all: *.c *.s *.h
        gcc -Wall -O2 mp_test.c *.s -o mp_test
        gcc -Wall -O2 -lgmp mpz_test.c -o mpz_test
        gcc -Wall -O2 -lcrypto bn_test.c -o bn_test

clean:
        rm -f mp_test mpz_test bn_test

汇编语言是最美的编程语言,我猜读者一定赞同我的伟大看法,迫不及待地阅读我编写的函数mp_mul_256(c, a, b)的完整源代码了,相信我,阅读双平台汇编语言程序代码有益于睡眠,如果配合《线性代数》和《基础数论》这两本睡前读物,那真的就一觉睡到大天亮了。为了不让阅读本文的读者昏昏欲睡,我决定将完整汇编代码放在【a64 vs x64】用汇编语言编程实现256位无符号整数乘法(中),那里面除了代码真的啥都没有。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章