java家族有java、kotlin、groovy等,而c家族有c、cpp、objective c/c++等,java家族的编译器有javac、kotlinc等,c家族编译器有gcc、llvm等,而编译器前端与编译器后端还出现了一些著名且影响很广的项目clang、gas、smali,让我们先从编译器的前端开始这趟路程。

java家族与c家族编译器的工作流程

  • javac/kotlinc: java/kotlin(高级语言)--->语法解析---> 字节码(二进制文件.class or .dex)
  • gcc/llvm: cpp(高级语言)--->语法解析--->汇编(低级语言)---> 机器码(二进制文件elf)

编译器分为前端和后端,前端主要是对源代码语法的处理,转换成语法树,后端则是关注字节码或者机器码的生成。开源项目llvm的clang项目就是编译器前端,是c家族语法的解析,而llvm项目早期主要是聚集在编译器后端,处理x86、arm等指令,只不过随着项目壮大clang、lld等项目产生逐渐变成一个构建编译器的工具箱。

kotlin编译

编译流程

kotlin源代码 –> 词法分析器 –> Token流 –> 语法分析器 –> 语法树/抽象语法树 –>语义分析器 –> 注解抽象语法树 –> 字节码生成器 —> JVM字节码

  1. 词法分析器:使用JFlex开源库,_JetLexer(KotlinLexer)代表词法分析器
  2. 语法分析器(syntax parser):使用InteliJ项目中的PsiParser(KotlinParser),并且生成AST
  3. 语义分析(semantic analyzer):检查AST 上下文相关属性,并且生成中间代码。org.jetbrains.kotlin.resolve包下为语义分析,org.jetbrains.kotlin.ir包下为中间代码生成
  4. 目标代码生成:org.jetbrains.kotlin.codegen

编译器前端与后端

  • 编译前端: build syntax tree and semantic info
  • 编译后端: generates target/machine code
/**
 *                      frontend
 * source code --> [ parser  -- syntax tree ---> semantic analyzer ] 
 *
 * -- syntax tree + semantic info -->
 *
 *       backend
 * -->  [intermediate code:generator & optimizer -- intermediate representation --> machine code:generator & optimizer ] 
 *
 * -- target/machine code
 *
 * kotlin在编译后端自动生成set/get代码(PropertyCodegen),修改类为final
 */

汇编器Smali/GAS

什么是汇编语言 : 一种相对于高级语言最接近机器语言的低级语言,所以性能毋庸置疑,开发效率低。编译成机器码的汇编器有GAS(即GNU AS汇编编译器,基于AT&T syntax指令,生成.s文件)、NASM(基于Intel syntax指令,生成.asm文件)、MASM(Windows平台下的汇编编译器,也使用Intel风格),机器码的汇编语言风格有Intel和AT&T之分,编译成Java字节码的汇编器有Jasmin和Smali。Smali是anroid虚拟机字节码的汇编器,GAS是android机器码的汇编器

Smali

如果你遇到没有源码的应用,又要对其进行修改,那么会使用Smali的汇编指令就很有必要了,而在没办法修改源代码,通过修改字节码(或者机器码)对应的反汇编代码,去改变应用逻辑的做法,就叫做插桩,属于静态二进制插桩(gralde transform也属于静态二进制插桩,inline hook属于动态二进制插桩)。哪些工作内容会用到插桩这门技术呢? 可以看一下这篇文章基于原厂ROM移植MIUI

想要了解更多关于Smali就要具有一定知识储备。

  • 什么是Jasmin :jasmin是一款针对官方Java虚拟机(JVM)的汇编器。.j <---> .class
  • 什么是Smali : smali是一款针对Android平台JVM(Dalvik)的汇编器。 .smali <---> .dex 。其已经被开源到AOSP的external/smali目录下,但是由于中国的环境,没办法轻松获取到这个工具集,google已经将其开源到github上面了,并由google工程师Ben Gruver负责。

了解了这些内容,就可以简单的判断smali就是一款用于Dalvik虚拟机的汇编器,其反汇编器叫做baksmali,所以apktool其实是smali/baksmali的封装,兼具汇编和反汇编的功能。并且smali汇编器的语法是基于jasmin汇编器的语法。那为什么两者的语法却有点不同 ? 最终归结于虚拟机的不同导致的,官方虚拟机是基于内存中的堆栈实现,而Dalvik虚拟机是基于cpu的寄存器实现,但是jasmin的汇编语言理念被保留了下来。

GAS

参考

Professional Assembly Language

[Quora]What is smali in Android ?

llvm

Kotlin 源代码编译过程分析

k2视频讲述

GCC 汇编分析

ARM Assembly By Example

C语言与汇编混合编程

如果您觉得写得还不错或者对您有所启发,那就赶紧动动您的小指头,点击下面的红色按钮,狠狠地打赏一番吧。