关于指令代码占用字节的计算问题

计算机器指令占用字节数的关键:精确定位结束地址
在计算一段代码占用的总字节数时,最核心也是最容易出错的一步,就是精确地确定这段代码最后一个字节所在的地址。通用的计算公式 总字节数 = 结束地址 - 起始地址 + 1 虽然简单,但其正确性完全依赖于我们能否准确地找到这个“结束地址”。
结束地址由函数体的最后一条指令决定。它的计算方法是:
结束地址 = 最后一条指令的起始地址 + 该指令的字节长度 - 1
示例一:最后一条为单字节指令
函数 f1:
...
起始地址 -> 00401020 55 push ebp
...
...
最后一条指令 -> 0040107F C3 ret
1. 确定代码段的起始地址
- 函数
f1的起始地址是第一条指令的地址,即00401020H。
2. 确定最后一条指令的属性
-
函数的最后一条指令是
ret。 -
它的起始地址是
0040107FH。 -
它对应的机器码是
C3,这是一个单字节指令,所以其长度为 1字节。
3. 计算代码段的结束地址
-
根据公式:
结束地址 = 最后一条指令的起始地址 + 指令长度 - 1 -
代入数值:
0040107FH + 1 - 1 = 0040107FH。 -
结论:代码段的最后一个字节地址就是
0040107FH。对于所有单字节指令,其起始地址和结束地址是相同的。
4. 计算总字节数
-
使用总大小公式:
总字节数 = 结束地址 - 起始地址 + 1 -
代入数值:
0040107FH - 00401020H + 1 -
计算:
5FH + 1 = 60H -
转换为十进制:
60H = 96字节。
示例二:最后一条为多字节指令(关键点展开)
现在,我们构造一个新的场景。假设有一个函数 g1,它的最后一条指令是 cmp 指令。
// 这是一个假设的函数 g1
函数 g1:
...
起始地址 -> 004020A0H ... ...
...
...
// 函数的最后一条指令是 cmp
最后一条指令 -> 004020E5H 39 4D F4 cmp dword ptr [ebp-0Ch],ecx
1. 确定代码段的起始地址
- 假设函数
g1的起始地址为004020A0H。
2. 确定最后一条指令的属性
-
函数的最后一条指令是
cmp dword ptr [ebp-0Ch],ecx。 -
它的起始地址是
004020E5H。 -
它对应的机器码是
39 4D F4。这串机器码由三个十六进制数组成,代表它是一条3字节指令。
3. 计算代码段的结束地址(这是本例的核心)
-
这条3字节的指令占用了从
004020E5H开始的连续三个字节,分别是:-
004020E5H(存放39) -
004020E6H(存放4D) -
004020E7H(存放F4)
-
-
因此,函数
g1代码段的最后一个字节位于地址004020E7H。 -
我们用公式来验证:
结束地址 = 最后一条指令的起始地址 + 指令长度 - 1 -
代入数值:
004020E5H + 3 - 1 = 004020E7H。 -
结论:可以看到,对于多字节指令,其结束地址不等于其起始地址。精确计算出这个结束地址是后续所有计算的前提。
4. 计算总字节数
-
使用总大小公式:
总字节数 = 结束地址 - 起始地址 + 1 -
代入数值:
004020E7H - 004020A0H + 1 -
计算:
47H + 1 = 48H -
转换为十进制:
48H = 4 * 16 + 8 = 72字节。
总结
-
找到起点:确定第一条指令的起始地址。
-
找准终点:找到最后一条指令,分析其字节长度(是1字节、2字节还是多字节),并使用公式
最后指令的起始地址 + 长度 - 1来精确计算出整个代码段的结束地址。 -
套用公式:最后,使用
总字节数 = 结束地址 - 起始地址 + 1得出最终结果。