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

在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…
关注者
49
被浏览
1463
好奇一下,题主是用哪种办法查看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的指针。

例子中的数字,
  • 16:这是题主给出的例子中this对象里telephonymanager字段所在的偏移量。dex2oat将一个Java类转换为ART能理解的形式时会为其计算Class元数据的内容布局,确定元数据的数量、种类和位置,例如说vtable有多少项,分别都是哪些方法;以及对象实例的内存布局,确定所有Java字段在对象中的偏移量。
  • 0:这是ART中Java对象的klass_字段的偏移量,指向Class对象
  • 572:这是在Class对象中vtable的偏移量加上getdeviceid()方法对应的项在vtable中的偏移量。在Class对象中的这个偏移量读到的就是getdeviceid()对应的vtable项——一个ArtMethod指针
  • 40:从ArtMethod中找到“入口地址”。这是个普通的C++字段,这个偏移量是由C++编译器算出来的。

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