跳至主要内容

LLVM学习基础之编译原理学习(一):语言

https://ift.tt/2pWfSHe

程序设计语言

现在除了底层人员,一般的开发人员所说的程序语言都是高级语言了,但是对于安全人员,底层开发人员来说远不止这些,主要有下面

  • 高级语言
    就是现在所通用的类人类语言的编程语言,比如c,c++,python,ruby这种。书写代码通俗易懂
  • 汇编语言
    对于逆向人员这个真是再熟悉不过了,就不多说了。汇编语言是针对CPU架构来说的
  • 机器语言
    这个也很好理解,就是字节码,汇编语言其实是对字节码的封装再解释

语言的转换

  • 翻译
    把某种语言的源从程序,在不改变语意的条件下,转换成另外一种语言程序:目标语言程序
  • 编译
    专门由计算机的高级语言转为低级语言,就是把整个程序都翻译过来
  • 解释
    接受某高级语言的一个语句输入,进行解释并控制计算机执行,马上得到这句的执行结果,然后再接受下一句

编译的转换过程

  • 两阶段转换
    编译 ---> 运行
    
    

    这种转换的时候,通过编译器直接把源程序转换为机器语言,目标程序可直接执行

  • 三阶段转换
    编译 ---> 汇编 ---> 运行
    
    

    当进行这种转换的时候,编译器编译的时候回首先产生汇编文件,然后通过汇编文件的编译器再生成目标文件

    1. 编译时:
      源程序——>编译程序->汇编语言
    2. 汇编时:
      汇编程序-> 目标代码

    3. 运行时:
      初始数据->运行子程序目标代码->计算结果

编译程序概述

自然语言的翻译

  1. 先识别句子中的一个个单词
  2. 分析句子的语法结构
  3. 根据句子的含义进行初步翻译
  4. 写出最后的译文

其实编译器的原理跟自然语言的原理一模一样,什么事情只要找一件我们能够理解的事情最对比,就迎刃而解了

编译程序的工作

通过对自然语言的翻译,我们可以总结归纳出把高级语言转换为低级语言的整套历程,下面就对其每个步骤进行一个大概的介绍

词法分析

  • 任务
    输入源程序,对构成源程序的字符串进行扫描和分解,识别出一个个的单词,转换成统一规格,备用。
    
    

那么上面的就的话就印出来几个基本概念,下面一一来解释:

  • 单词
    • 是高级语言中有实在意义的最小语法单位,它由字符构成
  • 现在高级语言一般的单词构成
    • 基本字(保留字)
    • 标示符
      用户自己定义的符号
    • 常整数
    • 运算符
    • 界限符
      括号,逗号什么的,能表示程序开始或者结束或者其他状态的符号
  • 转换
    • 对基本字,运算符,界限符的转换
      • 对于这类,都是有限的,可以内置好
    • 标示符的转换
    • 常数的转换
    • 转换后的格式:
      类号 内码
      描述词法规则的有效工具是 正规式和有限自动机

正规式:正则表达式,表示正规集的工具
有限自动机:是一段程序,自动进行语法分析
正规式和有限自动机

语法分析

  • 任务
    在语法分析的基础上,根据语言的语法规则,把单词符号组成各类的语法单位:短语,子句,语句,过程,程序。
    
    

从任务的描述中,又引出了几个概念,首先介绍一下什么叫语法规则:

  • 语法规则
    就是语言的规则,又称为文法;规定单词如何构成短句,语句,过程和程序。
    • 语法规则(文法)的表示
      \(BNF: A::=B|C\)
      上面的公式叫做巴科斯范式
      其中 \(A::\) 在这里表示的意思是定义为,那么整句话的意思就是A定义为B或C。可以跟我们学习英文或者中文的时候做个联想,比如 句子定义为主谓宾 是一个道理。
语法举例:等号赋值语句的语法规则

\(A::=V=E\)

首先上面的公式表示为:A定义为V赋值为E.
其中V又被定义为标示符,这里的意思也就是说把E这个东西赋值给标示符,这种情况就杜绝了赋值号左边是表达式的情况。
那么E又等是什么呢,E是表达式,\(E::=T|E+T\),其中T又可以定位为\(T::=F|T*F\),F又定义为\(F::=V|(E)|C\).V上面已经说过了是标示符,C是常数,那么整个式子就推到下来了

语法分析的方法

语法分析主要有2个指导性的方法:推导(derive)归约(reduce)

推导

主要分为 最左推导最右推导两种。
首先看一下最左推导

  • 最左推导
    简单点来写就是每次把右边的大写字母,按照规则转换成另外一种东西。
  • 举例:
    \(A==>V=E\) 等号赋值运算表达式如上,推导出\(x=a+b*50\)

    最左推导的逆过程就是最右归约。

因此就有了下面的规律:

  • 最左推导,最右规约
  • 最右推导,最左规约

语义分析和中间代码生成

语法分析的过程也可以作为用一颗倒着的树来分析,这颗树就叫做语法树。

这是之前推导过的式子,用树状来进行表达了

中间代码
  • 任务
    对语法分析识别出各类语法范畴,分析其含义,进行和初步翻译,产生于介于源代码和目标代码之间的一种代码。
    
    

在进行中间代码生成的时候,主要有2个节点的工作:

  • 对每种语法范畴进行静态语义检查
  • 若语义正确,就进行中间代码的翻译
    同时在中间代码生成的时候,只要有3中生成规则,它们分别是:
  • 四元式
  • 三元式
  • 逆波兰式

暂时举个例子先来了解下什么是四元式:
将\(x=a+b*50\)变成中间代码,下图就是最四元式的诠释:

首先,第一步得把50转换为实常数,我们把转换后的结果用T1来表示,现在整个式子变成了\(x=a+b*T1\),紧接着我们来计算\(b*T1\),通过上表的步骤2我们可以看到,*是运算符,b是做操作数,T1是右操作数,T2是计算后的结果,凡是符合构成算符,左操作数,右操作数,结果这种格式的生成方法,就叫做四元式。

优化

  • 任务
    对前面产生的中间代码进行加工变换 ,以期在最后阶段能产生更为高效的代码。
    
    
  • 原则
    等价交换
    
    
  • 考虑优化的方面
  1. 公共子表达式的提取
  2. 合并已知量
  3. 删除无用语句
  4. 循环优化

目标代码生成

  • 任务
    把经过优化的中间代码转换成特定机器上的低级语言代码
    
    
  • 目标代码的形式
  1. 绝对指令代码
  2. 汇编指令代码
  3. 可重定位指令代码

END &补充

至此正编译器的流程已经大概介绍完了,但是我们发现生成流程表上还有表格管理出错处理这两个模块,那这是干什么呢?下面就补充一下:

表格管理

用来记录源程序的各种信息以及编译过程中的各种状况,会产生表格的主要是编译的前三个阶段,一般来说会产生下面几种表:

  • 符号表
  • 常数表
  • 标号表
  • 入口函数表

出错处理

  • 任务

    如果有源程序有错误,编译程序应设法发现错误,并报告给用户

  • 完成

    由专门的出错程序来完成

  • 错误类型

    • 语法错误
      在语法分析和词法分析阶段检测出来
    • 语义错误
      一般在语义分析阶段检查出来

The post LLVM学习基础之编译原理学习(一):语言 appeared first on cole.

https://ift.tt/2NNefoS LLVM, 编译原理&LLVM, 编译原理学习 October 18, 2018 at 10:46AM

评论

此博客中的热门博文

反Hook 之自己实现GetProcAddress和LoadLibraryA(c++ version)

http://ift.tt/2AocAD0 // 课上练习.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> //要实现的功能: /* 自己实现GerProcAddress LoadLibraryA */ //思路: /* GerProcAddress和LoadLibraryA都是在Kernel32.dll中的 首要的任务就是找到Kernel32.dll,然后遍历IAT就能找到这两个函数 现在首要的难点就是如何找到kernel32.dll() 通过dll的加载顺序可以找到,而且虽然需要使用未文档化的API,但是好在windgb可以直接看,而且用到的也并不是很多 懒得去晚上搜了,直接自己实现一个得了,作为演示,能用就行(最好还是搜一个正规的结构体) */ /* 0: kd> dt _TEB /a nt!_TEB +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB //首先实现部分TEB结构体,因为只需要用的PEB的部分,所以实现到这就ok了 */ //构建 TEB typedef struct _TEB { //保证0x30是peb的结构体就ok了 struct _tem { DWORD a1; DWORD a2; DWORD a3; DWORD a4; DWORD a5; DWORD a6; DWORD a7; DWORD a8; DWORD a9; DWORD a10; ...

IDA动态调试ELF中遇到的问题(1)

https://ift.tt/2Gxnf2F 遇到 got SIGCHLD singal(child status has changed)...这种提示 singal fork了子进程 直接点yes,然后继续单步执行,出来提示 pass to application就行了 内存查看 用od习惯了之后,凡事都想右键看一下内存,但是IDA中好像没有那么如意, 目前只是在栈中右键发现有查看hex的选项 动态调试的时候的nop ida保存动态调试的时候修改的数据 方法一:在程序运行的时候保存 The post IDA动态调试ELF中遇到的问题(1) appeared first on cole . https://ift.tt/2q9Qf5g WHATEVER April 05, 2018 at 09:44AM

数据库(MySQL)编程之数据库和表的基本操作

http://ift.tt/2gOXg6X     数据库和表的基本操作 操作前的基本知识 基本 sql语句不区分大小写(关键字建议用大小写),但字符串常量区分大小写 sql语句可单行或多行书写,以; 结尾 关键字不能跨行或简写 可以用空格或者缩进来提高可读性 注释 sql标准 /**/ : 多行注释 "--":单行注释 mysql 标准: "#":单行注释 "COMMENT":为字段或列添加注释 创建和查看数据库 创建数据库 模板 CREATE DATABASE [IF NOT EXISTS ] db_name create_specification: IF NOT EXITSTS : 检查数据库是否存在,如果存在就不创建 creat_specification :创建条件 CHARACTER SET: 制定数据聚采用的字符集 COLLATE :制定数据库字符集的比较方式 DEFAULT :表示默认内容,即使没有制定该项,也有默认的值 # 创建数据库使用字符集为 UTF-8 ,使用规则为 uftf_bin CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE uft8_bin; 一般默认的数据库就是utf8 和utf8_bin的比较方式,因此一般创建数据库的时候都用 CREATE DATABASE db_name mysql> create database testdb; Query OK, 1 row affected (0.02 sec) 查看数据库 命令 SHOW DATABASES     mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sakila | | sys | | testdb | |...