入门ART虚拟机(7)——TLS Entry Points

Android安全交流群:478084054

前面笔记贴过老罗博客的一段话(非原文,简化了一下):

“ART运行时会为类方法生成相应的本地机器指令,这些本地机器指令可能会调用外部函数,这就涉及到模块依赖问题,就好像我们在编写程序时,需要依赖C库提供的接口一样。ART运行时支持两种类型的Backend:Portable和Quick。Portable类型的Backend通过静态链接器生成本地机器指令,通过重定位技术来处理模块依赖问题。这对熟悉linker动态加载过程的程序员来说很容易理解。而Quick类型的Backend生成的本地机器指令用另外一种方式来处理模块之间的依赖关系。简单的说,就是ART运行时会在每一个线程的TLS(线程本地区域)提供一个函数表,本地机器指令通过它来调用其它模块的函数。这使得生成的OAT文件在加载时不需要再处理模块之间的依赖关系,也就省去了重定位,不需要通过系统的动态链接器提供的dlopen来加载。这样OAT文件在加载时就会更快,这也是称其为Quick的缘由。”

本篇笔记就看看这段话中提到的TLS函数表(还是以6.0源码为例)。

在ART初始化过程中的Runtime::Init函数中,有如下代码:

入门ART虚拟机(7)——TLS Entry Points_第1张图片

作用是将当前线程注册到ART运行时的线程列表中。

入门ART虚拟机(7)——TLS Entry Points_第2张图片

继续看Thread::Init函数。

入门ART虚拟机(7)——TLS Entry Points_第3张图片

最后调用thread_list->Register(this),就是将当前线程注册到ART运行时的线程列表中去。

在这之前,还有一步:InitTlsEntryPoints(),在InitTlsEntryPoints中调用InitEntryPoints。

入门ART虚拟机(7)——TLS Entry Points_第4张图片

调用InitEntryPoints时传入的:interpreter_entrypoints、jni_entrypoints、quick_entrypoints三个参数,就是老罗那段话中提到的TLS保存的用于解决模块依赖关系的函数表。

这些函数表在InitEntryPoints函数中被初始化。

继续看InitEntryPoints(以arm版本为例)。

入门ART虚拟机(7)——TLS Entry Points_第5张图片

首先初始化interpreter_entrypoints,保存的是解释器要用到的跳转函数。

只包含两项,分别是artInterpreterToInterpreterBridge和artInterpreterToCompiledCodeBridge。前者用于从一个解释执行的类方法跳到另一个也是解释执行的类方法去执行,后者用于从一个解释执行的类方法跳到另一个以本地机器指令执行的类方法去执行。

然后初始化jni_entrypoints,保存的是JNI调用相关的跳转函数。

如果在生成的本地机器指令中,需要调用一个JNI函数,那么就需要先通过art_jni_dlsym_lookup_stub找到正确的JNI函数,然后再执行。

剩下的就都是quick_entrypoints的初始化了,覆盖了所有的Quick后端生成的本地机器指令要用到的跳转函数。

入门ART虚拟机(7)——TLS Entry Points_第6张图片
入门ART虚拟机(7)——TLS Entry Points_第7张图片
入门ART虚拟机(7)——TLS Entry Points_第8张图片
入门ART虚拟机(7)——TLS Entry Points_第9张图片

其中包含了art_quick_to_interpreter_bridge,用于从一个以本地机器指令执行的类方法跳到另一个解释执行的类方法去执行。

这些跳转表中有很多bridge和trampoline函数,我很想知道它们到底是怎么工作的。后面再去看吧。

感谢老罗博客。

你可能感兴趣的:(入门ART虚拟机(7)——TLS Entry Points)