9.20第一次作业

来源:互联网 发布:mac上好用的画图软件 编辑:程序博客网 时间:2024/06/16 04:50

eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。

比方说: add eax,-2 ;    //可以认为是给变量eax加上-2这样的一个值。

这些32位寄存器有多种用途,但每一个都有“专长”,有各自的特别之处。

EAX  是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。

EBX  是"基地址"(base)寄存器, 在内存寻址时存放基地址。

ECX  是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。

EDX  则总是被用来放整数除法产生的余数。

ESI/EDI 分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

EBP 是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:
  
  push ebp ; 保存当前ebp
  mov ebp,esp ; EBP设为当前堆栈指针
  sub esp, xxx ; 预留xxx字节给函数临时变量.
  ...
  
  这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数. EBP下方则是临时变量. 函数返回时作 mov esp,ebp/pop ebp/ret  即可.

ESP  专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节。

1.EIP 

2.ESP 

3.EBP 

1.EIP

寄存器里存储的是

CPU

下次要执行的指令的地址

 

也就是调用完

fun

函数后,让

CPU

知道应该执行

main

函数中的

printf

"

函数调用结束

"

语句了。

 

2.

EBP

寄存器里存储的是是栈的栈底指针,通常叫栈基址

,这个是一开始进行

fun()

函数调

用之前,由

ESP

传递给

EBP

的。

(在函数调用前你可以这么理解:

ESP

存储的是栈顶地址,

也是栈底地址。

 

3.

ESP

寄存器里存储的是在调用函数

fun()

之后,栈的栈顶

。并且始终指向栈顶。

 

堆栈

是一种简单的数据结构,是一种只允许在其一端进行插入或删除的线性表。

 

允许插入或删除操作的一端称为

栈顶

另一端称为

栈底

对堆栈的插入和删除操作被称

入栈

出栈

 

 

有一组

CPU

指令可以实现对进程的内存实现堆栈访问。其中,

POP

指令实现

出栈

操作,

PUSH

指令实现

入栈

操作。

 

 

CPU

ESP

寄存器存放

当前线程的栈顶指针

 

 

EBP

寄存器中保存

当前线程的栈底指针

 

 

CPU

EIP

寄存器存放

下一个

CPU

指令存放的内存地址

CPU

执行完当前的指令后,

EIP

寄存器中读取下一条指令的内存地址,然后继续执行。

 

esp

ebp

区别


1.EIP 

2.ESP 

3.EBP 
1.EIP寄存器里存储的是CPU下次要执行的指令的地址。 
也就是调用完fun函数后,让CPU知道应该执行main函数中的printf("函数调用结束")语句了。 
2.EBP寄存器里存储的是是栈的栈底指针,通常叫栈基址,这个是一开始进行fun()函数调用之前,由ESP传递给EBP的。(在函数调用前你可以这么理解:ESP存储的是栈顶地址,也是栈底地址。) 
3.ESP寄存器里存储的是在调用函数fun()之后,栈的栈顶。并且始终指向栈顶。 堆栈是一种简单的数据结构,是一种只允许在其一端进行插入或删除的线性表。 
允许插入或删除操作的一端称为栈顶,另一端称为栈底,对堆栈的插入和删除操作被称入栈和出栈。  
有一组CPU指令可以实现对进程的内存实现堆栈访问。其中,POP指令实现出栈操作,PUSH指令实现入栈操作。  
CPU的ESP寄存器存放当前线程的栈顶指针,  
EBP寄存器中保存当前线程的栈底指针。  
CPU的EIP寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。 

lea SI,D1
是把D1的地址放入SI寄存器中。
所以SI中的值会变的,变成的是D1的地址。而D1则是用户定义的一个内存数据的助记符。
如果是mov SI,D1就会把D1的值放进SI。
例如,D1 dw 0x0000
汇编以后可能变成:
地址 值
0x9000 00
0x9001 00
那么lea SI,D1,SI的值是0x9000而不是0000,要用mov就是0000了
在汇编语言中,MOV指令是数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址(寄存器间的数据传送本质上也是一样的)。其特点是不破坏源地址单元的内容。
例如:
MOV AX,2000H;将16位数据2000H传送到AX寄存器
MOV AL,20H;将8位数据20H传送到AL寄存器
MOV AX,BX;将BX寄存器的16位数据传送到AX寄存器
MOV AL,[2000H];将2000H单元的内容传送到AL寄存器
需要注意的是:
(1)两个存储单元之间不能直接传送数据,即:MOV指令只允许一个操作数在存储器中。MOV [SI],[2000H];这是错误的
(2)MOV指令中立即数不能直接传送给段寄存器(CS、DS、SS、ES)和IP;段寄存器之间不能直接传送。MOV IP,2000 H ;这是错误的
(3)CS和IP不能作为目的操作数。MOV CS,AX ;这是错误的
(4)MOV指令中立即数不能作目标操作数。MOV 2000H,[SI] ;这是错误的
在这里RET指令的内部操作是:栈顶字单元出栈,其值赋给IP寄存器。即实现了一个程序的转移,将栈顶字单元保存的偏移地址作为下一条指令的偏移地址。
pushax是把ax里的值压入堆栈。即当前esp-4出的值变为ax的值,ax本身的值不变。
popdx是把当esp指向的栈中的值(即之前push ax进栈的ax的值)赋给dx
并且esp+4(dx的值改变,esp在pop之前指向的地方的值不变,还是之前ax进栈后的值,即堆栈里的那个值不会自动清零)
可以直接在debug里实践,然后看它们的值,就是实际经验了
不同的CPU可能有不同的规定。下面只说常见的简单CPU的指令。

常见的CPU的CALL指令(“调用”指令)的功能,就是以下两点:
(1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈,
(2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。

而子程序结尾处通常都要编写一条RET指令(“返回”指令),RET指令的功能就是一条:
从栈中取出一条数据送入PC。

从上面叙述可以看出,正常情况下,RET指令从栈中取出的一条数据,也就是当初被CALL指令所入栈的下一条指令的所在地址。
因此,RET指令后,CPU的下一条指令就回去执行当初的CALL指令的下一条了。
jmp 就是无条件转移指令啊,遇到jmp 就转移,
跳转指令不止jmp,jmp是无条件跳转,jmp要配合条件跳转指令使用
比如C语言程序
s=0;
for (int i=0;i<10;++i)
{
s+=i;
}
可能会编译为等效如下汇编代码的指令:
mov eax,0
mov ebx,0
loop1:
cmp ebx,10
jge out
add eax,ebx
add ebx,1
jmp loop1
out:
mov s,eax
这里jmp就和jge配合使用
sub是减法运算。

比如
mov ax,2
mov bx,1
sub ax,bx

其中sub ax,bx就是ax中的值减bx中的值,等于1,然后把结果,也就是1,放入ax中。
ADD指令,是一种计算机指令,含义为两数相加(不带进位)。OPRD1为任一通用寄存器或存储器操作数,可以是任意一个通用寄存器,而且还可以是任意一个存储器操作数。




原创粉丝点击