[toc]
一个典型的CPU由运算器、控制器、寄存器(CPU工作原理)等器件构成,这些器件靠内部总线相连。
- 运算器进行信息处理(运算单元)
- 寄存器进行信息存储(存储单元)
- 控制器负责控制各种器件工作(控制单元)
几乎所有的冯·诺伊曼型计算机的 CPU,其工作都可以分为5个阶段:取指令、指令译码、执行指令、访存取数、结果写回。
- 取指令: 取出内存中OPCode字节码。
- 指令译码:将OPCode字节码翻译成汇编指令。
- 指令执行:执行汇编指令。
- 访存取数:根据汇编指令需要,可能会访问内存数据,根据地址码得到内存位置并读取该操作数。
- 结果写回:运行结果数据写回到 CPU 的内部寄存器,方便后续指令快速存取。
8086CPU中一共有14 个寄存器,所有寄存器都是16位宽,存2个字节,因为是完全的16位微处理器。
AX,BX,CX,DX,SP,BP,SI,DI,IP,FLAG,CS,DS,SS,ES
这 14 个寄存器有可能进行具体的划分,按照功能可以分为五种:
- 通用寄存器
- 段寄存器
- 偏移寄存器
- IP寄存器
- 标志寄存器
通用寄存器有4个:AX,BX,CX,DX,一般用来存放数据,也被称为数据寄存器。
它们可分为两个可独立使用的8位寄存器
如下图所示。
8086CPU可以一次性处理以下两种尺寸的数据。
- 字节:记为byte,一个字节由8个bit组成,可以存在8位寄存器中。
- 字:记为word,一个字由两个字节组成,可以存在一个16位寄存器中(16位CPU)
8086采用小端模式:高地址存放高位字节,低地址存放低位字节。
一个8位寄存器所能存储的数据范围是:0~255 (2的8次方-1)
AX也叫做累加寄存器,主要用于输入/输出大规模的指令运算。
以下例子是我在Windows下编译的32位汇编,其中AX扩展成了EAX,我们可以看见乘法(累加)后的结果他其实就是保存到了EAX中,然后再将EAX赋值给整型变量c,所以乘法(imul)
和除法(div)
运算都会用到AX寄存器,除法会将商保存到ax中,余数保存到dx中。
编译命令:cl -FAS .\1.cpp
可以利用文章https://www.cnblogs.com/VxerLee/p/15264290.html中的方法将C语言转换成DOS汇编代码,然后对比源码和汇编代码发现乘法结果确实会放入到ax中。
乘法:
除法(取余数):
ax还常常被用作函数的返回值。
bx叫做数据寄存器,用来暂存一般数据,不过用的最多的还是用来寻址,bx存放偏移地址,然后根据基地址+偏移进行物理内存地址的定位。
暂存一般数据:
mov bx,2
add bx,bx
mov ax,bx
用bx寻址:
cx也是叫做数据寄存器,也能暂存一般数据,不过cx还有个专门的用途,根据字面意思c - > "Count",用来在Loop(循环)时候,用cx寄存器来进行计数指定循环的次数。
mov cx,10 ;循环10次
xor ax,ax
xor bx,bx ;存放sum
s:
int ax ;
add bx,ax;/bx = 1+2+3+4+5+6+7+8+9+10
loop s
除此之外在Win32汇编中,ecx经常会作为类指针进行传入。
#include <stdio.h>
#include <iostream>
using namespace std;
class Cat{
public:
int age;
char *name;
public:
void run();
};
void Cat::run()
{
cout << "I'm a Cat." << endl;
cout << "My Name is " << this->name << endl;
printf("age=%d\n",this->age);
printf("I'm Running.....\n");
}
int main()
{
Cat maomi;
maomi.age = 2;
maomi.name = "xiaohui";
maomi.run();
return 0;
}
进行反汇编后可以发现代码调用maomi.run()
的时候会把this指针
传入ecx
寄存器。lea ecx,dword ptr ss:[x]
dx寄存器和之前的寄存器一样,都是能暂存一般数据,在之前的汇编代码中可以发现编译器会将(通用寄存器)和si、di都拿来暂存一般的数据,除此之外之前还介绍过乘法和除法的值也会写入dx中。
dx用作乘法的时候,用来存储ax寄存器不够存储的高位数据
dx用作除法的时候前面介绍过了,用来存储余数。
CPU中包含了四个段寄存器,用作程序指令,数据或栈的基础位置。ps:(不过在Windows中好像这些段寄存器没什么用,因为Windows用了平坦模式,每个段的地址都一样都是0,直接用偏移来定位)
段寄存器主要的功能如下:
CS(Code Segment)
: 代码寄存器,程序代码的基础位置DS(Data Segment)
: 数据寄存器,变量的基本位置SS(Stack Segment)
: 栈寄存器,栈的基础位置ES(Extra Segment)
: 其他寄存器,内存中变量的其他基本位置。
mov cs:[xxx],ax
mov ds:[xxx],ax
mov ss:[xxx],ax
mov es:[xxx],ax
偏移寄存器或者叫索引寄存器,主要是包含段地址的偏移量,用来进行内存地址的定位。
BP(Base Pointer)
:基础指针,它是栈寄存器上的偏移量,用来定位栈上变量SP(Stack Pointer)
: 栈指针,它是栈寄存器上的偏移量,用来定位栈顶SI(Source Index)
: 变址寄存器,用来拷贝源字符串DI(Destination Index)
: 目标变址寄存器,用来复制到目标字符串
用[bp-xx]
表示变量
用[bp+xx]
表示函数参数
堆栈数据中bp+6
开始就是test
函数的第一个参数直到bp+16
为止。
这个其实主要是栈顶指针,无论何时sp指针都执行栈的顶部,[栈是一个从高地址向下生长的内存]。
push数据时候 sp指针情况(sp地址会减少)
pop数据时候 sp指针情况(sp地址会增加)
si寄存器是变址寄存器,可以用来存放寻址用的偏移,此外si还被用作隐含的源串地址,默认在DS段中。 [无论是si还是di这两个寄存器总感觉和字符串都有点关系,c++的string?]
char source[]="hello,world"; (假装=esi寄存器)
char dest[]={0}; (假装=edi寄存器)
;----------------------------------------------
mov ecx,strlen(source) ;字符串长度
rep movsb ;重复循环 并且传输字符串
;----------------------------------------------
[dest] = "hello,world"
di寄存器是目标变址寄存器,和si一样可以用来存放寻址用的偏移,此外di还被用作隐含的目的串地址,默认在ES段中。
先来看看STOS指令的介绍:
字符串存储指令 STOS
格式: STOS OPRD
功能: 把AL(字节)或AX(字)中的数据存储到DI为目的串地址指针所寻址的存储器单元中去.指针DI将根据DF的值进行自动调整.
接下来我们来看看,在汇编语言中是如何实现高级语言中清空数组的操作,以下是一个初始化字符数组的高级代码。
char szMsg[500]={0};
翻译后的汇编代码。
上面的汇编代码执行完后,可以发现szMsg数组的内容全部被清空了。
IP(Instruction Pointer)
: 指令指针寄存器,它是从 Code Segment 代码寄存器处的偏移来存储执行的下一条指令。
就剩下两种寄存器还没聊了,这两种寄存器是指令指针寄存器和标志寄存器:
FLAG
: Flag 寄存器用于存储当前进程的状态,这些状态有- 位置 (Direction):用于数据块的传输方向,是向上传输还是向下传输
- 中断标志位 (Interrupt) :1 - 允许;0 - 禁止
- 陷入位 (Trap) :确定每条指令执行完成后,CPU 是否应该停止。1 - 开启,0 - 关闭
- 进位 (Carry) : 设置最后一个无符号算术运算是否带有进位
- 溢出 (Overflow) : 设置最后一个有符号运算是否溢出
- 符号 (Sign) : 如果最后一次算术运算为负,则设置 1 =负,0 =正
- 零位 (Zero) : 如果最后一次算术运算结果为零,1 = 零
- 辅助进位 (Aux Carry) :用于第三位到第四位的进位
- 奇偶校验 (Parity) : 用于奇偶校验
参考文献: https://blog.csdn.net/qq_39654127/article/details/88698911 《王爽汇编笔记》 https://segmentfault.com/a/1190000037478310《十一假期淦了八天寄存器的相关知识》 https://docs.microsoft.com/zh-cn/cpp/build/reference/fa-fa-listing-file?view=msvc-160《/FA/Fa使用》 https://blog.csdn.net/bagboy_taobao_com/article/details/6203705 《了解寄存器:ESI EDI变址寄存器》 http://c.biancheng.net/view/3679.html《汇编语言字符串基本指令简介》 https://blog.csdn.net/weixin_43216249/article/details/110728729《汇编语言学习笔记--串操作篇(c++的string???)》