汇编指令和机器指令的差别在于指令的表示方法上。汇编指令是机器指令便于记忆的书写格式。
汇编指令是机器指令的助记符。
寄存器: CPU中可以存储数据的器件,一个CPU中有多个寄存器。
AX BX都是寄存器的代号。
汇编语言由以下三部分组成:
1.汇编指令(机器码的助记符)
2.伪指令(由编译器执行)
3.其他符号(由编译器识别)
CPU 我们需要向CPU提供指令和数据,它才能工作。
指令和数据都存放在存储器中,也就是内存。
在内存中,指令和数据没有区别,都是二进制的信息。
存储器被划分为若干个存储单元,从0开始顺序编号。
CPU若要进行数据的读写,需要和外部内存进行三类信息的交互:
1.存储单元的地址(地址信息)
2.器件的选择,读写命令的选择(控制信息)
3.读或写的数据
所以电脑中有三种总线,逻辑上分为地址总线,数据总线和控制总线。
一个CPU有N根地址总线,我们就可以说它的宽度为N,它可以寻址:2的N次方个内存单元。
CPU的数据总线宽度决定了它与外界的数据传送速度。
最终运行程序的是CPU,我们用汇编编程的时候,必须要从CPU角度考虑问题。
一个典型的CPU由运算器,控制器和寄存器组成,这些器件内部通过总线相连。
数据寄存器4个:AX,BX,CX,DX;
地址指针寄存器2个:SP,BP;
变址寄存器2个:SI,DI;
段寄存器4个:CS,DS,SS,ES;
控制寄存器两个:IP,FLAGS。
http://www.cnblogs.com/zhaoyl/archive/2012/05/15/2501972.html
8086 CPU 中寄存器总共为 14 个,且均为 16 位 。
即 AX,BX,CX,DX,SP,BP,SI,DI,IP,FLAG,CS,DS,SS,ES 共 14 个。
而这 14 个寄存器按照一定方式又分为了通用寄存器,控制寄存器和段寄存器。
通用寄存器:
AX,BX,CX,DX 称作为数据寄存器:
AX (Accumulator):累加寄存器,也称之为累加器;
BX (Base):基地址寄存器;
CX (Count):计数器寄存器;
DX (Data):数据寄存器;
SP 和 BP 又称作为指针寄存器:
SP (Stack Pointer):堆栈指针寄存器;
BP (Base Pointer):基指针寄存器;
SI 和 DI 又称作为变址寄存器:
SI (Source Index):源变址寄存器;
DI (Destination Index):目的变址寄存器;
控制寄存器:
IP (Instruction Pointer):指令指针寄存器;
FLAG:标志寄存器;
段寄存器:
CS (Code Segment):代码段寄存器;
DS (Data Segment):数据段寄存器;
SS (Stack Segment):堆栈段寄存器;
ES (Extra Segment):附加段寄存器;
,每一个 16 位寄存器就可以当做 2 个独立的 8 位寄存器来使用了 。
AX 寄存器可以分为两个独立的 8 位的 AH 和 AL 寄存器;
BX 寄存器可以分为两个独立的 8 位的 BH 和 BL 寄存器;
CX 寄存器可以分为两个独立的 8 位的 CH 和 CL 寄存器;
DX 寄存器可以分为两个独立的 8 位的 DH 和 DL 寄存器;
BX 寄存器中存放的数据一般是用来作为偏移地址使用的。
基址其实就是段地址,段地址存储在段寄存器。
在 8086 CPU 中,CPU 是根据 <段地址:偏移地址> 来进行寻址操作的。
在 8086 CPU 中,只有 4 个寄存器可以以 […] 的方式使用,这四个寄存器分别是 BX,SI,DI,BP。
段也就是在编程时,我们将若干个地址连续的内存单元看做是一个段,
段有数据段,代码段,栈段,它们的含义很明显,就是分别用来存储数据,代码和作为栈作用的内存空间。
不同的段,它们默认的段地址存储在不同的寄存器中,
数据段的段地址存储在DS(data segment)寄存器中,
代码段的段地址放在CS(code segment)寄存器中,
栈段的段地址存放在SS(stack segment)寄存器中。
CS:IP两个寄存器指示CPU当前要读取的指令的地址,其中CS为代码段寄存器,IP为指令指针寄存器。
CPU是怎样做到自动读取指令的呢?
当我们运行一个可执行文件时,我们需要另外一个程序把这个可执行文件加载到内存当中,我们就认为是shell程序来
加载可执行程序,它将可执行文件加载到内存中后,就会设置CPU中的两个寄存器,即设置CS:IP两个寄存器,指向
可执行文件的起始地址,此后CPU即可从这个地址中读取内存中的指令,并且执行。
汇编语言中的START标记就是用来标记这段代码的起始地址。
栈顶的段地址存放在SS中,偏移地址存放在SP寄存器当中。
在任何时刻,SS:SP都是指向栈顶元素。
段的支持是在 CPU上体现的,而不是在内在中实现了段。段是逻辑上的概念,它们都是一段内在,为什么要分数据段和代码段呢?这是为了编程的方便,或者说是代码编写方便。
CF(Carry FLag) - 进位标志(第 0 位);
PF(Parity flag)-奇偶标志(第二位)
AF(auxiliary carry flag) 辅助进位标志(第4位)
ZF(zero flag)零标志(第6位)
SF:符号位(7) TF(trap flag)追踪标志(8)
OF(over flag) 溢出标志 (第11位)
在写汇编指令或寄存器的名称时,不区分大小写,如MOVE AX 18,mov ax 18,等价。
AX是16位寄存器,所以只能存放4位十六进制的数,如果存放的数据超过4位,则其存储低位,高位存储在dx中。
编程计算2的4次方
Mov add
Mov ax 2;
Add ax 2;
Add ax2;
Add ax2;
CPU 在访问内存单元时,要给出内存单元的地址,所有内存单元构成的存储空间是一维的线性空间,每一个内在单元在这个空间中都有一个唯一的地址,我们将这个地址称为物理地址。
CPU通过地址总线送入存储器的必须是一个内存单元的物理地址,但是在向地址总线发送物理地址前,必须先形成
这个物理地址,不同的CPU有不同的方式生成物理地址。
地址加法器采用物理地址=段地址左移四位(乘16)+偏移地址的段地址和偏移地址合成物理地址。
我们对事物的认识会限制我们会它的使用。至少是从意识上限制它的使用,也许在实践中无意发生新的运用。
CPU可以使用不同的段地址和偏移地址形成同一个物理地址。
偏移地址16位,变化范围为0-ffffh,可以用来定位64KB个内存单元。
CPU根据什么来判断内存地址存储的是数据还是数据?
根据CS:Ip的内容,如果等于此地址,则是代码。
Jmp CS:IP
Jmp 合法寄存器 :用寄存器中的值修改IP
Debug是DOS,windows 提供的实模式(8086)程序的调试工具,可以用来查看CPU各种寄存器中的内容,内存的情况和机器码级跟踪程序的运行。
debug
A 1000:0
然后写入
汇编指令
然后修改CS:IP的地址到1000:0然后t去执行指令,观察寄存器的变化;
Rcs
1000
Rip
0