首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >riscv gcc工具链是如何被编译的

riscv gcc工具链是如何被编译的

作者头像
bigmagic
发布于 2022-01-10 00:10:09
发布于 2022-01-10 00:10:09
2.3K00
代码可运行
举报
文章被收录于专栏:嵌入式iot嵌入式iot
运行总次数:0
代码可运行

riscv gcc工具链是如何被编译的

  • 概述
  • 编译器编译原理
    • 历史背景
    • gcc工具链是如何工作的?
    • 工具链中有哪些组件?
  • 工具链的构建顺序
  • riscv gcc编译器的目录结构
  • riscv gcc编译器的构建
  • 编译最小支持RVB和RVV的riscv gcc

概述

gcc工具链是一个复杂而又巧妙的工程,随着riscv上层软件的逐渐完善,工具链和底层系统软件的开发也显得尤为重要。深入理解gcc的原理,能够更好的对计算机体系结构有一个完整的了解。

但是由于gcc的源码过于复杂,其诞生的年代也十分久远,入手gcc也相当棘手。而riscv是一个新的体系架构,在该架构上去理解gcc的开发和编译过程,不会有许多的历史包袱,这也是后面文章中主要进行分析的架构。

编译器编译原理

历史背景

GNU C编译器的早期作者是GNU项目的创始人Richard Stallman。

GNU项目最早开始于1984年,其目的是为了创建一个完全自由免费的类Unix的操作系统。由于每一个类Unix的操作系统都需要一个C编译器作为支持,但是当时并没有免费使用的编译器。所以GNU项目不得不从头开始进行编译器的开发工作。在1987年,第一个GCC正式版本诞生,这是一个免费发布并且可移植的编译器,此后GCC成为开发免费软件最重要的工具之一。

后来随着编译语言的增多,包括Fortran,ada,JavaObjective-C也被支持。

gcc工具链是如何工作的?

gcc工具链并不是一个单独的程序,而是一系列程序的合集,这些工具以一种串联的方式进行排列。

其中就包括预处理,编译,汇编,链接等过程。这种特性的特点就是上一个步骤的输出结果总是下一个过程的输入,最后生成了特定架构所需的可执行的文件。按照这种方式组合,形成了"工具链",当为不同的架构生成机器代码时,称为交叉编译工具链。

工具链中有哪些组件?

下图展示了riscv gcc编译完成后的组件。当然,最新发挥作用的是编译器gcc本身,将C文件转换成汇编代码。

汇编代码则由汇编器进行链接,生成特定的机器代码。

下面通过一个表格简单的描述一下

工具

功能

addr2line

可以将指令的地址转换成文件名,函数名和源代码行数的工具

ar

库管理器,创建静态库

as

汇编器,主要处理汇编代码

objcopy

将文件转换成另外一种格式,比如.bin转换成.elf,或者将.elf转换成.bin

objdump

反汇编

readelf

显示elf相关的信息

size

列出可执行文件的每一部分的尺寸,代码段,数据段等大小信息

通过上述一些列的工具,可以将C语言转换成可以执行的代码程序,但是现在还缺少在目标机器上运行程序时的C库,C库提供了一个标准的抽象层,可以执行基本的任务,包括内存分配、终端输出、文件访问等等。对于不同的系统,也有着不同的C库,比如针对Linux桌面环境,有glibc或者eglibc或者uClibc等等。对于嵌入式Linux,可以选择eglibc或者uClibc,对于没有任何操作系统或者RTOS来说,可以使用newlib,甚至可以不使用。还有一些小众的C库,针对特定的需要进行设计,比如针对ramdisk优化的klibc等等。

工具链的构建顺序

这些工具构建需要一定的顺序,这是一件有趣的事情。

  • 编译出的编译器需要C库
  • 编译出C库需要编译器

这就带来一个问题,A依赖B,B也依赖A。这就是典型的先有鸡,后有蛋的问题。

编译器首先会构建一个不需要C库就能构建出来的精简编译器,这部分我们称为引导程序、初始编译器或者核心编译器。

  • 最后的编译器需要C库
  • 编译出C库需要编译器
  • 编译器需要C库的头文件和引导程序

现在的问题变成了编译C库需要的头文件和引导文件。由于C库提供了"C runtime",也被称为CRT,但是这部分的编译还是需要依赖编译器。

  • 最后的编译器需要C库
  • 编译出C库需要编译器
  • 编译器需要C库的头文件和引导程序
  • 编译C库的引导程序

这样问题可能就变得简单一些了,我们只需要构建一个简单的编译器,他不需要C库头文件但是需要启动文件,该编译器同时也是C库的引导程序。我们称为这个简易编译器为pass1。最后完整的编译器为pass2。下面则变得清晰了起来:

  • 最后的编译器需要C库
  • 编译出C库需要编译器
  • 编译器需要C库的头文件和引导程序
  • 编译C库的引导程序
  • 我们需要一个简易的编译器

这样下来,我们就可以得到一个编译器所需要的C库了,然后完整的编译出最终的编译器。

上述只是一个基本的流程概述,实际上过程比这个更加的复杂。

下面来看riscv gcc编译后生成的文件夹

带有build前缀的都是编译器编译时的中间产物。可以看到build-gcc-newlib-stage1build-gcc-newlib-stage2

实际上gcc在编译过程中编译了三次:

  • 编译额外的C编译器(stage1)
  • 用stage1的编译器重新编译GCC编译器(stage2)
  • 用stage2的编译器再次编译GCC编译器(stage3)

stage2和stage3是为了更好的检查GCC编译的准确性,同时,也可以采用不同的优化等级对最后生成的gcc工具链进行优化。

其实stage2和stage3产生的应该是一样的结果,可以采用make compare来进行校验,由于这种严密的编译机制,可以使得最后的gcc生成的产物变得准确无误。

riscv gcc编译器的目录结构

在了解如何编译之前,首先看一下riscv gcc仓库有哪些东西。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://github.com/riscv-collab/riscv-gnu-toolchain
  • qemu

工具链仓库的qemu左右是为了测试使用,结合riscv gcc的dejagnu测试框架,测试功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
make report-linux SIM=qemu # Run with qemu
  • riscv-binutils

该目录用于binutils生成,比如ar,ld等二进制工具,工具集合,也是非常重要的一个仓库。

  • riscv-dejagnu

dejagnu测试框架是测试gcc和binutils重要的工具,是保证gcc和binutils功能正常的非常重要的测试框架。

  • riscv-gcc

gcc主要的程序

  • riscv-gdb

通过外设接口,可以通过gdb调试

  • riscv-glibc

支持编译的程序在Linux运行的glibc库

  • riscv-newlib

支持编译的程序在rtos或者baremetal上运行的的C库

riscv gcc编译器的构建

当前公认的riscv gcc主线在

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://github.com/riscv-collab/riscv-gnu-toolchain

该master分支是稳定的可以使用的riscv 版本。但是现在做riscv扩展指令集分析,这里选择

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://github.com/riscv-collab/riscv-gnu-toolchain/tree/basic-rvv

该分支实现了也就是riscv b扩展,v扩展的最小支持。该分支作为入手gcc分析是最好的选择。

下载代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
git clone https://github.com/riscv-collab/riscv-gnu-toolchain.git
cd riscv-gnu-toolchain
git checkout basic-rvv
git submodule init && git submodule update

在官方的readme.md中介绍了如何编译的流程。

大概介绍一下:

该编译器支持两种libc库,支持rtos和barematel的newlib库和支持Linux的glibc。

默认使用make时,链接的是newlib库,使用make linux时,链接的是glibc。

同时由于riscv有着非常多的arch组合,可以编译单独的arch,比如

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./configure --prefix=/opt/riscv --with-arch=rv32gc --with-abi=ilp32d

那么只编译arch是rv32gc,abi为ilp32d的组合。

如果同时支持rv32和rv64的组合配置,可以选择--enable-multilib

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./configure --prefix=/opt/riscv --enable-multilib

不同的组合有着不同的需求,如果只是针对不同的芯片编译出的编译器,那么只选择一个配置即可,若需要发布更多组合的arch支持编译器,可以选择multilib。

编译最小支持RVB和RVV的riscv gcc

可以选择下面的配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./configure --prefix=$RISCV/learn/  --with-arch=rv64gcv_zba_zbb_zbc_zbs --with-abi=lp64d --with-cmodel=medany --with-multilib-generator="rv64gcv_zba_zbb_zbc_zbs-lp64d--"
make -j $(nproc)

这里的RVV可以直接采用gcv即可,而RVB则被拆分成各种子扩展。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Zba - address generation
Zbb - basic bit manipulation
Zbc - carryless multiplication
Zbs - single-bit instructions

最后生成的riscv gcc工具链可以做测试。

结合编译参数,开启O2优化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'-march=rv64gcv_zba_zbb_zbc_zbs' ,'-mabi=lp64d'

可以生成带有RVB扩展的格式的代码。

不难看出,当写出下面的函数时

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
long sh1add_test(long a, long b)
{
  return a + (b << 1);
}

而开启rvb扩展时的反汇编代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
long sh1add_test(long a, long b)
{
    800000a2:   1141                    addi    sp,sp,-16
    800000a4:   e422                    sd      s0,8(sp)
    800000a6:   0800                    addi    s0,sp,16
  return a + (b << 1);
}
    800000a8:   6422                    ld      s0,8(sp)
    800000aa:   20a5a533                sh1add  a0,a1,a0
    800000ae:   0141                    addi    sp,sp,16
    800000b0:   8082                    ret

不开启rvb扩展时的反汇编代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
long sh1add_test(long a, long b)
{
    800000a2: 1141                 addi sp,sp,-16
    800000a4: e422                 sd s0,8(sp)
    800000a6: 0800                 addi s0,sp,16
  return a + (b << 1);
}
    800000a8: 6422                 ld s0,8(sp)
  return a + (b << 1);
    800000aa: 0586                 slli a1,a1,0x1
}
    800000ac: 952e                 add a0,a0,a1
    800000ae: 0141                 addi sp,sp,16
    800000b0: 8082                 ret

由此可见开启rvb扩展优化后,代码的code size和性能均会提高。

那么这个优化在gcc中是如何实现的,后面文章中会慢慢的提及。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式IoT 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
riscv gcc中添加custom自定义指令
在riscv的处理器开发过程中,各家处理器往往都会涉及到自定义指令功能的添加。在处理器设计上,添加一些特定功能的指令是十分正常的,一般处理办法本文会讲述,让其识别客户自定义的指令。从现有的解决办法上来看,第一种是可以利用Kito Cheng提供的.insn模板进行开发,第二种则是修改binutils的方法。本文主要介绍这两种办法进行riscv custom指令的添加。
bigmagic
2021/10/09
5.2K0
教你在RISCV中使用DSP指令!
DSP有相关的专业芯片,能够专门实现计算功能,相比于通用处理器,DSP芯片专门用于计算,可以在一个周期内执行多条计算。随着单片机对计算功能的需求越来越多,如果用传统的通用处理器去执行大数据的计算,将会消耗许多的机器周期,导致系统的实时性变低。于是,一些通用芯片上也开始集成DSP扩展,比如常见的ARM Cortex-R和ARM Cortex-M内核。
bigmagic
2021/09/15
2.2K0
教你在RISCV中使用DSP指令!
riscv gcc中添加自定义的csr支持
由于RISCV的模块化的指令集的定义,各家都有着自己的实现方式。从当前看来,除了标准的CSR外,很多都实现了自己的CSR指令扩展。如何自定义CSR并且让编译器能够识别,本文将进行一定的分析,同时从riscv gcc开发的角度出发,来分析编译器开发的流程。
bigmagic
2021/08/20
2.1K0
交叉编译学习笔记(一)——交叉编译和交叉工具链
本文介绍了交叉编译和交叉工具链的基本概念,以及其在嵌入式开发中的应用。同时,还详细描述了交叉工具链的重要组成部分,以及如何使用它们进行交叉编译。
剑影啸清寒
2018/01/02
6.2K0
D1 riscv芯片上运行rt-thread进行RVV性能评估
D1 && D1s(f133)采用的是平头哥C906的core,上面已经支持了RVV 0.7.1版本,虽然目前RVV1.0已经frozen,这就意味着上游编译器或者一些相关的生态软件将支持RVV1.0,但是作为性能评估RVV0.7.1与RVV1.0影响并不大。下面的文章主要描述如何在D1 && D1s芯片上运行rt-thread,并且描述如何开启RVV,同时对RVV性能进行一个简单的评估,最后讨论RVV如何与RTOS使用的问题。
bigmagic
2022/03/04
1.7K0
D1 riscv芯片上运行rt-thread进行RVV性能评估
riscv64 裸机编程实践与分析
任何芯片在启动之前都需要有一段汇编代码,从这段汇编代码上就可以体现一些架构设计的特点。往往做嵌入式底层开发都需要关注这段汇编代码的含义,这样在使用的时候才能全面的了解启动时做了什么事情,在后续的程序中遇到问题也能复盘推演。
bigmagic
2021/01/08
3.4K0
深入浅出GCC编译器
GCC原名为GNU C语言编译器(GNU C Compiler),只能对C语言进行编译等处理。后来随着其功能的扩展,可以支持更多编程语言,如C++、Java、Fortran、Pascal、Objective -C、Ada、Go以及各类处理器架构上的汇编语言等。所以,现在我们所说的GCC是指GNU编译器套件(GNU Compiler Collection)。本文将带你迈入GCC的大门,了解一个C源文件是如何在GCC编译工具链的加工下成为一个可执行性文件的,并详细讲解GCC编译参数以及可能会用到的其他知识。
mindtechnist
2024/08/08
9860
深入浅出GCC编译器
GCC工具链都包含哪些工具
GCC原名为GNU C语言编译器(GNU C Compiler),原本只能处理C语言。后来随着功能的扩展,支持的语言种类越来越多 ,故更名为GCC(GNU Compiler Collection,GNU编译器套件)
乱码三千
2021/08/24
1.7K0
S3C2440② | arm-linux-gcc交叉编译工具链
宿主机运行的是标准Linux操作系统,编译出的程序却需要在目标处理器(S3C2440@ARM920T)上跑,这就叫交叉编译,编译器叫做交叉编译器。
Mculover666
2020/07/16
4.2K0
S3C2440② | arm-linux-gcc交叉编译工具链
Linux编译工具:gcc入门
1. 什么是gcc gcc的全称是GNU Compiler Collection,它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器(GNU C Compiler),现在除了c语言,还支持C++、java、Pascal等语言。gcc支持多种硬件平台。 2. gcc的特点 gcc是一个可移植的编译器,支持多种硬件平台。例如ARM、X86等等。 gcc不仅是个本地编译器,它还能跨平台交叉编译。所谓的本地编译器,是指编译出来的程序只能够在本地环境进行运行。而gcc编译出来的程序能够在其他平台进行运
Tencent JCoder
2018/07/02
5.1K0
征服工具链-FFmpeg的编译(Windows 篇)
注:参考自bilibili系列视频,征服工具链-FFmpeg的编译(Windows 篇),更详细的内容可以从视频获取https://www.bilibili.com/video/BV17i4y1G7WA
瑶瑶
2020/07/03
1.6K0
在全志D1开发板上玩ncnn
在此期间,ncnn收到perfxlab和腾讯犀牛鸟开源人才的学生有关riscv vector的优化
阿志小管家
2024/02/24
2200
在全志D1开发板上玩ncnn
riscv:ra寄存器的设置与保存
今天在写DragonOS的进程切换代码的时候,对于ra寄存器的设置与保存有点疑惑,于是写这篇文章来分析一下。
灯珑LoGin
2024/04/01
5480
riscv:ra寄存器的设置与保存
C语言开发-开发工具安装配置,gcc下载安装配置
下载安装VSCode开发工具,下载地址:https://code.visualstudio.com/ 喜欢用中文的可以,同时按Ctrl + Shift + X 快捷键 在左侧“扩展”视图文本框中输入“Language Packs”,点击你所需要的语言,这里我们安装的是中文简体,安装完成右下角弹出一个重启按钮,点击重启,语言自动切换。
共饮一杯无
2022/11/28
6270
C语言开发-开发工具安装配置,gcc下载安装配置
C/C++生态工具链——gcc/g++编译器使用指南
GCC的全称是GNU Compiler Collection,是GNU工具链中的一种。GCC不仅支持C/C++语言,还支持Fortran/Ada/Java等语言的编译。
Coder-ZZ
2023/02/23
2.9K0
C/C++生态工具链——gcc/g++编译器使用指南
交叉编译学习笔记(二)——交叉编译器的命名规则
该文介绍了交叉编译工具链的使用,包括arm-linux-gnueabi-gcc、arm-linux-gnueabihf-gcc、arm-none-eabi-gcc、arm-none-linux-gnueabi-gcc、arm-none-linux-gnueabihf-gcc、qoriq-elf-gcc等工具的使用方法。
剑影啸清寒
2018/01/02
5.1K0
GCC、ARM-LINUX-GCC、ARM-ELF-GCC浅析
The GNU Compiler Collection,通常简称GCC,是一套由GNU开发的编译器集,为什么是编辑器集而不是编译器呢?那是因为它不仅支持C语言编译,还支持C++, Ada, Objective C等许多语言。另外GCC对硬件平台的支持,可以所无所不在,它不仅支持X86处理器架构, 还支持ARM, Motorola 68000, Motorola 8800, Atmel AVR, MIPS等处理器架构。
全栈程序员站长
2022/07/18
7.8K0
用哪吒D1开发板体验riscv向量底层编程
RISCV V扩展即向量指令扩展(RVV),这部分作为研究AI加速计算领域有着非常关键的作用。既然的D1支持了rvv扩展(0.7.1,最新的版本已经0.10版本),那么就实际的从底层原理角度分析一下使用的流程。利用了多媒体加速指令集,可以让计算变得更加的高效,同时并行计算的特性使得同时多次计算一组数字成为可能,类似于arm的NEON等等,那么RISCV又该如何去开启和使用V扩展指令,让计算变得更加高效呢?
bigmagic
2021/07/01
1.7K0
为riscv64编译uboot和grub
首先需要安装交叉编译工具链,可以用apt安装riscv64的gcc编译工具链。我是自己编译了一个musl-gcc,下载:
灯珑LoGin
2023/11/20
6570
Linux下开发stm32 ①
这是为了给接下来的Linux下嵌入式开发打好基础,尽快熟悉Linux下c编程,但是在开发stm32的时候,编译工具链要使用gcc-arm-none-eabi,为什么不是gcc呢?这就要说到linux下的交叉编译了,因为我们要在PC机上编译出可以运行在ARM上的程序,使用gcc编译出的是在PC上运行的程序,所以我们要使用gcc-arm-none-eabi进行交叉编译~
Mculover666
2020/07/16
3.7K0
Linux下开发stm32 ①
相关推荐
riscv gcc中添加custom自定义指令
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档