gpt4 book ai didi

java - 在ASM中能否获取putfield或putstatic指令的Field实例?

转载 作者:行者123 更新时间:2023-11-30 09:04:59 25 4
gpt4 key购买 nike

我正在使用 ASM并希望操纵类文件以跟踪某些字段写入。我了解到 putfieldputstatic 指令是 ASM 中 FieldInsnNode 类的实例,我想注入(inject)一些代码来构造一个 Field对象并调用其他方法,将此 Field 对象作为参数。

我通过编译一个简单的 Java 源代码做了一些实验:

package com.test.simple;

public class Simple {
public int a,b;

public void foo() {
a = 20;
b = 10;
}
}

然后使用javap检查类文件:

$ javap -c -l Simple.class 
Compiled from "Simple.java"
public class com.test.simple.Simple {
public int a;

public int b;

public com.test.simple.Simple();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0

public void foo();
Code:
0: aload_0
1: bipush 20
3: putfield #2 // Field a:I
6: aload_0
7: bipush 10
9: putfield #3 // Field b:I
12: return
LineNumberTable:
line 7: 0
line 8: 6
line 9: 12
}

在这里我可以发现 putfield 实际上后面跟着类似 #2 的东西,我猜这是对常量池的引用。 (我有一个更大胆的猜测,常量实际上是 Field 的一个实例)

但是在ASM中,FieldInsnNode只有3个字段(即owner, name, desc)隐藏关于常量字段的所有细节,所以我不知道如何验证我的猜测。

我的问题是:

  • 如果 Field 对象确实位于常量池中,我如何检索它并将其压入 ASM 中的堆栈?
  • 如果我找不到 Field 对象,是否可以使用 FieldInsnNode.nameFieldInsoNode.owner 来实例化一个实例Field 的(因为 Field 没有公共(public)构造函数)?
  • 如果以上所有方法都不起作用,我想我仍然可以打印出 FieldInsnNode.name 这样至少我可以知道指令写入了哪个字段。但看起来所有字符串也都位于常量池中,那么我如何构建一些指令以在运行时实例化字符串?

最佳答案

您可以简单地使用ldc 指令将String 常量从常量池加载到操作数栈。但是,您不能使用 Field 来做到这一点。与您的假设相反,常量池上没有 Field 实例。 JVM 的正常操作不使用反射。

putfield(等)指令的关联常量池条目指的是一个描述符,简单地说,它包含 ASM 提供的信息、所有者类、字段名称及其类型签名。

要从这些信息中获取 Field 实例,您可以使用

ldc owner // a Class instance from constant pool
ldc name // a String instance from constant pool
invokevirtual java/lang/Class getDeclaredField (Ljava/lang/String;)Ljava/lang/reflect/Field; // returns the Field

此处可以忽略 desc,因为反射将简单地返回唯一命名的字段,而不管其类型。

ASM 库提供了构建上述指令序列的方法。请注意,visitFieldInsn 为所有者类提供了一个 Stringyou have to convert to a Type instance在传递给 visitLdcInsn 之前因为您想生成一个 ldc 指令来生成关联的 Class 实例,而不是包含类名称的 String 实例。


为了完整起见,从 Java 7 开始,有可能从常量池包装字段操作中获取 MethodHandle,例如 putfield 用于编译时已知的字段,但生成的句柄仅允许使用其 invoke 方法执行封装字段操作,但不允许检查封装字段的属性。这是为 Java 8 或更新版本保留的,它引入了一个 API method for converting such a MethodHandle to a Field但这并不比上面的三个指令序列简单,它适用于从 Java 5 开始的所有 JVM。

关于java - 在ASM中能否获取putfield或putstatic指令的Field实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25000771/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com