Android Multidex 方法调用
Android Multidex method invocation
我对 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 文件其他地方的 table 的索引,它给出了方法名称、类型签名和 class。该方法可以在任何地方定义,甚至可以在另一个 dex 文件中定义,或者是系统 classes 之一的一部分。任何给定的 dex 文件最多只能引用 65k 个方法,但是多个 dex 文件可以引用不同的方法集,因为它们包含自己的 table 方法描述符。
根据:"Basically, how does it know the code offset and how does it know which dex file the method is located?"
请考虑这些 dex 文件是 "intermediate" 由 VM (ART) 或编译器 (dex2oat) 解释或编译的文件。这意味着,没有 ELF 或 MACH-O 文件中的 "offset" 或重定位 table。
正如 Antimony 所解释的那样,invoke 调用中的 id 只是单个 dex 文件的 ref table 中的一个索引。此 ref table 将 class 名称、方法名称和签名映射到索引。最后,VM 加载所有 dex 文件并在内存中创建 table 个 class es 和方法。如果 invoke(..) get 被调用,它会检查 dex 文件的 ref table 并获取 taret 方法、class 名称和签名。现在它在内存中搜索这三个值并调用。
请考虑到您必须处理将中间语言转换为体系结构相关代码的 VM,网址为:
* 运行时(解释器模式)
* 运行时但必要时缓存 ("Just in time")
* 在安装您的应用程序期间 ("Ahead of time")
请检查: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
这里可以看到"constant pool"。
在 INDEX #3 处,您有 java/lang/Boolean.parseBoolean:(Ljava/lang/String;)Z 的方法引用(正如我告诉 Class、方法和签名)。 VM、jit 或 aot 读取此值并在运行时在内存中检查 table 中的 class,其中表示所有中间文件的所有 classes。
重要的是class路径指向所有必要的中间体。否则你会得到一个 "ClassNotFound" 异常。它记得运行时链接器搜索符号名称并填充二进制文件的重定位 table 是的,但它在技术上完全不同。
我对 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 文件其他地方的 table 的索引,它给出了方法名称、类型签名和 class。该方法可以在任何地方定义,甚至可以在另一个 dex 文件中定义,或者是系统 classes 之一的一部分。任何给定的 dex 文件最多只能引用 65k 个方法,但是多个 dex 文件可以引用不同的方法集,因为它们包含自己的 table 方法描述符。
根据:"Basically, how does it know the code offset and how does it know which dex file the method is located?"
请考虑这些 dex 文件是 "intermediate" 由 VM (ART) 或编译器 (dex2oat) 解释或编译的文件。这意味着,没有 ELF 或 MACH-O 文件中的 "offset" 或重定位 table。
正如 Antimony 所解释的那样,invoke 调用中的 id 只是单个 dex 文件的 ref table 中的一个索引。此 ref table 将 class 名称、方法名称和签名映射到索引。最后,VM 加载所有 dex 文件并在内存中创建 table 个 class es 和方法。如果 invoke(..) get 被调用,它会检查 dex 文件的 ref table 并获取 taret 方法、class 名称和签名。现在它在内存中搜索这三个值并调用。
请考虑到您必须处理将中间语言转换为体系结构相关代码的 VM,网址为: * 运行时(解释器模式) * 运行时但必要时缓存 ("Just in time") * 在安装您的应用程序期间 ("Ahead of time")
请检查: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
这里可以看到"constant pool"。 在 INDEX #3 处,您有 java/lang/Boolean.parseBoolean:(Ljava/lang/String;)Z 的方法引用(正如我告诉 Class、方法和签名)。 VM、jit 或 aot 读取此值并在运行时在内存中检查 table 中的 class,其中表示所有中间文件的所有 classes。
重要的是class路径指向所有必要的中间体。否则你会得到一个 "ClassNotFound" 异常。它记得运行时链接器搜索符号名称并填充二进制文件的重定位 table 是的,但它在技术上完全不同。