GNU toolchain(GNU工具链)是一个包含了由GNU项目所产生的各种编程工具的集合。这些工具形成了一条工具链(串行使用的一组工具),用于开发应用程序和操作系统。riscv-gnu-toolchain与普通gnu-toolchain基本相同,支持riscv32/64位指令集架构。
本文将在Ubuntu-22.04-LTS上编译riscv-gnu-toolchain
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install autotools-dev
sudo apt-get install curl
sudo apt-get install python3
sudo apt-get install libmpc-dev
sudo apt-get install libmpfr-dev
sudo apt-get install libgmp-dev
sudo apt-get install gawk
sudo apt-get install build-essential
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install texinfo
sudo apt-get install gperf
sudo apt-get install libtool
sudo apt-get install patchutils
sudo apt-get install bc
sudo apt-get install zlib1g-dev
sudo apt-get install libexpat-dev
sudo apt-get install libnewlib-dev
sudo apt-get install device-tree-compiler
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git submodule update --init #递归下载子模块
整个工具链主要包括以下模块:
子模组路径 'glibc':检出 '9826b03b747b841f5fc6de2054bf1ef3f5c4bdf3'
子模组路径 'musl':检出 '85e0e3519655220688e757b9d5bfd314923548bd'
子模组路径 'newlib':检出 '415fdd4279b85eeec9d54775ce13c5c412451e08'
子模组路径 'pk':检出 '2efabd3e6604b8a9e8f70baf52f57696680c7855'
子模组路径 'qemu':检出 '823a3f11fb8f04c3c3cc0f95f968fef1bfc6534f'
子模组路径 'riscv-binutils':检出 '20756b0fbe065a84710aa38f2457563b57546440'
子模组路径 'riscv-dejagnu':检出 '4ea498a8e1fafeb568530d84db1880066478c86b'
子模组路径 'riscv-gcc':检出 '5964b5cd72721186ea2195a7be8d40cfe6554023'
子模组路径 'riscv-gdb':检出 '5da071ef0965b8054310d8dde9975037b0467311'
子模组路径 'spike':检出 'a0298a33e7b2091ba8d9f3a20838d96dc1164cac'
此时不要关闭终端。在图形界面进入riscv-gnu-toolchain文件夹,检查子模块的文件夹是否为空。
1、下载失败
可以选择科学上网,也可选择重试大法。或者选择别的时间点进行下载,亲测北京时间凌晨3点至4点的下载速度很快。
2、提示下载完成,本地文件夹中却显示此文件夹为空
此时不要关闭终端,在riscv-gnu-toolchain文件夹下删除为空的子文件夹,在终端中重新执行git submodule update --init 命令即可。
sudo mkdir /opt/RISCV/riscv64
sudo chmod -R 777 /opt/RISCV/riscv64
sudo vim ~/.bashrc
export RISCV="/opt/RISCV/riscv64" #工具链的安装链接路径
export PATH=$PATH:$RISCV/bin
source ~/.bashrc #使此设置永久有效,不然每次打开终端都需要重新设置
riscv-gnu-toolchain可以编译为以下版本:
以
riscv64-unknown-linux-gnu
为前缀表示该版本的工具链是64位架构的Linux版本工具链。注意:此linux不是指当前版本工具链一定要运行在linux操作系统的电脑上,而是是指该GCC工具链会使用Linux的Glibc作为C运行库。
同理,riscv32-unknown-linux-gnu
前缀的版本则是32位架构。
以riscv64-unknown-elf
为前缀表示该版本为非linux(Non-linux)版本的工具链。注意:此Non-Linux不是指当前版本工具链一定不能运行在Linux操作系统的电脑上,而是指该GCC工具链会使用newlib作为C运行库。
同理,riscv32-unknown-elf
前缀的版本则是32位架构。
以riscv64-multilib-elf
为前缀表示该版本为同时支持32位和64位的裸机编译工具链。
以riscv64-linux-multilib
为前缀表示该版本为同时支持32位和64位的linux版本编译工具链。
以riscv-none-embed
为前缀版本表示是最新为裸机(bare-metal)嵌入式系统而生成的交叉编译工具链,所谓裸机(bare-metal)是嵌入式领域的一个常见形态,表示不运行操作系统的系统。该版本使用新版本的newlib作为C运行库,并且支持newlib-nano,能够为嵌入式系统生成更加优化的代码体积(Code Size)。
总结: riscv的gcc编译器,分为2大类:
non-embed
编译器,对于每一类,如果禁用multilib
,那么又分为32位版本和64位版本。如果使能multilib
,那么就只有一个版本,但是这个版本工具,可以同时支持32位和64位。cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv64 --with-arch=rv32imc --with-abi=xxx
sudo make -jN
cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv64 --with-arch=rv64imc --with-abi=xxx
sudo make -jN
cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv32 --with-arch=rv64imc --with-abi=xxx --enable-linux
sudo make linux -jN
cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/RISCV/riscv64 --with-arch=rv64imafd --with-abi=lp64d --enable-linux --disable-multilib
sudo make linux -jN
编译multilib版本的gcc,可以同时支持32位和64位
cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/riscv64-multilib-elf --enable-multilib --target=riscv64-multilib-elf
sudo make -jN
对于riscv64-multilib-elf-gcc
编译器,可以通过以下选项,来决定生成的程序是32位版本还是64位版本:
-march=rv32 : 32位版本
-march=rv64 : 64位版本
cd riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=/opt/riscv-linux-multilib --enable-multilib --target=riscv64-linux-multilib
sudo make -jN
对于riscv64-linux-multilib-gcc
编译器,可以通过以下选项,来决定生成的程序是32位版本还是64位版本:
-march=rv32 : 32位版本
-march=rv64 : 64位版本
专门为嵌入式使用的gcc交叉编译工具链。官方网站:https://gnu-mcu-eclipse.github.io/toolchain/riscv/
可以直接下载linux的二进制执行程序,以及windows的安装包。这个一般要搭配GNU MCU eclipse工具一起使用。
因为这个工具,直接提供可执行程序,因此就不介绍了。
RISCV指令集采用模块化设计,用户可按需选择指令集。其中基本整数指令集为唯一强制要求实现的指令集。
基本指令集 | 指令数 | 描述 |
---|---|---|
RV32I | 47 | 32位整数指令集,包含算术、分支、访存指令,32位寻址空间,32个32位寄存器 |
RV32E | 47 | RV32I的子集,用于小型的嵌入式场景,16个32位寄存器 |
RV64I | 59 | 64位整数指令集,兼容RV32I,64位寻址空间,32个64位寄存器 |
RV128I | 71 | 128位整数指令集,兼容RV32I和RV64I,128位寻址空间,32个128位寄存器 |
拓展指令集 | 指令数 | 描述 |
---|---|---|
M | 8 | 乘法(Multiplication)指令集和除法指令集,包括4条乘法、2条除法、2条余数操作指令 |
A | 11 | 存储原子(Automic)指令集,包含原子操作指令,如读-修改-写、比较-交换等 |
F | 26 | 单精度浮点(Float,32bit)指令集 |
D | 26 | 双精度浮点(Double,64bit)指令集,兼容F |
C | 26 | 压缩(Compresses)指令集,指令长度变为16位,目的是减少代码大小 |
【注:特定组合“IMAFD”被称为“通用(General)”组合,用字母G表示】
其他的扩展指令集还包括:
- “B”标准扩展:位操作
- “E”标准扩展:嵌入式
- “H”特权态架构扩展:支持管理程序(Hypervisor)
- “J”标准扩展:动态翻译语言
- “L”标准扩展:十进制浮点
- “N”标准扩展:用户态中断
- “P”标准扩展:封装的单指令多数据(Packed-SIMD)指令
- “Q”标准扩展:四精度浮点
数据类型的大小、布局和对齐;
调用约定(控制着函数的参数如何传送以及如何接受返回值),例如,是所有的参数都通过栈传递,还是部分参数通过寄存器传递;哪个寄存器用于哪个函数参数;通过栈传递的第一个函数参数是最先push到栈上还是最后;
系统调用的编码和一个应用如何向操作系统进行系统调用; 一个完整的操作系统ABI中,目标文件的二进制格式、程序库等等
i即int
,l即long
,p即pointer
(指针),32/64指前面给出的类型是32位还是64位;
f即float
,指float
型浮点数参数通过浮点数寄存器传递
d即double
,指float
型和double
型浮点数参数通过浮点数寄存器传递
数据模型 | int字长 | long字长 | 指针字长 |
---|---|---|---|
ilp32 / ilp32f / ilp32d | 32bit | 32bit | 32bit |
lp64 / lp64f / lp64d | 32bit | 64bit | 64bit |
是否需要浮点扩展指令 | float参数 | double参数 | |
---|---|---|---|
ilp32 / lp64 | 不需要 | 通过整数寄存器(a0~a1)传递 | 通过整数寄存器(a0~a3)传递 |
ilp32f / lp64f | 需要F扩展 | 通过浮点寄存器(fa0~fa1)传递 | 通过整数寄存器(a0~a3)传递 |
ilp32d / lp64d | 需要F扩展和D扩展 | 通过浮点寄存器(fa0~fa1)传递 | 通过浮点寄存器(fa0~fa1)传递 |
浮点参数传递规则只与 --mabi
选项有关,与--march
选项没有直接关系。但是部分--mabi
选项需要浮点寄存器,浮点寄存器是通过浮点扩展指令引入的,这就需要在--march
选项中指定浮点扩展。
../configure --help
查看riscv64-unknown-linux-gnu-gcc -v
出现如下信息则表示安装成功
Using built-in specs.
COLLECT_GCC=riscv64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/RISCV/riscv64/libexec/gcc/riscv64-unknown-linux-gnu/11.1.0/lto-wrapper
Target: riscv64-unknown-linux-gnu
Configured with: /home/lihua/riscv-gnu-toolchain/build/../riscv-gcc/configure --target=riscv64-unknown-linux-gnu --prefix=/opt/RISCV/riscv64 --with-sysroot=/opt/RISCV/riscv64/sysroot --with-pkgversion=g --with-system-zlib --enable-shared --enable-tls --enable-languages=c,c++,fortran --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libsanitizer --disable-nls --disable-bootstrap --src=../../riscv-gcc --disable-multilib --with-abi=lp64d --with-arch=rv64imafd --with-tune=rocket --with-isa-spec=2.2 'CFLAGS_FOR_TARGET=-O2 -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-O2 -mcmodel=medlow'
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.1.0 (g)
进入spike目录下
cd spike
mkdir build
cd build
../configure --prefix=$RISCV
make
[sudo] make install #sudo为可选项
进入pk目录下
cd pk
mkdir build
cd build
../configure --prefix=$RISCV --host=riscv64-unknown-linux-gnu
make
make install
其中–host选项要为与之前构建的交叉编译器相匹配,如果之前构建的交叉编译器为riscv64-unknown-elf-gcc
,则该项应设置为riscv64-unknown-elf
。默认情况下将生成64位的可执行程序,如果想要生成32位可执行程序,请在configure后面添加--with-arch=rv32i
编写一个测试程序
#include<stdio.h>
void main(){
printf("hello world!\n");
}
使用riscv64-unknown-linux-gnu-gcc
编译:
riscv64-unknown-linux-gnu-gcc -o hello hello.c -static
使用spike
执行可执行文件:
spike pk hello
当屏幕上出现hello world
时,则说明全套工具安装成功。
当安装有多个版本的pk
时,执行命令spike pk
会报如下错误:
terminate called after throwing an instance of 'std::runtime_error'
what(): could not open pk (did you misspell it? If VCS, did you forget +permissive/+permissive-off?)
此时则需要我们指定pk
的绝对路径:
spike /opt/RISCV/riscv64/bin/pk hello