您的位置:首页 > 其它

8086汇编学习之基础知识、通用寄存器、CS/IP寄存器与Debug的使用

2017-04-23 00:15 399 查看

一、基本概念:

1、汇编语言的组成:

汇编指令+伪指令+符号体系

汇编指令:机器码的助记符(因为机器码难以记忆)通过编译器翻译成机器指令,每一个汇编指令对应一个机器指令(机器码);

伪指令:指导编译器如何将汇编指令翻译成机器指令,由编译器执行,计算机不执行,没有对应的机器码;

符号体系:+、-、*、/等一系列运算符号,由编译器识别,没有对应的机器码。

2、指令的概念:

机器指令:一连串二进制数字,不同的二进制组合有不同的意义(CPU执行机器指令,通过CPU内部的一系列运算器、控制器等数字电路模块对机器指令对应的高低电平进行处理,产生相应结果);

指令存放位置: 汇编指令(机器指令)和数据均以二进制形式存放在内存中,在内存/磁盘上指令和数据没有区别,都是二进制信息,但是CPU在工作时需要对指令和数据进行区分。

3、总线的概念:

CPU要进行数据的读写(所谓读与写就是CPU与外部器件进行信息交互,比如写显卡、读键盘、写磁盘等),需要用到三类总线:地址总线、数据总线、控制总线。

(1)地址总线(Address Bus,AB):用来传递地址信息。AB总线宽度决定寻址能力大小。

(2)数据总线(Data Bus,DB):用来在CPU与其他部件之间传送数据信息。DB宽度决定一次性数据传送量的大小。

(3)控制总线(Control Bus,CB):用来传送各种控制信号(读、写、中断等),完成对外部期间的控制。CB宽度决定CPU对外部器件的控制能力。

(4)常见微处理器型号的总线宽度:

地址总线:

8080:16根、8088:20根、8086:20根、80286:24根、80386:32根

数据总线:

8080:8根、8088:8根、8086:16根、80286:16根、80386:32根

eg:针对以上总线宽度,那么对于1024Byte的数据,8086(16/8=2B/次)至少需要读512次,80386(32/8=4B/次)至少需要读256次。

(4)、内存地址空间:

内存是存放数据和指令的,狭义的内存是指内存条,而广义的内存是指内存条、显卡(显存)、网卡等硬件。CPU的地址总线在不同地址区间上的操作是对不同硬件的操作。下图为8086PC机内存地址空间分配图:



8086有20根地址总线,寻址能力为2^20=1MB(0~FFFFF)。

ROM:只读存储器

RAM:随机存储器

二、寄存器:

8086CPU有14个寄存器,每个寄存器都是16位的:AX、BX、CX、DX;DS、ES、SS、CS;SI、DI;BP、SP、IP以及标志位寄存器(8bit有效,其余bit位为无效位,具体可参考标志位寄存器与CF、OF标志位的区分),如下:



1、通用寄存器:

AX、BX、CX、DX:通用寄存器,一般存放数据(当然地址也算数据)

一个寄存器2Byte=16bit,可表示的值为0–65535。

一个16位的通用寄存器可以分为2个8位的寄存器:高八位(High)和低八位(Low)

AX = AH + AL

BX = BH + BL

CX = CH + CL

DX = DH + DL

(1)、两个指令MOV,ADD:

mov指令将一个值移动到指定寄存器中,add将一个值加到指定寄存器上。

eg:

mov ax,FFEE
mov bx,ax
mov ch,al
mov dl,bh


测试:



(2)关于mov与add以及寄存器需要注意的问题:

以上测试的操作都是合法的,但是还有不合法的操作我们要注意:

eg:

mov ax,FFFFF    //16位寄存器给定的值大于2个字节,错误
mov ah,FFF  //高8位寄存器给定的值大于1个字节,错误
mov al,FFF  //低8位寄存器给定的值大于1个字节,错误
mov bx,FFFE //BX=FFFE
mov ax,bl   //将8位寄存器移动到16位寄存器中,不匹配,错误
add bx,FFFE //BX溢出,BX=1 FFFC=FF FC(1溢出,但是没有丢失)
add bl,FE   //BL溢出,但不会溢出到BH中,BX=(FF)(1FA)=FFFA
add bx,FFFFF    //add的值大于2个字节,错误


注意:当写成AX时,高八位与低八位是有关联的,但是写成AH或AL时,高八位与低八位是独立的。

2、CS寄存器与IP寄存器:

(1)、地址寄存器:

debug

-d

查看:



可以看到三部分:第一部分为地址,第二部分为内存值,第三部分为内存值对应的ASCII码。

可是内存地址为什么要写成“073F:0100”(段地址:偏移地址)这种格式呢?由于8086CPU地址线有20根(20bit),但是一个寄存器只有16bit。不能用一个寄存器表示一个完整的地址,就需要用两个寄存器来表示。

而前半部分为段地址,后半部分为偏移地址(相对于段地址的偏移量)。段地址存放在段地址寄存器中,段地址寄存器有四个(DS、ES、SS、CS),偏移地址存放在偏移地址寄存器中:SI、DI、BP、IP、SP、BX(通用寄存器当然也可以存放地址)。

(2)、CS:IP寄存器:

而图中的073F:0100两部分分别存放在CS寄存器和IP寄存器中。CS和IP是专门存放指令的寄存器,CPU也是据此来区分数据与指令的(也就是说在8086机中,任意时刻CPU将CS:IP指向的内容当做指令执行)。我们可以查看CS与IP的内容:



可以看到,当前CS:IP=073F:0100,正是-d的第一行地址(也是下一条将要执行的指令)。

那么我们解析一下上图中的地址:

073F:0100 = 073FH * 16 + 0100H = 073FH * 10H = 0100H = 07400H

073F为段地址、0100位偏移地址、07400位实际物理地址。

公式:

物理地址 = 基础地址 + 偏移地址

基础地址 = 段地址 * 16 = 段地址 * 10H

段地址:偏移地址 ==>只能得到一个物理地址

一个物理地址 ==>可以分解不止一种”段地址:偏移地址”的组合

eg:

3000H:2000H ==>合并: 3000H * 10H + 2000H = 32000H

32000H ==>解析:3000H * 10H + 2000H

2900H * 10H + 3000H

3100H * 10H + 1000H

3200h * 10h + 0000H

……

偏移地址能表示的最大值为FFFFH

(3)、指令的执行过程:

①CPU从CS:IP所组成的地址中读取指令,将这个指令存放在指令缓存器中。

②IP = IP + 所读指令字节数(指令是有长度的,不同指令长度不尽相同,可以由多个字节组成。)

③执行指令缓存器中的内容,回到步骤①,重复这个过程。

以上三步在”-t”执行指令的时候按顺序分别执行,一气呵成。

注意:这里所说的指令不单单指狭义的mov、add等,而是一整条类似“mov ax,1234H”的指令。而“mov ax,1234H”和“mov al,12H”的机器指令是不同的(“mov ax,1234H”的机器指令为B83412“mov al,12H”的机器指令为B012),可以看到其长度也是不同的,所以指令长度不因mov、add等单一决定。

测试如下:



073F:011B存储的指令“ADD SI DH”执行以后,IP从011B+2变成了011D,也是下一条指令的偏移地址。之后再执行073F:011D的指令以后加4成为0121,也是下一条指令的偏移地址。



(4)、JMP指令:

JMP转移指令:能够修改CS或IP,或者同时修改CS:IP的指令。

格式:

jmp CS:IP

jmp IP

eg:
jmp 2000:20000  //同时修改了段地址和偏移地址,那么下一条将要执行的指令就从2000:2000开始
jmp 1000    //只修改了IP偏移地址
mov ax,2000
jmp ax      //jmp借助通用寄存器修改IP也是可以的


注意:可以通过jmp修改CS和IP(jmp直接用值修改CS:IP或只修改IP),也可以通过”mov cs,ax/bx/cx/dx”修改CS(mov借助通用寄存器修改),但是不能通过”mov cs,FFFF”修改CS(mov不能直接用值修改CS),也不能通过mov修改IP(无论是借助通用寄存器,还是直接用mov修改)。



可以看到mov对IP修改时出错,基础ax修改cs不会出错,但是直接修改cs会出错。

jmp指令的测试:



三、Debug的使用:

首先:Debug是Dos、Windows都提供的实模式(8086方式)程序的调试工具。使用它可以查看CPU各种寄存器中的内容、内存使用情况和在机器码级跟踪程序的运行。(摘自《汇编语言(第三版)》·王爽

-r:查看寄存器信息
-r ax (Enter)
FFFF (Enter)    //修改ax的值为FFFF
-d:查看“段地址:偏移地址”与128个字节的内存信息
-d cs:ip (Enter)    //查看指定起始位置开始的128个字节
-u:将后续的字节翻译成汇编指令,查看汇编指令
-u cs:ip (Enter)    //指定起始地址以及其后的汇编指令
-a:写指令
-a cs:ip (Enter)    //从指定起始位置开始写指令
-e:修改
-e cs::ip (Enter)   //从指定位置开始修改,一次修改一个字节,按空格完成一个字节的修改,按回车完成修改。也可以一次修改一串字符。
-t:执行当前cs:ip中所指向的指令,不能指定cs:ip


(1)关于-e、-d的测试:

一次修改一个字节测试如下:



从-e指定的073F:0110开始,一个一个修改,从-d指定的073F:0110开始一个一个查看,可以看到修改的41~56以及61~69分别对应的内存值变化了,并且ASCII码对应的字符显示也很明显。

一次修改一串的测试如下:



修改从B8100H开始的内存地址中内容:



修改的地址为显存的地址,将ASCII对应字符在屏幕上对应的显示了出来。

(2)、关于-a与-r的jmp混合测试:



我们-a将指令写入指定的从2000:0000开始的地址中,然后-r查看cs:ip当前的值为(073F:0100),-a 073F:0100到下一条指令所在地址中修改指令为“jmp 2000:0000”,以便-t执行以后,直接jmp跳转到2000:0000开始执行之前写好的三条指令(循环求2的幂次方)。

上面我们采用的是不修改CS:IP的值(指令地址),而是修改CS:IP的内容(指令),当然我们也可以选择修改下一条指令的地址(即CS:IP的值),如下图:



虽然我们写“jmp 2000:0000”、“jmp 2000:0003”…,但是要注意的是:这种简单粗暴的方式是不安全的,测试可以用但是实际不要这么使用。(以上寄存器名、十六进制、Debug命令都是不区分大小写的)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  汇编