我对Android中的Multidex有疑问。给定一个包含多个Dex文件(classes.dex,classes2.dex)的应用程序,调用如何在字节码中工作?
由于调用指令中引用的方法ID仍为16位(来自https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions:]
直接调用{vC,vD,vE,vF,vG},meth @ BBBB
A:参数字数(4位),B:方法参考索引(16位),C..G:参数寄存器(每个4位)
那么,classes2.dex中定义的方法如何引用或更重要的是调用classes.dex或classes3.dex中定义的方法?
问候,
罗兰
根据:“基本上,它如何知道代码偏移量,以及如何知道该方法位于哪个dex文件?”
请注意,这些dex文件是由VM(ART)或编译器(dex2oat)解释或编译的“中间”文件。这意味着,没有ELF或MACH-O文件中的“偏移”或重定位表。
正如锑所解释的那样,invoke调用中的id只是单个dex文件的引用表中的索引。该引用表将类名称,方法名称和签名映射到索引。最后,VM加载所有dex文件,并在内存中创建类和方法的表。如果调用invoke(..)get,它将检查dex文件的引用表并获取taret方法,类名和签名。现在,它在内存中搜索这三个值并调用。
请注意,您必须在以下位置处理将中间语言转换为体系结构依赖代码的VM:*运行时(解释器模式)*运行时,但在必要时进行缓存(“及时”)*在安装应用程序期间(“提前”)
请检查:https://source.android.com/devices/tech/dalvik/configure
这里有另一个示例,但是使用了JVM(意味着java操作码):
public final class org.chickenhook.binderfuzzy.BuildConfig
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
#1 = Methodref #6.#32 // java/lang/Object."<init>":()V
#2 = String #33 // true
#3 = Methodref #34.#35 // java/lang/Boolean.parseBoolean:(Ljava/lang/String;)Z
#4 = Fieldref #5.#36 // org/chickenhook/binderfuzzy/BuildConfig.DEBUG:Z
#5 = Class #37 // org/chickenhook/binderfuzzy/BuildConfig
#6 = Class #38 // java/lang/Object
#7 = Utf8 DEBUG
#8 = Utf8 Z
#9 = Utf8 APPLICATION_ID
#10 = Utf8 Ljava/lang/String;
#11 = Utf8 ConstantValue
在这里您可以看到“常量池”。在INDEX#3处,您具有对java / lang / Boolean.parseBoolean:(Ljava / lang / String;)Z的methodref(正如我告诉的Class,方法和签名)。 VM,jit或aot会读取此值,并在运行时在内存中检查表中表示所有中间文件的所有类的表中的类。
重要的是,类路径指向所有必要的中间体。否则,您将获得“ ClassNotFound”异常。它记得运行时链接程序在搜索符号名称并填充二进制yes的重定位表时所花的一点点时间,但是从技术上来说,它的完成方式有所不同。
方法索引只是指向dex文件其他地方包含的表的索引,该表提供了方法名称,类型签名和类。该方法可以在任何地方定义,甚至可以在另一个dex文件中定义,也可以是系统类之一的一部分。任何给定的dex文件最多只能引用65k个方法,但是由于多个dex文件包括它们自己的方法描述符表,因此可以引用不同的方法集。]