2312llvm,01基本介绍
LLVM设计的核心是它的IR.
在把LLVMIR翻译特定汇编语言时,LLVM首先将程序变换为(DAG)有向无环图,以更易选指(SelectionDAG)容易,然后变换回三地址指令,来调度指令(MachineFunction).
为了看清驱动编译程序时,调用的后续工具,用-###命令行参数:
$ clang -### hello.c -o hello
部分工具:
1,opt:IR层次优化器.输入必须是LLVM位码(编码的LLVMIR)文件,输出文件也是该类型.
2,llc:通过具体后端把LLVM位码变换为目标机器汇编语言文件或目标文件.可通过参数选择优化级别,开启调试选项,开关目标指定优化.
3,llvm-mc:为多种(如ELF,MachO,PE)目标格式汇编指令生成目标文件.也可反汇编同样目标文件,输出等价的汇编信息和内部LLVM机器指令数据结构.
4,lli:为LLVMIR实现了解释器和JIT编译器.
5,llvm-link:连接若干LLVM位码,产生包含所有输入的单个LLVM位码.
6,llvm-as:把人类可读的LLVM汇编转换为LLVM位码.
7,llvm-dis:解码LLVM位码,生成LLVM汇编.
考虑简单的来自多个源文件多个函数组成的C程序.第一个源文件是main.c,代码如下:
#include <stdio.h>
int sum(int x, int y);
int main() {int r = sum(3, 4);printf("r = %d\n", r);return 0;
}
第二个源文件是sum.c,代码如下:
int sum(int x, int y) {return x + y;
}
可用下面命令编译它:
$ clang main.c sum.c -o sum
然而,用独立工具也可实现相同结果.首先,用不同参数调用clang,让它为C源文件生成LLVM位码,然后不继续编译,就此停止:
$ clang -emit-llvm -c main.c -o main.bc
$ clang -emit-llvm -c sum.c -o sum.bc
-emit-llvm参数,让clang根据输入参数是-c还是-S,生成LLVM位码或LLVM汇编文件.
示例中,-emit-llvm参数和-c,让clang生成LLVM位码格式的目标文件.
用-flto-c组合参数同样.如果想生成可读的LLVM汇编,用下面这对命令代替:
$ clang -emit-llvm -S -c main.c -o main.ll
$ clang -emit-llvm -S -c sum.c -o sum.ll
注意,不用-emit-llvm或-flto参数时,-c参数用目标机器语言生成目标文件,而-S参数生成目标汇编语言文件.行为与GCC一样.
这里.bc和.ll分别是LLVM位码和汇编文件的扩展名.
为每个LLVM位码生成目标指定的目标文件,用系统链接器链接它们以生成可执行文件:
$ llc -filetype=obj main.bc -o main.o
$ llc -filetype=obj sum.bc -o sum.o
$ clang main.o sum.o -o sum
首先,链接这两个LLVM位码为一个最终的LLVM位码.然后,为该最终的位码生成目标指定目标文件,调用系统链接器生成可执行文件:
$ llvm-link main.bc sum.bc -o sum.linked.bc
$ llc -filetype=obj sum.linked.bc -o sum.linked.o
$ clang sum.linked.o -o sum
-filetype=obj参数指定输出目标文件,而不是输出汇编文件.
流程:C==>BC=>llc为.obj文件,再系统链接
流程:C==>BC=>llvm-link为.单个BC文件,再llc,再系统链接
调用(llc)后端前,链接IR文件,用opt工具链接时优化
llc工具也可生成汇编输出,利用llvm-mc进一步汇编.
LLVM基础库
1,libLLVMCore:包含所有LLVMIR相关的逻辑:IR构造(数据布局,指令,基本块,函数)和IR验证.还提供了趟管理器.
2,libLLVMAnalysis:包含若干IR分析趟,如别名分析,依赖分析,常量合并,循环信息,内存依赖分析,指令简化等.
3,libLLVMCodeGen:实现目标无关生成代码和机器级(低层版本LLVMIR)的分析和转换.
4,libLLVMTarget:通过抽象通用目标,访问目标机器信息.libLLVMCodeGen实现了通用后端算法,目标相关逻辑留给后面的库,而高层抽象提供交流通道.
5,libLLVMX86CodeGen:包含x86目标相关的生成代码信息,转换和分析趟,由它们构成了x86后端.注意,每个机器目标都有自己不同的库,如分别实现了ARM和MIPS后端的LLVMARMCodeGen和LLVMMipsCodeGen.
6,libLLVMSupport:包含实用工具.如错误处理,整数和浮点数处理,命令行解析,调试,文件支持,串操作等,这些是该库实现算法示例,LLVM的各个组件都用它们.
7,libclangDriver:包含一套C++类.编译器驱动用它们理解类似GCC的命令行参数,以编译任务,为外部工具组织参数,以完成编译.根据目标平台,可用不同编译策略.
8,libclangAnalysis:这是一系列Clang提供的包括构造CFG和调用图,可达代码,安全格式化串等的前端架构分析.
libclang
libclang:(对比C++的LLVM代码)它实现一套C接口以暴露Clang的前端功能:诊断报告,遍历AST,补全代码,光标和源码间映射.
C接口相当简单,用C设计接口是为了更稳定,让其它语言(如Python),可很容易地使用Clang的功能.
它仅覆盖内部LLVM组件所用的C++接口的子集.
C++实践
在基类中实现通用生成代码算法,继承和多态方法抽象不同后端共同任务.这样,每个具体后端专注实现它的特性,编写少量必需函数以覆盖父类通用操作.
如libLLVMCodeGen包含常见算法,libLLVMTarget包含具体机器抽象接口.下面的代码片演示了MIPS目标机器描述类是如何按LLVMTargetMachine类的子类声明的.此代码是LLVMMipsCodeGen库的一部分:
class MipsTargetMachine : public LLVMTargetMachine {MipsSubtarget Subtarget;const DataLayout DL;
...
另一例,目标无关的(所有后端公共的)分配寄存器器要知道哪些寄存器是保留而不能用于分配的.
此信息依赖具体目标,不能通用的父类中确定.这可调用MachineRegisterInfo::getReservedRegs()函数来确定,每个目标必须覆盖它.
下面演示了SPARC目标如何覆盖:
BitVector SparcRegisterInfo::getReservedRegs(...) const {BitVector Reserved(getNumRegs());Reserved.set(SP::G1);Reserved.set(SP::G2);
...
此代码中,通过位向量,SPARC后端说明了哪些寄存器不能用于通用分配寄存器.
调试编译器细节
尽量使用libLLVMSupport实现的断言.
查看ARM后端趟代码,它修改常量池布局,重新赋值.
ARM程序常用该策略加载大型常量,因为单个大型的池距离指令太远,以致指令无法访问它,来解决受限的PC相对寻址机制.如下:
//lib/Target/ARM/ARMConstantIsland趟.cpp
const DataLayout &TD = *MF->getTarget().getDataLayout();
for (unsigned i = 0, e = CPs.size(); i != e; ++i) {unsigned Size = TD.getTypeAllocSize(CPs[i].getType());assert(Size >= 4 && "Too small constant pool entry");unsigned Align = CPs[i].getAlignment();assert(isPowerOf2_32(Align) && "Invalid alignment");//验证所有常量池项是否都是`对齐的倍数`.如果不是,则要`填充`,以便`指令`保持一致.assert((Size % Align) == 0 && "CP Entry not multiple of 4 bytes!");
此代码遍历ARM常量池,期望它的每个字段遵守约束.注意如何用assert来控制数据语义.
插件式趟接口
趟是转换分析或优化.通过LLVMAPI可在编译生命期的不同阶段轻松注册任意趟.
趟管理器用来注册趟,调度趟,声明趟之间的依赖关系.因此,不同编译阶段都可取得PassManager类的实例.
如,目标可自由地在如分配寄存器前后,或输出汇编前等生成代码的若干位置,应用定制优化.如:
//lib/Target/X86/X86TargetMachine.cpp
bool X86PassConfig::addPreEmitPass() {...if (getOptLevel() != CodeGenOpt::None && getX86Subtarget().hasSSE2()) {addPass(createExecutionDependencyFixPass(&X86::VR128RegClass));...}if (getOptLevel() != CodeGenOpt::None &&getX86Subtarget().padShortFunctions()) {addPass(createX86PadShortFunctions());...}...
注意后端如何根据具体目标信息,决定是否添加某个趟.添加第一个趟前,X86目标检查是否支持SSE2多媒体扩展.
对第二个趟,检查是否要求特殊填充.
编写第一个LLVM项目
创建一个程序,它读入位码文件,打印程序定义的函数名,函数基本块数量.
编写Makefile
//注意制表符.
LLVM_CONFIG =llvm-config
ifndef VERBOSE
QUIET:=@
endif
SRC_DIR =$(PWD)
LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags)
COMMON_FLAGS=-Wall -Wextra
CXXFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags)
CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) -I$(SRC_DIR)
第一部分定义了若干编译选项的Makefile变量.第一个变量决定llvm-config程序位置.
llvm-config用来打印构建要链接LLVM库外部项目的有用信息.
如,定义C++编译器的一系列选项时,注意请求Make来运行llvm-config-cxxflagsshell命令,让它打印编译LLVM项目的一系列选项.
这样,编译项目源码和LLVM源码兼容.最后把变量定义的一系列选项传递给编译器预处理器.
HELLO=helloworld
HELLO_OBJECTS=hello.o
default: $(HELLO)
%.o : $(SRC_DIR)/%.cpp@echo Compiling $*.cpp$(QUIET)$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $<
$(HELLO) : $(HELLO_OBJECTS)@echo Linking $@$(QUIET)$(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) $^ `$(LLVM_CONFIG) --libs bitreader core support`
这里:
llvm-config –libs bitreader core support
-libs选项要求llvm-config提供链接器选项清单,来链接期望的LLVM库.这里,要求链接libLLVMBitReader,libLLVMCore,libLLVMSupport.
代码
完整给出趟代码.因为创建在LLVM趟基础设施上,代码相对较短.
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Support/system_error.h"
#include <iostream>
using namespace llvm;
static cl::opt<std::string> FileName(cl::Positional, cl::desc("位码 file"), cl::Required);
int main(int argc, char** argv) {cl::ParseCommandLineOptions(argc, argv, "LLVM hello world\n");LLVMContext context;std::string error;OwningPtr<MemoryBuffer> mb;MemoryBuffer::getFile(FileName, mb);Module *m = ParseBitcodeFile(mb.get(), context, &error);if (m==0) {std::cerr << "读位码错误: " << error << std::end;return -1;}raw_os_ostream O(std::cout);for (Module::const_iterator i = m->getFunctionList().begin(),e = m->getFunctionList().end(); i != e; ++i) {if (!i->isDeclaration()) {O << i->getName() << " has " << i->size() << " basic block(s).\n";}}return 0;
}
程序利用cl(cl代表命令行)名字空间的llvm工具来实现命令行接口.调用ParseCommandLineOptions函数,并声明一个cl::opt<std::string>类型的全局变量,以此说明程序接收带位码文件名类型的单个串参数.
然后,实例化一个保存LLVM编译的从属数据的LLVMContext对象,来让LLVM线安.MemoryBuffer类对内存块定义了个只读接口.
ParseBitcodeFile函数用它读取输入文件内容,并解析文件中的LLVMIR.错误检查完成后,遍历文件中模块的所有函数.
LLVM模块类似翻译单元,它包含编码一切内容的位码文件,作为LLVM的顶端实体,下面是若干函数,然后基本块,最后是指令.
如果函数只是个声明,则忽略它.找到函数定义时,打印名字,及基本块数.
编译后,用-help参数运行,看一看已为你的程序准备好的LLVM命令行功能.然后,找个想变换为LLVMIR的C或C++文件,变换,并再用程序分析.
$ clang -c -emit-llvm mysource.c -o mysource.bc
$ helloworld mysource.bc
相关文章:
2312llvm,01基本介绍
LLVM设计的核心是它的IR. 在把LLVMIR翻译特定汇编语言时,LLVM首先将程序变换为(DAG)有向无环图,以更易选指(SelectionDAG)容易,然后变换回三地址指令,来调度指令(MachineFunction). 为了看清驱动编译程序时,调用的后续工具,用-###命令行参数: $ clang -### hello.c -o hello…...
Spring之手写IoC
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...
IDEA运行JSP启动后页面中文乱码
源代码截图: 运行结果截图: 在<head>标签内加入代码 <% page contentType"text/html; charsetgb2312"%> 重启服务器,问题已改善 ————————————————— 该文仅供学习以及参考,可做笔记收藏…...
Python 自动化之收发邮件(二)
发邮件之Windows进程监控 文章目录 发邮件之Windows进程监控前言一、基本内容二、基本结构三、库模块四、函数模块1.进程监控2.邮件发送 五、程序运行模块1.获取时间2.用户输入3.进程监控3.1进程启动发邮件3.2进程停止发邮件 总结 前言 上一篇简单写了一下如何进行邮件的收发操…...
RHEL8_Linux_Ansible常用模块的使用
本章主要介绍Ansible中最常见模块的使用 shell模块文件管理模块软件包管理模块服务管理模块磁盘管理模块用户管理模块防火墙管理模块 ansible的基本用法如下。 ansible 机器名 -m 模块x -a "模块的参数" 对被管理机器执行不同的操作,只需要调用不同的模块…...
2023 英特尔On技术创新大会直播 | AI 融合发展之旅
前言 2023 年的英特尔 On 技术创新大会中国站,主要聚焦最新一代增强 AI 能力的计算平台,深度讲解如何支持开放、多架构的软件方案,以赋能人工智能并推动其持续发展。 大会的目标之一是优化系统并赋能开发者,特别注重芯片增强技术…...
【JavaWeb】往浏览器打印一个hello world
上集:建一个web项目 第一步:建好Servlet类的文件 右键src,建一个class 就行 第二步:编代码 可以直接复制粘贴 用来测试的类 import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; //↓是注解࿰…...
技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1)
1. 引言 开源代码实现见: https://github.com/hashcloak/fhe_risc0_zkvm(Rust)https://github.com/weikengchen/vfhe-profiled(Rust)https://github.com/l2iterative/vfhe0(Rust) L2IV Resea…...
Spring容器中scope为prototype类型Bean的回收机制
文章目录 一、背景二、AutowireCapableBeanFactory 方法 autowireBean 分析三、Spring 容器中 scope 为 prototype 类型 Bean 的回收机制四、总结 一、背景 最近做 DDD 实践时,遇到业务对象需要交给 Spring 管理才能做一些职责内事情。假设账号注册邮箱应用层代码流…...
Python生成器(python系列25)
前言:什么是生成器,他和迭代器的区别是什么?什么时生成器表达式,为什么和列表推导式那么像呢? 生成器: 定义:能够动态(循环一次,计算一次,返回一次…...
Vue项目搭建过程
Vue项目搭建过程 1、安装NodeJs 1.1 下载安装包 在 http://nodejs.cn/download/ 上下载64位安装包,然后进行安装,和普通软件的安装一样。 C:\Users\Administrator>node -v v16.13.1C:\Users\Administrator>npm -v 8.5.51.2 安装cnpm # 安装cn…...
系统分析师(软考)知识点整理(一)
第一章 信息 信息是不确定性的减少 xi: n个状态中的第i个状态p(xi):出现第i个状态的概率b: b一般取值为2 特征 #mermaid-svg-pvPkY9RE5GZIIIxl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pvPkY9RE5GZIIIxl…...
2021年数维杯国际大学生数学建模D题2021年电影市场票房波动模型分析求解全过程文档及程序
2021年数维杯国际大学生数学建模 D题 2021年电影市场票房波动模型分析 原题再现: 1、电影票房预测建模背景 随着人们文化消费需求的增加,电影院和银幕的数量不断增加,我国的电影产业不断呈现出繁荣景象。2019年,全国电影票房…...
Kubernetes 的用法和解析 -- 5
一.企业级镜像仓库Harbo 准备:另起一台新服务器,并配置docker yum源,安装docker 和 docker-compose 1.1 上传harbor安装包并安装 [rootharbor ~]# tar xf harbor-offline-installer-v2.5.3.tgz [rootharbor ~]# cp harbor.yml.tmpl harbor…...
HTML选择题试题——附答案
单选题 HTML的缩写是什么? A) Hyper Tool Markup LanguageB) Hyperlinks and Text Markup LanguageC) Hyper Text Markup LanguageD) Home Tool Markup Language 下列哪个标签用于定义文档的主体内容? A) <head>B) <body>C) <title>D)…...
html之CSS的高级选择器应用
文章目录 一、CSS高级选择器有哪些呢?二、高级选择器的应用1、层次选择器后代选择器子选择器相邻兄弟选择器通用兄弟选择器 2、结构伪类选择器(不常用)3、属性选择器E[attr]E[attrval]E[attr^val]E[attr$val]E[attr*val] 一、CSS高级选择器有…...
elementui+ <el-date-picker type=“datetime“/>时间组件的当前时间的180天之内的禁止选择处理
需求1如下:当前时间180天不可选择,180天之后可以选择,之前的时间都禁止选择 页面代码如下: <el-date-picker v-model"temp.expire_time" :picker-options"pickerOption" type"datetime" placeh…...
全网好听的BGM都在这里下载,赶紧收藏好了
无论是自媒体创作者还是从事视频剪辑工作的朋友,对于BGM的选择都很重要,一首适配的BGM能大大提升你作品的质量,还能让作品更优秀。哪里才能找到好听又免费的BGM?下面推荐几个我多年收藏的6个音效、音频素材网站,赶紧收…...
Spark编程实验一:Spark和Hadoop的安装使用
目录 一、目的与要求 二、实验内容 三、实验步骤 1、安装Hadoop和Spark 2、HDFS常用操作 3、Spark读取文件系统的数据 四、结果分析与实验体会 一、目的与要求 1、掌握在Linux虚拟机中安装Hadoop和Spark的方法; 2、熟悉HDFS的基本使用方法; 3、掌…...
代理和AOP
一:java代理 整体分为两种:静态代理和动态代理 静态代理:23种设计模式里面有个代理模式,那个就是静态代理。 动态代理:分为编译时增强(AspectJ)和运行时增强(JDK动态代理和CGLIB动态代理) 1:静态代理 这种代理在我们日常生活中其…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
