Android5.0中ARM指令中对于类方法的调用的实际跳转地址的计算方法?

软件工程师、主攻高级编程语言虚拟机的设计与实现

27 👍 / 13 💬

问题描述

在Android5,0及其以上的版本,系统会通过dex2oat将应用编译为ARM机器指令来提高执行速度。
而对于ARM指令,我想请问一下对一个类的方法是如何获取他的实际跳转地址的呢?
例如调用telephonymanager.getdeviceid(),其对应的dex code为
iget-object telephonymanager;
invoke telephonymanager.getdeviceid

其实际的跳转地址在我的写的应用中的 获取过程为 :
 [r1,#16]->r5,
 r5->r1 
 [r1,#0]->r0 
 [r0,#572]->r0 
 [r0,#40]->lr 
 blx lr 

所以我想请问一下这一段获取其实际跳转的地址的具体意义,其中这些数值 如16 572等是如何计算出来的, 麻烦大家帮忙解释一下,如果给一份学习资料也是挺好的,因为我现在找到的所有关于arm调用的资料都是 函数的调用,而对这种类的方法的调用所讲的比较少。

好奇一下,题主是用哪种办法查看ART编译出来的机器码的?oatdump么?

题主帖的那段代码其实挺明确的,就是个普通的基于vtable的虚方法调用而已:

[r1,#16]->r5,     ;; r5:TelephonyManager = this.telephonymanager
r5->r1            ;; r1:TelephonyManager = r5
[r1,#0]->r0       ;; r0:Class = telephonymanager.klass_
[r0,#572]->r0     ;; r0:ArtMethod = r0+vtable_offset+vtable_offset_of(getdeviceid)
[r0,#40]->lr      ;; lr = r0.entry_point_from_quick_compiled_code_
blx lr            ;; call telephonymanager.getdeviceid

其实跟C++的基于vtable的虚函数调用非常相似。

只不过ART里对象的虚函数表(vtable)被嵌在Class对象的末尾,而对象实例开头的字段指向的是这个Class对象而不是像C++的常见实现那样指向vtable的第0项。

另外ART的vtable里每一项装的不直接是函数的“入口地址”(因为可能有多种入口),而是一个指向ArtMethod对象的指针。真正的“入口地址”存在ArtMethod的字段里。

这些对象之间的引用关系是这样的:

          Object                Class
 +0 [ klass_          ] -->   [ ...       ]
    [ monitor_        ]       [ ...       ]
    [ instance fields ]       [ vtable[0] ]
                              [ vtable[1] ]
                              [ ...       ]                      ArtMethod
                              [ vtable[n] ] -->   [ ...                                   ]
                              [ ...       ]       [ ...                                   ]
                                                  [ entry_point_from_quick_compiled_code_ ] --> [ compiled code ]
                                                  [ ...                                   ]

可以看到vtable被嵌入在Class对象之中,而vtable里的项是指向ArtMethod的指针。

例子中的数字,

在ART的一些相关的runtime代码: