java虚拟机Class格式与指令
2015-09-10 21:09
375 查看
前几天看《深入理解java虚拟机》中关于.class文件的详细解析,实际上Class文件里面就是包含着运行时候的指令,以及数据等内容。如果想要能够读懂Class文件,那一定需要对Class的文件结构以及Java虚拟机指令集有一定的了解
与指令紧密相关的就是操作数了,JVM里面有操作数栈,本地变量表。
使用
使用
从上面的结果可以大概看出一些内容,其中major version是java的版本,java7对应是51.然后是类的访问标志,public。然后是常量表,记录字符的表,包括函数名称,变了名称,类路径名称等等。
再之后是函数,每个函数其实是方法表,方法表里面再包括了访问标志,代码表,LineNumberTable是指函数是在第几行。
代码段里面的内容主要是刚刚操作码的指令,从这些字节代码是完全可以查看函数的功能的。
找到了问题,一下子没源码,就尝试修改class文件去解决这个问题,毕竟class文件是编译后,按照规范的,只要class是符合规范,程序验证通过的话,就会被JVM接受。使用修改的方式如下
使用vim -b Upload.class,这个时候是打开二进制文件,一堆乱码
输入vim的命令 :%!xxd 把文件转换成二进制的读入,转化后内容会变成这样
“`
0000010: 1400 1508 0016 0a00 1700 1807 0016 0700 …………….
然后看着右边那里的解释修改。我是直接改了路径,所以相对比较简单,如果太复杂就最好先编译。输入 :%!xxd -r 可以切换回原来的模式。修改后保存。修改可以直接改那些数字。
一次非常好的class文件学习实践体验。
JVM指令集
java虚拟机也有自己的指令集(字节码指令集),指令占一个字节长度,也就是说JVM中的指令最多也就256个。一常用的指令如:iload,iadd,isub,imul…,这里举的例子只是对应于int类型的运算操作码,如果float类型,对应的指令为:fload,fadd,fsub,fmul…。由指令加上对应的数据就是一次运算了。与指令紧密相关的就是操作数了,JVM里面有操作数栈,本地变量表。
Class文件结构
对一个非常简单的java文件:public class Test{ private int a; public int value(){ return a; } }
使用
javac Test.java得到Test.class.
使用
javap -verbose Test.class可以获得Class文件可视化结果.其中包括常量池,函数字节码代码
Classfile /Users/houzhi/Test.class Last modified Sep 8, 2015; size 265 bytes MD5 checksum 7a6cc538f28ef4dc4978891008b41ed8 Compiled from "Test.java" public class Test SourceFile: "Test.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #4.#15 // java/lang/Object."<init>":()V #2 = Fieldref #3.#16 // Test.a:I #3 = Class #17 // Test #4 = Class #18 // java/lang/Object #5 = Utf8 a #6 = Utf8 I #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 value #12 = Utf8 ()I #13 = Utf8 SourceFile #14 = Utf8 Test.java #15 = NameAndType #7:#8 // "<init>":()V #16 = NameAndType #5:#6 // a:I #17 = Utf8 Test #18 = Utf8 java/lang/Object { public Test(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 2: 0 public int value(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #2 // Field a:I 4: ireturn LineNumberTable: line 7: 0 }
从上面的结果可以大概看出一些内容,其中major version是java的版本,java7对应是51.然后是类的访问标志,public。然后是常量表,记录字符的表,包括函数名称,变了名称,类路径名称等等。
再之后是函数,每个函数其实是方法表,方法表里面再包括了访问标志,代码表,LineNumberTable是指函数是在第几行。
代码段里面的内容主要是刚刚操作码的指令,从这些字节代码是完全可以查看函数的功能的。
利用查看Class解决bug
这里顺便提一下我昨天干的一件事,因为部署的服务器应用的源代码在另外一个开发者那里,暂时他去有事了。但是我重新部署他的代码发现有问题,保存图片的位置一直不对,经过测试,感觉他可能是在程序里面写了一个固定的地址,导致换了服务器后,路径总是不太对。正巧这段时间有空的时候就在虚拟机的相关东西,而且基本能确定很大可能是路径问题,所以直接尝试去查看class的内容,就使用了javap -verbose来查看对应的class文件的内容,查看引用的地方最终找到了保存的代码,发现确实是他把保存路径写死了。
找到了问题,一下子没源码,就尝试修改class文件去解决这个问题,毕竟class文件是编译后,按照规范的,只要class是符合规范,程序验证通过的话,就会被JVM接受。使用修改的方式如下
使用vim -b Upload.class,这个时候是打开二进制文件,一堆乱码
输入vim的命令 :%!xxd 把文件转换成二进制的读入,转化后内容会变成这样
“`
0000010: 1400 1508 0016 0a00 1700 1807 0016 0700 …………….
0000020: 1901 0004 5445 5354 0100 124c 6a61 7661 ....TEST...Ljava 0000030: 2f6c 616e 672f 5374 7269 6e67 3b01 000d /lang/String;... ```
然后看着右边那里的解释修改。我是直接改了路径,所以相对比较简单,如果太复杂就最好先编译。输入 :%!xxd -r 可以切换回原来的模式。修改后保存。修改可以直接改那些数字。
一次非常好的class文件学习实践体验。
相关文章推荐
- Android Native 绘图方法
- XP下使用虚拟机安装配置Solaris[多图]
- VirtualBox虚拟机XP与宿主机Ubuntu互访共享文件夹
- Linux下三大免费桌面虚拟机评测
- 用 GNOME Boxes 下载一个操作系统镜像
- C#中struct和class的区别详解
- VBS ArrayList Class vbs中的数组类
- 大家看了就明白了css样式中类class与标识id选择符的区别小结
- android 使用虚拟机安装apk(图文教程)
- 深入了解PHP类Class的概念
- setAttribute 与 class冲突解决
- JavaScript中的类(Class)详细介绍
- javascript面向对象包装类Class封装类库剖析
- jQuery使用hide方法隐藏指定元素class样式用法实例
- jQuery给多个不同元素添加class样式的方法
- Vmware虚拟机的安装及配置方法
- JavaScript更改class和id的方法
- 一篇入门的php Class 文章
- 深入C++中struct与class的区别分析
- js中设置元素class的三种方法小结