Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有一种聪明的方法来确定Java字节码指令的长度?_Java_Jvm_Jvm Bytecode - Fatal编程技术网

有没有一种聪明的方法来确定Java字节码指令的长度?

有没有一种聪明的方法来确定Java字节码指令的长度?,java,jvm,jvm-bytecode,Java,Jvm,Jvm Bytecode,我正在为Java创建一个静态分析工具,如果我可以从.class文件中的字节码中获得一些关于我正在分析的程序的信息,那么这些信息将更容易获得 我不关心类文件中的每一个。例如,我可能只需要查看是否有任何getfield指令 问题在于,由于每条指令的长度都是可变的,因此在一般情况下,我需要(在代码中)指定每条操作码的长度,然后才能确定(例如)getfield指令的开始和结束位置 对于其他一些指令集(如),有这样的规则:“任何低于0x0F的操作码都是1字节,任何等于或大于0x0F的操作码都是2字节。”

我正在为Java创建一个静态分析工具,如果我可以从
.class
文件中的字节码中获得一些关于我正在分析的程序的信息,那么这些信息将更容易获得

我不关心类文件中的每一个。例如,我可能只需要查看是否有任何
getfield
指令

问题在于,由于每条指令的长度都是可变的,因此在一般情况下,我需要(在代码中)指定每条操作码的长度,然后才能确定(例如)
getfield
指令的开始和结束位置

对于其他一些指令集(如),有这样的规则:“任何低于0x0F的操作码都是1字节,任何等于或大于0x0F的操作码都是2字节。”

Java字节码指令中有这样的方便模式吗

非常清楚指令集:

操作数的数目和大小由操作码决定

您可以尝试利用现有的字节码库,如ApacheCommons BCEL,并使用其中定义的操作码元数据为应用程序构建单独的数据结构。例如,与表示JVM指令的
getLength()
方法一起使用。

非常清楚指令集:

操作数的数目和大小由操作码决定


您可以尝试利用现有的字节码库,如ApacheCommons BCEL,并使用其中定义的操作码元数据为应用程序构建单独的数据结构。例如,除了表示JVM指令的
getLength()
方法之外。

字节码设计中没有此类功能。操作码的含义很简单。我见过的JVM实现使用字节码长度的表查找,并对和字节码进行特殊处理

它非常小:只有202个字节码


注意长度不仅取决于操作码本身,还取决于字节码的位置:
表开关
查找开关
由于对齐要求,具有可变长度填充。

字节码设计中没有此类功能。操作码的含义很简单。我见过的JVM实现使用字节码长度的表查找,并对和字节码进行特殊处理

它非常小:只有202个字节码


注意长度不仅取决于操作码本身,还取决于字节码的位置:
表开关
查找开关
由于对齐要求,具有可变长度的填充。

如果尝试将指令操作码映射到指令大小,您将得到以下令人沮丧的表格:

0-15 1字节
16.2字节
17.3字节
18.2字节
19-20 3字节
21-25 2字节
26-53 1字节
54-58 2字节
59-131 1字节
132 3字节
133-152 1字节
153-168 3字节
169 2字节
170-171特殊处理
172-177 1字节
178-184 3字节
185-186 5字节
1873字节
1882字节
189 3字节
190-191 1字节
192-1933字节
194-195 1字节
196特殊处理
197 4字节
198-199 3字节
200-201 5字节

换句话说,在指令的数值和位模式中没有编码大小的信息,但是还有另一个属性,你可以考虑某种模式:从200个定义的指令中,大约有150个指令的大小是一个字节,只留下50个指令,这些指令需要任何处理。即使是这一小部分指令也可以进一步细分为逻辑组,大多数指令占用三个字节,第二大指令占用两个字节

因此,快速浏览指令的方法代码可能如下所示:

static void readByteCode(ByteBuffer bb) {
    while(bb.hasRemaining()) {
        switch(bb.get()&0xff) {
            case BIPUSH: // one byte embedded constant
            case LDC:    // one byte embedded constant pool index
            // follow-up: one byte embedded local variable index
            case ILOAD:  case LLOAD:  case FLOAD:  case DLOAD:  case ALOAD:
            case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: case RET:
            case NEWARRAY: // one byte embedded array type
                bb.get();
                break;

            case IINC: // one byte local variable index, another one for the constant
            case SIPUSH: // two bytes embedded constant
            case LDC_W: case LDC2_W: // two bytes embedded constant pool index
            // follow-up: two bytes embedded branch offset
            case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE:
            case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE:
            case IF_ICMPGT: case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE:
            case GOTO: case JSR: case IFNULL: case IFNONNULL:
            // follow-up: two bytes embedded constant pool index to member or type
            case GETSTATIC: case PUTSTATIC: case GETFIELD: case PUTFIELD:
            case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case NEW:
            case ANEWARRAY: case CHECKCAST: case INSTANCEOF:
                bb.getShort();
                break;

            case MULTIANEWARRAY:// two bytes pool index, one byte dimension
                bb.getShort();
                bb.get();
                break;

            // follow-up: two bytes embedded constant pool index to member, two reserved
            case INVOKEINTERFACE: case INVOKEDYNAMIC:
                bb.getShort();
                bb.getShort();
                break;

            case GOTO_W: case JSR_W:// four bytes embedded branch offset
                bb.getInt();
                break;

            case LOOKUPSWITCH:
                // special handling left as an exercise for the reader...
                break;
            case TABLESWITCH:
                // special handling left as an exercise for the reader...
                break;
            case WIDE:
                int widened=bb.get()&0xff;
                bb.getShort(); // local variable index
                if(widened==IINC) {
                    bb.getShort(); // constant offset value
                }
                break;
            default: // one of the ~150 instructions taking one byte
        }
    }
}
我故意将一些指令分开,它们具有相同的后续字节数,但含义不同。毕竟,我想你想在某些地方插入一些实际的逻辑

请注意,两个
开关
字节码指令的处理被省略,它们需要填充,其实现需要了解缓冲区内的代码对齐情况,缓冲区由调用者控制。这取决于您的具体应用。请参阅和的文档


当然,将所有单字节指令作为
默认值处理意味着代码不会捕获未知或无效指令。如果您想要安全,您必须插入案例…

如果您尝试将指令操作码映射到指令大小,您将得到以下令人沮丧的表格:

0-15 1字节
16.2字节
17.3字节
18.2字节
19-20 3字节
21-25 2字节
26-53 1字节
54-58 2字节
59-131 1字节
132 3字节
133-152 1字节
153-168 3字节
169 2字节
170-171特殊处理
172-177 1字节
178-184 3字节
185-186 5字节
1873字节
1882字节
189 3字节
190-191 1字节
192-1933字节
194-195 1字节
196特殊处理
197 4字节
198-199 3字节
200-201 5字节

换句话说,在指令的数值和位模式中没有编码大小的信息,但是还有另一个属性,你可以考虑某种模式:从200个定义的指令中,大约有150个指令的大小是一个字节,只留下50个指令,这些指令需要任何处理。即使是这一小部分指令也可以进一步细分