【软件分析/静态分析】学习笔记02——中间表示Intermediate Representation

news2024/12/26 23:02:45

🔗 课程链接:李樾老师和谭天老师的:南京大学《软件分析》课程02(Intermediate Representation)_哔哩哔哩_bilibili

目录

第二章 Intermediate Representation

2.1 编译器与静态分析器的关系(Compilers & Static Analzers)

2.2 AST vs. IR

2.3 IR: 三地址码(Three-Address Code, 3AC)

2.4 真实静态分析器中的3AC:Soot

2.5 静态单赋值(Static Single Assignment, SSA)

2.6 控制流分析(Control Flow Analysis)⭐

2.6.1(Basic Blocks, BB)——建立节点

2.6.2 控制流图 (Control Flow Graph, CFG)——添加边

2.7 总结


第二章 Intermediate Representation

2.1 编译器与静态分析器的关系(Compilers & Static Analzers)

编译器的作用:
        将程序员写的Source Code转换成机器可以识别的Machine Code,并在转换中及时报错。

编译器的主体框架:

        

  1. 通过扫描器(Scanner)做词法分析(Lexical Analysis):根据正则表达式(Regular Expression)检查输入字符是否合法(例如如果是翻译一个英语句子,就是检查字符是否是英文的,单词是否正确/合法),如果通过了词法分析,每个单词就会生成Tokens,给下一步进行分析。
  2. 通过解析器(Parser)做语法分析(Syntax Analysis):通过语法规则(上下文无关文法,Context-Free Grammar)检查语法,通过就转换成抽象语法树AST
  3. 通过类型检查(Type Checker)做语义分析(Semantic Analysis):根据属性语法(Atrribute Grammar)检查语义(期望实现的是识别在英语中的例如Apple eats you,这样语法正确但是语义不对的句子,但是实际上实现的是,例如String的值除以int 这种类型不匹配的错误)如果通过,就生成Decorated AST
  4. 为了进行静态分析优化,要将Decorated AST转换为中间表示(IR),这里的IR一般为三地址码,再进行静态分析,最后通过代码生成器将优化后的代码生成机器码传给机器。

        实际上,静态分析就是做code优化的,静态分析器IR的基础上进行分析。

2.2 AST vs. IR

        

        如图所示

ASTIR
语法树形式的,hight-level,更接近程序源码通常是三地址码的形式,low-level,更接近机器编码
通常与语言有关通常与语言无关
\统一、简洁
缺少控制流信息包含控制流信息
适合做快速的类型检测通常被认为是静态分析的基础

        所以,以三地址码为主要形式的IR是更有利于做静态分析的。

2.3 IR: 三地址码(Three-Address Code, 3AC)

什么是3AC?

        三地址码就是最多有三个地址(address)的表达形式,并且由于这个性质,每个三地址码的右侧最多只能有一个运算符。这里的地址(Adress)可以是以下三种形式之一:

  • 变量名称: a, b 
  • 常量Constant: 3
  • 编译器生成的临时变量: t1, t2

例如:

        t2 = a + b + 3

转换为三地址码的形式就是:

        t1 = a + b

        t2 = t1 + 3

一些常见的3AC形式:

       

        如上图所示,3AC的操作符也包含很多种形式可以是很多种形式:

  • bop 代表的普通二进制运算或逻辑运算(+ - * /  ……)     
  • uop 代表的单运算符(取负数,非……)
  • 也可以没有运算符
  • goto L 无条件的跳转
  • if… goto L 有条件的跳转
  • rop 代表条件操作(>,<,==,……)

        当然这些知识简单的3AC形式,还有更复杂的,我们通过soot这个例子来学习,见2.4

2.4 真实静态分析器中的3AC:Soot

Soot是一个Java优化框架。它提供了四种中间表示法,用于分析和转换Java字节码。其中 Jimple是一种适合优化的类型化3地址中间表示法(typed 3-address code)。这一部分通过Jimple对3AC有更好的了解。

https://github.com/Sable/soot

Tutorials · soot-oss/soot Wiki · GitHub

1. For循环

        如下图所示将一个for循环的java代码转成3ac,这个例子比较简单,可以直接看懂,额外表注的还有关于传递参数时候的3AC表示。

2. Do-while 循环

        以下是do-while循环的3AC,理解起来也比较简单

3. 方法调用

        方法调用相对复杂一点,首先了解一些JVM的知识。

         JVM中主要的方法调用:

  • invokespecial:用于调用实例构造器<init>()方法、私有方法和父类中的方法
  • invokevirtual:调用非私有实例方法,比如 public 和 protected,大多数方法调用属于这一种,在调用的过程中会进行派生(vitual dispatch)
  • invokeinterface:调用接口方法,会检查实现这个接口的对象,但是调用的时候不能做一些优化
  • invokestatic:调用静态方法,
     
  • Java7: invokedynamic -> Java 是静态语言,动态解析出需要调用的方法,然后执行。

参考:5、JVM中的方法调用 - CarBlack - 博客园 (cnblogs.com)

        ② 方法签名(Method Signature)包含类名、 返回值类型、方法名 (参数1  类型,参数2  类型)

        例如:specialinvoke $r3.<java.lang.StringBuilder: void <init>()>(); 这个构造函数的尖括号里的就是一个方法签名,具体含义就是

  •         方法类型:java.lang.StringBuilder 构造函数
  •         方法名字:默认构造函数没有名字,统一叫<init>
  •         参数:没有参数 () 为空
  •         返回值:没有返回值,void

        再如下图中的3AC意思就是:调用$r3的append 方法,将 r1 加进字符串中

         再看3AC的代码可能就会理解一些了,以下的示例代码是在main函数中调用了foo方法,其中foo方法中有两个参数,返回拼接的字符串,先看foo函数的3AC代码

        main函数的3AC代码

 4. Class 类的3AC

         这里不太明白也没关系,反正再看地址码的时候别怕,仔细分析一定是可以看懂的。

2.5 静态单赋值(Static Single Assignment, SSA)

1. SSA的两个特点:

        ① 如下图,SSA里,会给每个变量不同的名字

        

        ② 但是如果是同一个变量在不同的分支呢?在这种情况下,SSA会在合并的时候,引入一个 \OΦ函数,如下图所示,在引入x2 等于这个 Φ 函数,后续使用x2。这个Φ(x0,x1)会根据流的路径来选择是x0 还是x1然后赋值给x2。

        

2. SSA的优点:

  • 程序流信息可以间接体现在不同的变量名上,通过不同的变量名,流的信息被间接地合并到唯一的变量名中
    •  可能有助于提供一些更简单的分析,例如,流不敏感分析通过SSA定义和使用对显式获得流敏感分析的部分精度。(因为流敏感度分析精度虽然高,但是太耗时了,而流不敏感分析就相当于上下文无关的分析,通过单一赋值制就可以获得很久之前就定义过的信息,知道是具体用了那边信息,就相当于获取到了上下文信息。)
  • Define-and-Use pairs(定义-使用对)明确
    • 在一些按需任务中启用更有效的数据事实存储和传播。
    • 一些优化任务在SSA上表现更好(例如,条件常数传播,全局值编号)。

3. SSA的缺点:

  • 如果程序有太多分叉,则会引入太多变量和Φ函数
  • 在最后还要转为机器码执行,在转换回去的时候由于过多的赋值操作产生性能方面的影响。

2.6 控制流分析(Control Flow Analysis)⭐

  • 在进行控制流分析的时候,通常采用建立控制流图(CFG)
  • CFG是静态分析的基础结构
  • CFG中的节点可以是单个的3AC,不过通常用Basic Blocks(BB),如下图所示

2.6.1(Basic Blocks, BB)——建立节点

1. BB的基本概念:        

        Basic Blocks(BB)是连续的满足以下性质的最大长度三地址指令的组成单元:
           -  这个Block的入口只有一个,就是第一个指令,不能从其他地方进来。
           -  这个Block的出口只有一个,就是最后一条指令,不能从其他地方出去。

         如下图所示,仅能从第一条指令出进去该Block,并且仅能从最后一条指令出去,中间的指令不允许进出,能满足这些性质的、连续的、最大的指令集合就是一个Basic Blocks。
        

2. 举个例子🌰

        如下图所示,怎么样来分代码块呢?
        

  • 首先,程序从(1)入口, (2) 没有其他入口和出口,但是(3) 有额外的入口,即从(11)跳转进入,所以(3) 不能和(1)(2)组合在一起,所以 (1)(2)可以组成一个Basic Block
    ——>得出结论如果一个指令是某个跳转的目标,则该指令只能作为一个BB的入口
  • 在看,(3)作为一个Block的入口,(4)没有入口,有个出口,可以加入,但是(5)不能加入,因为(4)已经有出口了,不能作为一个BB的中间指令,所以(3)(4)可以组成一个Basic Block
    ——>得出结论如果一个指令紧跟着一个跳转,则该指令只能作为一个BB的入口

        

3. 怎么建立BB

        通过上述例子的思考,就可以来尝试设计建立Basic Blocks的算法了,伪代码如下:

INPUT: 一个三地址指令序列 P
OUTPUT: P 的Basic Block列表
Method:
    (1) 确定 P 的入口 (leaders)
        · P 的第一句是一个入口
        · 任何一个跳转的目标指令,是一个入口
        · 任何一个跳转的下一条指令,是一个入口
    (2) 建立BBs for P
        · 每个入口到下一个入口之间就是一个BB

        练习:根据算法的设计思想,再看一下2中的例子,完成程序BBs的划分:

        

4. 将跳转到指令标签替换为跳转到基本块

         经过上述的划分,我们就把一个程序P 分割成了多个BBs,并且由于BB的定义导致跳转目标必定是某个BB的入口指令,所以可以将跳转目标的指令标签的形式,换成BB的编号。如下图所示,将原本的跳转到指令标签(7)替换为跳转到基本块 B4

        

2.6.2 控制流图 (Control Flow Graph, CFG)——添加边

1. 建立边

        在建立完CFG的节点之后,需要添加边(edge),基本规则如下:

  • A--->B 是跳转过去的,则AB 建立一个边,如第一组红色的AB
  • A--->有条件跳转,如第二组的蓝色的A跳转到第一组红B,且蓝A后还有指令蓝B
    • A--->建立一条边(if  goto)
    • A--->B(A紧接着的下一条指令 B) 也需要建立一条边(条件jump block 天然有两出口)
  • A->B 是第三组的绿A无条件跳转到第一组的红B,其中第三组的绿B按原指令紧挨着第三年组的绿A
    • A--->B 建立一条边 (goto)
    • A-×-> B  不建立绿A 向其代码紧挨着的下一条指令的边

        

        完成节点的划分、编号,最后一步就是再按照顺序以及根据上述示例的规则添加上边,将BB连接起来,最后通常,我们在加上Entry Exit,这样就得到了一个控制流图。

        我们还用2.6.1中的例子,为其添加上边,如下图所示。

        

 

2.7 总结

        这一章先讲了编译器与静态分析器的关系,侧重于了解静态分析处在什么位置,主要运用IR进行静态分析,介绍了AST与IR的不同。

         什么是三地址码,并通过soot更清楚的认识真实分析中的3AC。

        介绍CFG的建立步骤,以及Basic Blocks的划分方法,这些静态分析的基础。


🌻写在最后:

    笔者也是软件分析方向的学生, 这个是跟着课程总结和记录的学习笔记, 如果有错误的地方, 欢迎讨论\批评\指正.

   如果有更多关于软件分析领域的资料\论文\课程\建议, 欢迎留言, 一起学习进步~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/579510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloudAlibaba(简介及核心组件使用)

微服务架构常见的问题 一旦采用微服务系统架构&#xff0c;就势必会遇到这样几个问题&#xff1a; 这么多小服务&#xff0c;如何管理他们&#xff1f;服务发现/服务注册---》注册中心 这么多小服务&#xff0c;他们之间如何通讯&#xff1f;Feign -> 基于 http 的微服务调…

使用【Python+Appium】实现自动化测试

一、环境准备 1.脚本语言&#xff1a;Python3.x IDE&#xff1a;安装Pycharm 2.安装Java JDK 、Android SDK 3.adb环境&#xff0c;path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows&#xff0c;官网地址 Redirecting 点击下载按钮会到GitHub的…

使用golang 基于 OpenAI Embedding + qdrant 实现k8s本地知识库

使用golang 基于 OpenAI Embedding qdrant 实现k8s本地知识库 文章博客地址:套路猿-使用golang 基于 OpenAI Embedding qdrant 实现k8s本地知识库 流程 将数据集 通过 openai embedding 得到向量组装payload,存入 qdrant用户进行问题搜索,通过 openai embedding 得到向量,从…

“Jmeter WebSocket协议压测”,助你轻松应对高并发场景!

目录 引言 背景说明 步骤1&#xff1a;安装插件JMeter WebSocket Samplers 步骤2&#xff1a;采集器使用 步骤3&#xff1a;脚本执行 结语 引言 在当今高并发的网络环境下&#xff0c;WebSocket协议已经成为了最受欢迎的实时通信技术之一。然而&#xff0c;对于开发人员来…

CorelDRAW2023序列号及下载安装条件

始于1989年并不断推陈出新,致力为设计工作者提供更高效的设计工具&#xff01;CorelDRAW滋养并见证了一代设计师的成长&#xff01;在最短的时间内交付作品&#xff0c;CorelDRAW的智能高效会让你一见钟情&#xff01;CorelDRAW 全称“CorelDRAW Graphics Suite“&#xff0c;也…

Linux:命令tar、zip、unzip对文件或文件夹进行压缩与解压

Linux&#xff1a;命令tar、zip、unzip对文件或文件夹进行压缩与解压 .tar压缩操作&#xff1a; 创建要进行压缩的文件&#xff1a; 对文件进行压缩&#xff1a; 将三个文件压缩成text.tar文件&#xff0c;压缩到当前路径下(默认也是在当前路径) 对比体积&#xff1a; 发现&…

关于f-stack转发框架的几点分析思考

使用DPDK收包&#xff0c;想要用到TCP协议栈&#xff0c;可选的方案有linux原生的tun/tap口以及DPDK自带的KNI驱动&#xff0c;这两种都是通过将DPDK收到的报文注入到linux内核来使用TCP协议栈的功能&#xff0c;然后&#xff0c;用户态协议栈可以考虑开源的f-stack&#xff0c…

在页面使用富文本编译器

富文本编译器的选择 Editor.mdTinyMCESimpleMDECKEditor 还有一些&#xff0c;这里讲的是我用的TinyMCE 1、下载 下载地址&#xff1a;下载tiny | TinyMCE中文文档中文手册 下载开发版本&#xff0c;我下载的最新版 tinymce_6.4.2_dev.zip 将压缩包解压后可以看到下面目录&…

(哈希表 ) 202. 快乐数——【Leetcode每日一题】

❓202. 快乐数 难度&#xff1a;简单 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到…

Groovy系列一 Groovy基础语法

目录 为什么要学习Groovy Groovy 介绍 Groovy 特点 Groovy 实战 动态类型 简单明了的list,map类型 在groovy世界任何东西都是对象 属性操作变得更容易 GString 闭包 委派&#xff1a;delegate Switch变得更简洁 元编程 强制类型检查 Elvis Operator 安全访问 为…

【五】设计模式~~~创建型模式~~~单例模式(Java)

【学习难度&#xff1a;★☆☆☆☆&#xff0c;使用频率&#xff1a;★★★★☆】 5.1. 模式动机 对于系统中的某些类来说&#xff0c;只有一个实例很重要&#xff0c;例如&#xff0c;一个系统中可以存在多个打印任务&#xff0c;但是只能有一个正在工作的任务&#xff1b;一…

一波三折,终于找到 src 漏洞挖掘的方法了【建议收藏】

0x01 信息收集 1、Google Hack 实用语法 迅速查找信息泄露、管理后台暴露等漏洞语法&#xff0c;例如&#xff1a; filetype:txt 登录 filetype:xls 登录 filetype:doc 登录 intitle:后台管理 intitle:login intitle:后台管理 inurl:admin intitle:index of /查找指定网站&…

C++:征服C指针:指针(二)

指针二 1. 指向数组的指针2. 多维数组三级目录 上一篇文章我们介绍了&#xff1a;什么是指针&#xff0c;指针常见的问题&#xff0c;本篇我们主要介绍 &#xff1a;指针与数组。 1. 指向数组的指针 int *p[n] : 指针数组&#xff0c; 它包括 n 个成员&#xff0c;每个成员都是…

探索Maven创建项目全过程(超详细~~~)

文章目录 1.Maven介绍2.Servlet介绍2.1 Servlet定义2.2 Servlet的主要任务 3.创建Servlet程序步骤3.1 创建项目3.2 引入依赖3.3 创建目录3.4编写代码3.5 打包程序3.6 部署程序3.7 验证结果 4.更方便的部署方式4.1.下载Tomcat插件4.2 配置Tomcat插件4.3运行项目 1.Maven介绍 Ma…

认识Tomcat

hi,大家好,今天为大家带来Tomcat的相关知识 &#x1f36d;1.Tomcat是什么 &#x1f36d;2.Tomcat的下载安装 &#x1f36d;3.Tomcat的目录结构 &#x1f36d;4.启动Tomcat &#x1f36d;5.部署博客系统到Tomcat &#x1f349;1.Tomcat是什么 我们之前也已经学了http,http…

【JAVAWEB】HTML的常见标签

目录 1.HTML结构 1.1认识HTML标签 1.2HTML文件基本结构 1.3标签层次结构 1.4快速生成代码框架 2.HTML常见标签 注释标签 标题标签&#xff1a;h1-h6 段落标签:p 换行标签&#xff1a;br 格式化标签 图片标签 超链接标签&#xff1a;a 表格标签 列表标签 表单标…

Windows 同时安装 MySQL5 和 MySQL8 版本

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是Rockey&#xff0c;不知名企业的不知名开发着 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;联系方式&#xff1a;he18339193956&#xff0c;…

MySQL 00 : MySQL_数据库shell登录时遇到的问题

问题1描述&#xff1a;输入链接数据块的命令提示 sh:mysgl:command not found 解决:第一步配置环境变量来解决 1、vim /etc/profile 2、末尾写入export PATH$PATH:/usr/local/mysql/bin 3、保存 4、执行 source /etc/profile 第二部 问题描述 Mac通过MAMP安装MySQL时&#…

K8s之Replicaset控制器详解

文章目录 一、ReplicaSet 控制器介绍二、ReplicaSet案例1、Pod副本扩缩容案例2、Pod更新版本案例 一、ReplicaSet 控制器介绍 官方中文参考文档&#xff1a; ReplicaSet是k8s中一种资源对象&#xff0c;简写 rs&#xff0c;用于管理Pod副本数量和健康状态&#xff0c;在spec.…

MySQL如何导入大量数据?

有时我们会遇到需要将大量数据导入MySQL的需求&#xff0c;一般数据存储在csv或者txt中&#xff0c;数据由","分隔。这里提供两种方案供大家选择。 一、创建测试表 为了测试&#xff0c;我们先创建数据库和表&#xff0c;并创建一个用户。 create database loadda…