Коммит, где добавлял MASK, MATCH и INSN именно в riscv-gnu-toolchain/riscv-binutils перед установкой riscv-gnu-toolchain (о нём чуть позже пойдет речь) можно найти здесь:
https://github.com/MaxGrishenko/riscv-binutils-gdb/commit/d008e51a4bc5593c38d1023f6724b041128b1178
В качестве примера добавим AES: Round Instructions для RISC-V64
- aes64esm rd rs1 rs2
Round: ShiftRows, SubBytes, MixColumns - aes64es rd rs1 rs2
Round: ShiftRows, SubBytes - aes64dsm rd rs1 rs2
Round: InvShiftRows, InvSubBytes, InvMixColumn - aes64ds rd rs1 rs2
Round: InvShiftRows, InvSubBytes
Эти инструкции предназначены только для RISC-V64. Они реализуют SubBytes, ShiftRows и MixColumns преобразования AES. Каждая команда round принимает в качестве входных данных два 64-битных регистра, представляющих 128-битное состояние шифра AES и выводит один 64-битный результат, то есть половину следующего состояния round.
Для начала нам понадобится официальный git-репозиторий riscv-opcodes
$ git clone https://github.com/riscv/riscv-opcodes.git
В riscv-opcodes/ создадим текстовый файл opcodes-crypto со следующими опкод спецификациями для RISC-V
aes64esm rd rs1 rs2 31..25=7 14..12=2 6..0=0x2B
aes64es rd rs1 rs2 31..25=8 14..12=2 6..0=0x2B
aes64dsm rd rs1 rs2 31..25=9 14..12=2 6..0=0x2B
aes64ds rd rs1 rs2 31..25=10 14..12=2 6..0=0x2B
Их можно взять с официального git-репозитория https://github.com/riscv/riscv-crypto/blob/master/tools/opcodes-crypto-scalar
Также изменим riscv-opcodes/Makefile для генерации только необходимых нам MASK, MATCH и INSN для наших будущих crypto-команд
SHELL := /bin/sh
CRYPTO_H := ../encoding.h
CRYPTO_OPCODES := opcodes-crypto
$(CRYPTO_H): $(CRYPTO_OPCODES) parse_opcodes encoding.h
echo "/*" > $@
echo " * This file is auto-generated by running 'make $@' in" >> $@
echo " * https://github.com/riscv/riscv-opcodes (`git log -1 --format="format:%h"`)" >> $@
echo " */" >> $@
echo >> $@
cat encoding.h >> $@
cat $(CRYPTO_OPCODES) | python ./parse_opcodes -c >> $@
.PHONY : install
Теперь спокойно собираем riscv-opcodes
$ sudo make
После успешной сборки появляется ../encoding.h, содержащий необходимые MATCH, MASK и INSN
...
#define MATCH_AES64ESM 0xe00202b
#define MASK_AES64ESM 0xfe00707f
#define MATCH_AES64ES 0x1000202b
#define MASK_AES64ES 0xfe00707f
#define MATCH_AES64DSM 0x1200202b
#define MASK_AES64DSM 0xfe00707f
#define MATCH_AES64DS 0x1400202b
#define MASK_AES64DS 0xfe00707f
...
DECLARE_INSN(aes64esm, MATCH_AES64ESM, MASK_AES64ESM)
DECLARE_INSN(aes64es, MATCH_AES64ES, MASK_AES64ES)
DECLARE_INSN(aes64dsm, MATCH_AES64DSM, MASK_AES64DSM)
DECLARE_INSN(aes64ds, MATCH_AES64DS, MASK_AES64DS)
...
Они понадобятся чуть позже...
Теперь клонируем официальный git-репозиторий riscv-gnu-toolchain
$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
Переходим в riscv-gnu-toolchain/riscv-binutils/include/opcode/riscv-opc.h и по аналогии добавляем MATCH, MASK и INSN, которые сгенерировали ранее в ../encoding.h
Переходим в riscv-gnu-toolchain/riscv-binutils/opcodes/riscv-opc.c и по аналогии добавляем
{"aes64esm", 0, INSN_CLASS_C, "d,s,t", MATCH_AES64ESM, MASK_AES64ESM, match_opcode, 0 },
{"aes64es", 0, INSN_CLASS_C, "d,s,t", MATCH_AES64ES, MASK_AES64ES, match_opcode, 0 },
{"aes64dsm", 0, INSN_CLASS_C, "d,s,t", MATCH_AES64DSM, MASK_AES64DSM, match_opcode, 0 },
{"aes64ds", 0, INSN_CLASS_C, "d,s,t", MATCH_AES64DS, MASK_AES64DS, match_opcode, 0 },
Теперь надо собрать наш riscv-gnu-toolchain. Для этого могут понадобиться некоторые стандартные пакеты.
Для Ubuntu использовал
$ sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
Для других дистрибутивов нужные пакеты можно найти на git-репозитории https://github.com/riscv/riscv-gnu-toolchain
Укажем путь, и начнём сборку
$ ./configure --prefix=/opt/riscv
$ sudo make
По умолчанию используется RISC-V64 и Newlib cross-compiler
После успешной установки riscv-gnu-toolchain настроим пути
$ export PATH=/opt/riscv/bin:$PATH
Для самого простого теста создадим aes64esm-test.c
#include <stdio.h>
int main() {
uint64_t a = 1;
uint64_t b = 2;
uint64_t c;
asm volatile("aes64esm %[d], %[s], %[t]\n\t" : [d] "=r" (c) : [s] "r" (a), [t] "r" (b));
}
По аналогии протестируем и остальные команды: aes64ds, aes64es, aes64dsm
Теперь попробуем скомпилировать
$ riscv64-unknown-elf-gcc -o aes64esm-obj aes64esm-test.c
Если нет ошибки "unrecognized opcode", то riscv-gnu-toolchain был собран правильно
Протестируем через object dump то, что инструкция была использована
$ riscv64-unknown-elf-objdump -dC aes64esm-obj > aes64esm.dump
$ grep aes64esm aes64esm.dump
10164: oee7a7ab aes64esm a5,a5,a4