本文参考: http://www.vuln.cn/7115
本地变量和操作数栈
本地变量数组(Local Variable Array)
本地变量的数组包括方法执行所需要的所有变量, 包括 this 的引用, 所有方法参数和其他本地定义的变量. 对于那些方法 (静态方法 static method) 参数是以零开始的, 对于实例方法, 零为 this 保留.
所有的类型都在本地变量数组中占一个槽(entry), 而 long 和 double 会占两个连续的槽, 因为它们有双倍宽度(64-bit 而不是 32-bit).
操作数栈(Operand Stack)
操作数栈在执行字节码指令的时候使用, 它和通用寄存器在 native CPU 中使用的方式类似. 大多数 JVM 字节码通过 pushing,popping,duplicating,swapping, 或生产消费值的操作使用操作数栈.
看一个运算的例子
- public class calc
- {
- public static int half(int a)
- {
- return a/2;
- }
- }
编译
javac calc.java
反编译
javap -c -verbose calc.class
反编译结果
- ...
- major version: 52
- ...
- public static int half(int);
- descriptor: (I)I
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_2
- 2: idiv
- 3: ireturn
- LineNumberTable:
- line 5: 0
iload_0 第 0 个变量 (即变量 a) 压入操作数栈
- +-------+
- | stack |
- +-------+
- | a |
- +-------+
iconst_2 将 2 压入操作数栈
- +-------+
- | stack |
- +-------+
- | 2 |
- | a |
- +-------+
idiv 操作数栈中的前两个 int 相除, 并将结果压入操作数栈顶
- +-------+
- | stack |
- +-------+
- | result|
- +-------+
ireturn 返回栈顶元素
例子 2, 复杂一点的例子, 处理双精度的值
- public class calc
- {
- public static double half_double(double a)
- {
- return a/2.0;
- }
- }
反编译
- ...
- major version: 52
- ...
- #2 = Double 2.0d
- ...
- public static double half_double(double);
- descriptor: (D)D
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=4, locals=2, args_size=1
- 0: dload_0
- 1: ldc2_w #2 // double 2.0d
- 4: ddiv
- 5: dreturn
- LineNumberTable:
- line 5: 0
ldc2_w 指令是从常量区装载 2.0d, 另外, 其他三条指令有 d 前缀, 意思是他们使用 double 数据类型.
例子 3, 两个参数
- public class calc
- {
- public static int sum(int a, int b)
- {
- return a+b;
- }
- }
反编译
- ...
- major version: 52
- ...
- public static int sum(int, int);
- descriptor: (II)I
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=2, args_size=2
- 0: iload_0
- 1: iload_1
- 2: iadd
- 3: ireturn
- LineNumberTable:
- line 5: 0
iload_0 第 0 个变量 (即变量 a) 压入操作数栈
- +-------+
- | stack |
- +-------+
- | a |
- +-------+
iload_1 第 1 个变量 (即变量 b) 压入操作数栈
- +-------+
- | stack |
- +-------+
| b |
| a |
+-------+
iadd 操作数栈中的前两个 int 相加, 并将结果压入操作数栈顶
- +-------+
- | stack |
- +-------+
- | result|
- +-------+
ireturn 返回栈顶元素
例子 4, 类型改为长整型
- public class calc
- {
- public static long lsum(long a, long b)
- {
- return a+b;
- }
- }
反编译
- ...
- major version: 52
- ...
- public static long lsum(long, long);
- descriptor: (JJ)J
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=4, locals=4, args_size=2
- 0: lload_0
- 1: lload_2
- 2: ladd
- 3: lreturn
- LineNumberTable:
- line 5: 0
可以看到压入第二个参数的时候为 lload_2, 可见 lload_0 占了两个槽(entry)
例子 5, 混合运算
- public class calc
- {
- public static int mult_add(int a, int b, int c)
- {
- return a*b+c;
- }
- }
反编译
- ...
- major version: 52
- ...
- public static int mult_add(int, int, int);
- descriptor: (III)I
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=3, args_size=3
- 0: iload_0
- 1: iload_1
- 2: imul
- 3: iload_2
- 4: iadd
- 5: ireturn
- LineNumberTable:
- line 5: 0
iload_0 第 0 个变量 (即变量 a) 压入操作数栈
- +-------+
- | stack |
- +-------+
- | a |
- +-------+
iload_1 第 1 个变量 (即变量 b) 压入操作数栈
- +-------+
- | stack |
- +-------+
| b |
| a |
+-------+
imul 操作数栈中的前两个 int 相乘, 并将结果压入操作数栈顶
- +-------+
- | stack |
- +-------+
- |result1|
- +-------+
iload_2 第 2 个变量 (即变量 c) 压入操作数栈
- +-------+
- | stack |
- +-------+
- | c |
- |result1|
- +-------+
iadd 操作数栈中的前两个 int 相加, 并将结果压入操作数栈顶
- +-------+
- | stack |
- +-------+
- |result2|
- +-------+
ireturn 返回栈顶元素
来源: http://www.bubuko.com/infodetail-2567834.html