GCC 和 Clang 的原子库支持
本文首先介绍了标准库和运行时库在 GCC 和 clang 上的关系和区别。之后介绍各自编译器软件中对原子库的支持情况。 本文讨论的 GCC 的版本是 7.5.0,clang 的版本是 12.0.0。 本文提到的 GCC 和 clang 分别是对应的编译器系统,并不是 gcc/Clang 编译器前端或编译器驱动软件。 概念标准 C 库libc 是 Linux 下最早支持的标准 C 库。 后来逐步被 glibc 取代,glibc 是 GNU 版本的标准 C 库,是现在最流行的标准 C 库,在主流 Linux 操作系统中都是预装的。 glibc 实现了 Linux 系统中最底层的 API 库,主要是对系统调用的封装,比如 fopen。同时也提供了一些通用的数据类型和操作,如 string,malloc,signal 等。 除此之外,还有一些小众 C 库,比如用于嵌入式环境的 eglibc,还有轻量级的 glib 等。这些库在 Linux 系统中不是预装的。 标准 C++ 库标准 C++ 库主要有两个,libc++ 和 libstdc++,看似名字相同,libstdc++ ...
LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器
最近家里事情比较多,拖了一段时间。这个笔记已经基本完成了,还剩下最后一章,使用 simulator 来验证我们开发的编译器,我将其放到附录里,是因为它不属于开发工作,只是辅助工具。我们的 Simulator 实现了 Cpu0 的指令功能,从而可以将 hex 格式的代码文件在之上运行,并能在终端中查看运行结果。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器 A.1 运行 SimulatorA.1.1 编译 Simulator我们的 Simulator 使用 Verilog 语言实现,我借用了原作者提供的代码,代码文件是 cpu0.v,需要使用...
LLVM 后端实践笔记 10:汇编
这一章,我们来添加 Cpu0 的汇编功能,这包括独立汇编器和 C 语言内联汇编特性两个部分。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器 10.1 汇编器独立汇编器可以理解为依赖于 LLVM 后端提供的接口实现的一个独立软件,因为 LLVM 和 gcc 在这个地方的实现逻辑不一样。 在 gcc 中,编译器和汇编器是两个独立的工具,编译器,也就是 cc,只能生成汇编代码,而汇编器 as,才用来将汇编代码翻译为二进制目标代码,gcc 驱动软件 gcc 将这些工具按顺序驱动起来(还包括预处理器、链接器等),最终实现从 C 语言到二进制目标代码的...
LLVM 后端实践笔记 9:ELF文件支持
虽然我们的 Cpu0 模拟器只需要输入 hex 格式的编码文件就可以执行,但这一章依然介绍如何生成 ELF 文件,ELF 文件是一种通用的可执行文件、目标文件和共享库与核心转储文件标准,最早是由 System V 应用二进制接口发布,之后成为一种标准,并很快被类 Unix 操作系统接受。几乎所有支持编译的后端平台都需要生成一种可执行文件格式来执行代码,现在主流的三种可执行文件分别是 Linux 系统及裸机系统支持的 ELF 文件、Windows 系统支持的 COFF 文件以及 MacOS 系统支持的 Mach-O 文件格式。我们让 Cpu0 后端生成 ELF 文件格式。 之前章节我们介绍了 Cpu0 后端生成各种指令编码的代码,所以有关于指令编码的行为,是由 td 文件中的描述来确定的,LLVM 的公共部分已经帮我们生成了指令编码的功能。但目前还没有定义生成 ELF 文件的头部、段组成、重定位信息等内容,这一章主要实现这部分内容。 这一章,我们会使用二进制解析工具来检查 ELF 文件,比如 objdump 和 readelf 文件。需要注意的是,因为他们是 gnu 工具集的软件,...
LLVM 后端实践笔记 8:函数调用
在这一章,我们会在 Cpu0 后端中增加对子过程/函数调用的翻译功能,会添加大量代码。这一章首先会介绍 Mips 的栈帧结构,我们的 Cpu0 也会借用 Mips 的栈帧设计,大多数 RISC 机器的栈帧设计都是类似的,如果你对这块的背景知识有困惑,需要先查阅其他书籍,比如《深入理解计算机系统》这类计算机体系结构的书。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器 8.1 栈帧结构Cpu0 函数调用的第一件事是设计好如何使用栈帧,比如在调用函数时,如何保存参数。 具体如下表所示,保存函数参数有两种设计,第一种是将所有参数都保存在栈...
LLVM 后端实践笔记 7:控制流
这一章会介绍与控制流有关的功能实现,比如 if、else、while 和 for 等,还会介绍如何将控制流的 IR 表示转换为机器指令;之后会引入几个后端优化,处理一些跳转需求引入的问题,同时来说明如何编写后端优化的 pass。在条件指令小节中,会介绍 LLVM IR 中的特殊指令 select 和 select_cc,以及如何处理这种指令,从而来支持更细节的控制流支持实现。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器 7.1 控制流语句7.1.1 简要说明从机器层面上来看,所有的跳转只分为无条件跳转和有条件跳转,从跳转方式上来分,又分为...
LLVM 后端实践笔记 6:更多数据类型
之前的章节只实现了 int 和 32 位的 long 类型数据,这一章会新增一些更复杂的数据类型,比如 char, bool, short, long long,还会增加结构体,浮点,和向量类型。这一部分内容相对比较简单,其实这些类型也都是标准语言都支持的类型,所以 LLVM 自身已经实现了很大一部分功能,只要我们的后端不那么奇怪,就很容易填补缺失的内容。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器 6.1 实现类型6.1.1 局部指针我们需要在 td 文件中添加内存操作数的描述片段。具体参见代码描述部分。 6.1.2 char, sho...
LLVM 后端实践笔记 5:全局变量
之前的几章,只访问了局部变量,在这一章中,我们要处理全局变量的访问。全局变量的 DAG 翻译不同于之前的 DAG 翻译。它的 DAG 翻译,需要额外依据 llc -relocation-model 参数(指定重定位模式是静态重定位还是运行时重定位),在后端创建 IR DAG 节点,而其他的 DAG 只需根据输入文件来直接做 DAG 的翻译 (伪指令除外)。大家需要专注于如何在执行时创建 DAG 节点而增加的代码,以及如何在 td 文件中定义 Pat 结构。另外,全局变量的机器指令打印功能也需要完成。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器...
发掘战略性副业
今天想聊一下战略性副业。我在看《哈佛商业评论》的一期文章中学到了这个概念,原文这个词是 “the strategic side gig“ 。那么,到底什么是战略性副业? 一、什么是战略性副业我们经常聊到的副业工作,大多数都是非战略性副业,我们通过出卖剩余精力和时间来兑换金钱,这种工作并不会带来丰富的附加收益,比如提高我们的技能,增加我们的经验。 战略性副业,其实就是能有助于提高我们各方面能力的业余工作,从长期的角度来看,战略性副业才会有助于自己综合能力的提升,有助于实现人生价值。 我在《如何摧毁年轻人》一文中提到: 摧毁年轻人最简单的办法,就是让他们忙到无法学习和成长。如何摧毁年轻人 (qq.com) 而一份战略性副业,就是学习和成长的绝好机会。 二、对我们有什么好处战略性副业其实是一种良性的社会活动,我们可以将其看做是投资行为。我们都知道投资要分散资产,从而平滑风险。你的主业就是核心资产,而战略性副业就是卫星资产,你可以选择如何配置这些资产,来让它们产生联动。 《哈佛商业评论》调查了122个来自不同公司和行业的高管,他们都认同高质量的副业对于事业成功非常重要,并且他们自己...
LLVM 后端实践笔记 4:生成目标文件
之前的章节只介绍了汇编代码生成的内容,这一章,我们将介绍对 ELF 目标格式文件的支持以及如何使用 objdump 工具来验证生成的目标文件。在 LLVM 代码框架下,只需要增加少量的代码,Cpu0 后端就可以生成支持大端或小端编码的目标文件。目标注册机制以及它的结构也在本章介绍。 LLVM 后端实践笔记 0:序LLVM 后端实践笔记 1:新后端初始化和软件编译LLVM 后端实践笔记 2:后端结构LLVM 后端实践笔记 3:算术和逻辑指令LLVM 后端实践笔记 4:生成目标文件LLVM 后端实践笔记 5:全局变量LLVM 后端实践笔记 6:更多数据类型LLVM 后端实践笔记 7:控制流LLVM 后端实践笔记 8:函数调用LLVM 后端实践笔记 9:ELF文件支持LLVM 后端实践笔记 10:汇编LLVM 后端实践笔记 附录A:使用 Simulator 验证编译器 4.1 简要说明4.1.1 编码当 llc 指定 -filetype=obj 时,编译器会生成目标文件(而不是汇编文件),此时,AsmPrinter::OutStreamer 所引用的是 MCObjectStream...














