021-【X86-汇编语言】-程序的执行-EIP寄存器

程序的翻译

003-【X86-汇编语言】-绕不开的二进制004-【X86-汇编语言】-信息的形式&整数中提到对于计算机来说所的信息都是二进制,信息包括指令和数据。因此我们写完的.asm并不能直接交由操作系统或CPU执行,必须通过某种途径将.asm翻译机器能读取和执行的二进制信息。接下来让我们看看二进制的程序

编写以下实例代码,并单步调试

.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD

.data
X1 DWORD 1h
X2 WORD  2h
X3 BYTE  3h

.code
MAIN PROC
ADD X1,1h
ADD X2,1h
ADD X3,1h
INVOKE ExitProcess,0
MAIN ENDP
END MAIN

本次我们将反汇编的所有【查看选项】都选上

由反汇编可以看出【ADD X1,1h】这条源代码,翻译成二进制码为 83 05 00 40 39 01 01。我们简单分析一下这个二进制码。

最后一个【01】是源代码中的【1h】。

在【01】之前是目的操作数,也就是源代码中【X1】,我们知道X1其实是代表着一个地址,而win32中地址需要占用4个字节,所以我们很容易知道【00 40 39 01】表示的是【X1】的地址。要注意【00 40 39 01】是小端字节序(参见:原 011-【X86-汇编语言】-内存字节序(大端,小端)),所以真正的地址应该是01394000h

剩下最前端的【83 05】应该就是【ADD】代表的机器指令了

通过同样的方法我们可以推断出【ADD X2,1h】翻译的成的机器码是【66 83 05 04 40 39 01 01】其中【66 83 05】是【ADD】代表的机器指令。【ADD X3,1h】翻译成机器码是【80 05 06 40 39 01 01】其中【80 05】是【ADD】代表的机器指令。可以看出同样是ADD指令,因为操作数的不同,其翻译后的机器指令是不同的。

程序的执行

在反汇编器中我们可以看到每条指令所在的内存地址

当前我们的程序停在01391010h内存地址处,查看一下寄存器【EIP】,发现【EIP】的值就等于【01391010h】。注意每次执行指令所在的地址都是不同的,因此你在执行程序是的值跟我现在执行的程序地址是不同的。

我们尝试单步执行一下,发现单步执行后EIP的值变成了【01391017h】,由此可以得到结论,每次执行后EIP的值会变成下一条指令的地址。事实上程序也是这样被执行的,每一次CPU根据EIP寄存器的值执行一条指令,然后将EIP的值修改成下一条需要执行的指令的地址,周而复始。

观察可以发现【ADD X1,1h】的机器码【83 05 00 40 39 01 01】占用了7个字节,而【01391010】+7=【01391010】。程序指令在内存中是顺序存储的,因而修改EIP的值,其实就是用EIP的值加上当前指令的长度。

数据的存储

再将关注点改到操作数上,由上一段我们可以看出【ADD X1,1h】中的立即数1h再翻译之后成为了指令的一部分。而X1被翻译成了一个地址,我们来看一下这个地址

内存中可以看出02 00 00 00 是X1(因为已经执行了【ADD X1,1h】所以X1的值变成00000002h),02 00是X2,03是X3。可以知道数据与指令一样存储在内存中。

程序的加载和执行

当我们执行程序时,有一种叫加载器的系统程序,会将程序加载到内存。指令(.code)和数据(.data)会被加载到不同的内存位置,然后设置EIP的值为第一条需要执行指令的内存地址,修改每条指令操作数变量的地址。之后便可以一步一步地执行直到程序结束了。

 

猜你喜欢

转载自blog.csdn.net/patronwa/article/details/88942705