首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >尝试构建java字节码的反编译程序,并且不知道在何种情况下“堆栈映射框架”不会碰巧是"FRAMSAME“

尝试构建java字节码的反编译程序,并且不知道在何种情况下“堆栈映射框架”不会碰巧是"FRAMSAME“
EN

Stack Overflow用户
提问于 2016-09-06 15:14:55
回答 2查看 170关注 0票数 2

java代码段

代码语言:javascript
复制
    int x4(int a) {
    if(a>7){
        System.out.println("a>7");
    }


    if(a==0){
        System.out.println("a==0");
    }else if(a>77){
        System.out.println(" a>77");
    }else if(a>44){
        System.out.println(" a>44");
    }else{
        System.out.println("otherwise");
    }

    return 44;
}

字节码大纲:

代码语言:javascript
复制
// access flags 0x0
x4(I)I
// parameter  a
L0
ILOAD 1
BIPUSH 7
IF_ICMPLE L1  ---- operand stack is empty here , end of a statement
L2 ---- new statement mark
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a>7"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
FRAME SAME ---- branching place start with empty operand stack
ILOAD 1
IFNE L3
L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a==0"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L5
GOTO L6
L3
FRAME SAME ---- branching place start with empty operand stack
ILOAD 1
BIPUSH 77
IF_ICMPLE L7
L8
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC " a>77"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L9
GOTO L6
L7
FRAME SAME ---- branching place start with empty operand stack
ILOAD 1
BIPUSH 44
IF_ICMPLE L10
L11
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC " a>44"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L12
GOTO L6
L10
FRAME SAME ---- branching place start with empty operand stack
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "otherwise"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L6
FRAME SAME ---- branching place start with empty operand stack
BIPUSH 44
IRETURN
L13
// access flags 0x0
x4(I)I
// parameter  a
L0
ILOAD 1
BIPUSH 7
IF_ICMPLE L1
L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a>7"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
FRAME SAME ---- branching place start with empty operand stack
ILOAD 1
IFNE L3
L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a==0"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L5
GOTO L6
L3
FRAME SAME ---- branching place start with empty operand stack
ILOAD 1
BIPUSH 77
IF_ICMPLE L7
L8
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC " a>77"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L9
GOTO L6
L7
FRAME SAME ---- branching place start with empty operand stack
ILOAD 1
BIPUSH 44
IF_ICMPLE L10
L11
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC " a>44"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L12
GOTO L6
L10
FRAME SAME ---- branching place start with empty operand stack
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "otherwise"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L6
FRAME SAME ---- branching place start with empty operand stack
BIPUSH 44
IRETURN
L13

当操作数堆栈被“赋值”"operation+assignment“”跟随控制“”方法调用“清空时,一个新的标签将标记一个新的”语句行“。

“跟踪控制”块是“语句”的集合,当一个块(标记为“跳转指令”)结束时,它也将是一个“语句”结尾,因此操作数堆栈对于该块的后续代码或交替分支来说为空.

因此,在我看来,对于编译后的java源代码来说,“标记为‘跳转指令’的代码”将是“框架相同”的任何情况。

但我知道情况不会这样。否则,堆栈映射帧将不会被设计成字节码。

请专家们,非常感谢,给我的例子,非框架相同的分支,并解释直观。

非常感谢,请帮忙。请帮帮忙。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-07 09:54:44

如果您只想反编译,即打印指令序列,您可以简单地忽略堆栈帧。它们只提供关于操作数堆栈上的项类型和局部变量的信息。如果不打印这些类型,则不需要解析它们。

如果您只使用分支语句,那么在分支的两端确实没有操作数堆栈条目,但是您没有遇到局部变量更改的原因仅仅是在示例代码中没有这样的更改。

考虑:

代码语言:javascript
复制
for(int i=0; i<10; i++)
    System.out.println(i);

在这里,变量i已经添加到循环分支的堆栈框架中,因此您可能会遇到一个F_APPEND框架(编译器被鼓励,但不需要使用最紧凑的形式)。同样,当添加另一个后续分支时,如

代码语言:javascript
复制
for(int i=0; i<10; i++)
  System.out.println(i);
if(a==0)
  System.out.println();

您可能会遇到F_CHOP框架,因为在随后的分支中,i不再在范围内。

请注意,也可能有内部语句分支,允许有不同的操作数堆栈条目。

代码语言:javascript
复制
System.out.println(a==0? "zero": "non-zero");

有两根树枝。对于第一种情况,对PrintStream实例的引用已经在堆栈上,第二种是对PrintStreamString实例的引用在堆栈上。

此外,异常处理程序形成具有单个操作数堆栈条目的隐式分支目标,即捕获的异常。这种情况可以使用方便定义的F_SAME1帧类型进行编码。

如果计划使用堆栈框架中包含的信息,并且正在使用ASM库,则不需要解析所有不同的框架类型。只需在构造时将标志ClassReader.EXPAND_FRAMES传递给ClassReader,您将遇到的所有情况都是包含完整堆栈状态的F_NEW框架,而无需记住以前的框架。

票数 1
EN

Stack Overflow用户

发布于 2016-09-06 20:22:31

根据下面的链接,您可以完全忽略堆栈映射框架,因为堆栈映射帧的唯一用途是验证一个类是否安全地运行;堆栈映射框架与您试图通过反编译器恢复的底层源代码没有任何关系。

Is there a better explanation of stack map frames?

另见:http://chrononsystems.com/blog/java-7-design-flaw-leads-to-huge-backward-step-for-the-jvm

从标准本身来看:

StackMapTable属性是代码属性(§4.7.3)属性表中的可变长度属性。此属性在类型检查验证过程中使用(§4.10.1)。方法的代码属性最多可能有一个StackMapTable属性。https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39352495

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档