在每次呼叫特定方法之前使用ASM注入字节码

发布于 2025-02-13 20:02:30 字数 927 浏览 0 评论 0原文

如何重写类(最好使用ASM),以使setupspecial()调用是在每个调用special> special(int)之前引入调用的?

public class Application {

    public void f() {
         System.out.println("A");
         // setupSpecial(); ← to be added
         special(1);
         System.out.println("B");
         // setupSpecial(); ← to be added
         special(2);
         System.out.println("C");
         // setupSpecial(); ← to be added
         special(3);
    }

}

请注意,special()setupspecial()不是application的成员。

我可以将classVisitor+methodVisitor组合和截然呼叫通过覆盖> vistmethodinsn(opccodes.invokevirtual,com),“ com” /acme/magic“,“ special”,“()v”,false),尽管这将为时已晚,因为类型整数的方法已经通过visitintinsn(opcodes.bipush,int)。我需要一种方法来说“现在我看到了special()!滚动回电,打开魔术并再次继续进行的调用。”

How can I rewrite a class (preferably using asm) such that a setupSpecial() invocation is introduced before every single call to special(int)?

public class Application {

    public void f() {
         System.out.println("A");
         // setupSpecial(); ← to be added
         special(1);
         System.out.println("B");
         // setupSpecial(); ← to be added
         special(2);
         System.out.println("C");
         // setupSpecial(); ← to be added
         special(3);
    }

}

Note that both special() and setupSpecial() are not members of Application.

I can pass a ClassVisitor+MethodVisitor combination and intercept calls to special(int) via overriding visitMethodInsn(Opcodes.INVOKEVIRTUAL, "com/acme/Magic", "special", "()V", false), though this will be too late since the method argument of type integer is already passed via visitIntInsn(Opcodes.BIPUSH, int). I need a way to say "Now I see the call to special()! Roll this call back, turn magic on, and proceed again."

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆光飞翔i 2025-02-20 20:02:30

JVM具有基于堆栈的体系结构,因此您无需担心special(int)调用的参数。如果您只需准备setupspecial()呼叫special(int)呼叫

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
    if ("com/example/Magic".equals(owner) && "special".equals(name)) {
        visitMethodInsn(Opcodes.INVOKESTATIC, "com/example/Magic", "setupSpecial",
                Type.getMethodDescriptor(Type.VOID_TYPE), false);
    }
    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

: /code>要静态,但没关系),您将获得与以下类似的字节码:

0: getstatic     #24                 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc           #30                 // String A
5: invokevirtual #32                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: invokestatic  #68                 // Method setupSpecial:()V
12: invokestatic #38                 // Method special:(I)V

如您所见,special(int)呼叫的参数在堆栈上按 setupspecial(),这是不寻常的。但是,一旦setupSpecial()完成,它仍然将位于堆栈的顶部,因此,只要setupSpecial()不返回任何值,一切就可以正常工作。

如果是这样,您需要添加pop/pop2 opcode将其从堆栈中删除。

The JVM has a stack-based architecture, so you don't need to worry about the parameters to the special(int) call. If you simply prepend the setupSpecial() call to the special(int) call using:

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
    if ("com/example/Magic".equals(owner) && "special".equals(name)) {
        visitMethodInsn(Opcodes.INVOKESTATIC, "com/example/Magic", "setupSpecial",
                Type.getMethodDescriptor(Type.VOID_TYPE), false);
    }
    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

(I assume both special and setupSpecial to be static, but it does not matter), you'll obtain bytecode similar to this:

0: getstatic     #24                 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc           #30                 // String A
5: invokevirtual #32                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: invokestatic  #68                 // Method setupSpecial:()V
12: invokestatic #38                 // Method special:(I)V

As you can see, the parameter to the special(int) call is pushed on the stack before the call to setupSpecial(), which is unusual. However it will still be at the top of the stack once setupSpecial() has finished, so everything will work just fine as long as setupSpecial() does not return any value.

If it does, you'll need to add a pop/pop2 opcode to remove it from the stack.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文