x86从实际模式到保护模式(1):8086汇编语言程序与设计总结

可能大多数人入门汇编语言都是以8086为起点的(相对较为简单),本文也是以此为起点来讲解有关在8086实模式相关知识点(下一节会更新实模式下的更多内容以及PE模式的相关内容)

相关资料:

认识8086处理器

8086的通用寄存器

# 均为16位寄存器
AX: [AH-AL]     SI
BX: [BH-BL]	    DI
CX: [CH-CL]     SP
DX: [DH-DL]     BP

8086的内存访问和字节序

8086的数据线为16根,与寄存器一致,因此一个寄存器可以完全接收从内存来的数据

字节序分类

  • 低端字节序:寄存器的低字节占据低地址,高字节占据高地址

  • 高端字节序:寄存器的低字节占据高地址,高字节占据低地址

8086内存访问

8086有20根地址线,因此寻找内存地址的时候需要20个b,最大内存地址为[FFFFF]

DS: 数据段寄存器 16b
CS: 代码段寄存器 16b
IP: 段偏移寄存器 16b

而当不看最后四位比特时,则可以看作是一个16位的地址,此时就可以用DS或CS进行访存,则此时有一个IP寄存器表示段内偏移量,相加则会产生一个20位地址。

如何执行编译好的程序

跳转指令

jmp 0xfe05:0x000b

硬盘的构造和工作原理

硬盘分类

  • USB:软盘
  • HDD:机电式硬盘
  • SSD:集成电路硬盘

一个扇区是512字节

两个模式

  • CHS(cylinder-header-sector):磁头号-柱面号-扇区号
  • LBA(logical-block-address):使用逻辑扇区号,由CHS转换而来

主引导扇区

一般情况下,在BIOS中有一段代码,他将硬盘的主引导扇区中的程序读到内存地址[07c00]处,然后用一个跳转指令跳到那里继续执行

db 0	;位指令,用来向程序中添加一个字节的数据

times 502 db 0;重复位指令db 502次
;主引导扇区程序要求最后两个字节是55和AA
db 0x55
db 0xAA

在屏幕上显示文本

显卡和显存

色彩混合的原理:

RGB每个颜色用8个b表示,即2^8=256,三种颜色融合形成色彩混合

显存位置:[B8000~BFFFF]

将显存内的数据通过字符解析器传送到屏幕上

这段显存可以看作是一个段

mov指令

;mov 段寄存器, 通用寄存器

;mov 段寄存器, [内存地址]

;mov ax, 0xb800
;mov ds, ax	此后所有的[xxxx]都是以该ds为段地址的偏移地址
;mov byte [0x00], 0x41 表示从偏移0x00位置mov一个字节的数据

不允许将一个操作数直接传给段寄存器

字符的编码和显示属性

ASCII编码

字符在内存中的表示:字符编码-字符属性

字符属性:背景色 + 前景色(此处只有黑白,因此一个b表示黑或白)

在汇编程序中使用标号

标号只是一个对汇编地址的别名

start:	;该行有地址则用该地址,无地址则用其以后第一条指令地址
	...

段间直接绝对跳转指令

在不同的段进行跳转执行

;jmp 段地址:偏移地址
jmp 0x0000:0x7c00

寄存器的绝对间接近跳转

段内跳转

	mov bx, 0x7c00 + again
again:
	jmp bx	;使用寄存器跳转,段地址保持不变,bx是偏移地址

使用相对偏移量的短跳转和近跳转

jmp short start	;EB操作码-1B 8位的相对偏移量

jmp near start ;当跳转范围<-127 || >128 使用三个字节 E9 16位的相对偏移量

在屏幕上显示数字

显示数字的基本原理

第一步:将数字125分解为三个数字1、2和5(此时要进行数字拆分,即%10得余数)

125 -> 0111 1101

1 -> 0000 0001
2 -> 0000 0010
5 -> 0000 0101

第二步:将数字1、2和5分别转换成对应的数字字符

根据ASCII编码

无符号数除法指令div

  • 如果在指令中指定的是8位寄存器或者8位操作数的内存地址,则意味着被除数在寄存器AX里。相除后,商在寄存器AL里,余数在寄存器AH里。
  • 如果在指令中指定的是16位寄存器或者16位操作数的内存地址,则意味着被除数是32位的,低16位在寄存器AX里;高16位在寄存器DX里。
    相除后,商在寄存器AX里,余数在寄存器DX里。
  • 如果在指令中指定的是32位寄存器或者32位操作数的内存地址,则意味着被除数是64位的,低32位在寄存器EAX里;高32位在寄存器EDX里。
    相除后,商在寄存器EAX里,余数在寄存器EDX里。(80386支持)
  • 如果在指令中指定的是64位寄存器或者64位操作数的内存地址,则意味着被除数是128位的,低64位在寄存器RAX里;高64位在寄存器RDX里。
    相除后,商在寄存器RAX里,余数在寄存器RDX里。(64位处理器支持)
;div 除数所在的寄存器或者内存地址

div hb;bh是一个8位寄存器
div byte [0x2002]; 除数是一个8位内存单元(1B)

异或指令xor

xor bh, bh;相同为0,不同为1

加法指令add

add ax, 3;此处ax是16位寄存器,所以3被当作16进制下的3进行运算

使用标号访问内存数据

mov [0x7c00], dl;将dl数据传送给偏移地址在0x7c00地方

mov [0x7c00 + 1], dl ;将dl数据传送给偏移地址在0x7c00 + 1B地方

段超越前缀的使用

mov byte [0x01], 0x2f;表示移动1B数据

循环、批量传送和条件转移

跳过非指令的数据区

把代码和数据分开

mytext db 'L', 0x07, 'a', 0x07 \;\表示换行
		 'a', 0x07, 'L', 0x07

把数据放在段的前面,在读内存的时候会直接读mytext,但是这是数据,是不可执行的,因此

	jmp start

mytext ...

start:
	...

逻辑段的地址的重新设定

	jmp start
mytext ...

start:
	mov ax, 0x7c00	;设置数据段基地址
	mov ds, ax
	
	mov ax, 0xb800 ;设置附加段基地址
	mov es, ax

串传送指令和标志寄存器

;按字节进行传送
movsb
;按字进行传送
movsw

DS:SI:原始数据串的段地址:偏移地址

ES:DI:目标位置的段地址:偏移地址

cld;方向标志清0指令,std将DF置为1
mov si, mytext
mov di, 0
mov cx, (start - mytext) / 2
rep movsw;

标志寄存器FLAGES的方向标志位DF表示是正向传送还是反向传送

NASM的 和 和 $

$;表示当前行的汇编地址
$$;表示当前程序段的汇编地址

循环指令loop

digit:
	loop digit

基址寻址和INC指令

在8086处理器上,如果要用寄存器来提供偏移地址,只能使用BX、SI、DI、BP,不能使用其它寄存器。

寄存器Bx在设计之初的作用之一就是用来提供数据访问的基地址,所以又叫基址寄存器(Base Address Register) 。

mov bx, ax
mov [bx], dl; 正确
mov [ax], cl;非法

inc指令

inc bx;自增1B

dec指令

dec bx;自减1

基址变址寻址和条件转移指令

mov si, 4
mov al, [bx + si];bx:基址,si:变址

在8086处理器上,只允许以下几种基址变址的组合:

bx + si
bx + di
bp + si
bp + di

jns:FLAGS的符号位SF是否为0,为0则跳转

jns

8086的标志寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c7WFIrHJ-1635446292575)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20211029014410948.png)]

  • CF:进位标志。当一个算术操作在结果的最高位产生进位或者借位时,此标志是1;否则是0。
  • PF:奇偶标志:当一个算术操作的结果在低8位中有偶数个“1”,此标志是1﹔否则为0
  • AF:调整标志。当一个算术操作在结果的位3产生进位或者借位时,此标志是1﹔否则是0。此标志用于二进制编码的十进制数算法里。
  • ZF:零标志。当运算的结果为O时,此标志为1;否则为0。
  • SF:符号标志。用运算结果的最高位来设置此标志(一般来说,这一位是有符号数的符号位。0表示正数,1表示负数)。
  • OF:溢出标志。对任何一个算术操作,假定它进行的是有符号运算。那么,当结果超出目标位置所能容纳的最大正数或者最小负数时,此标志为1,表示有符号整数运算的结果已经溢出﹔否则为0。

现有指令对标志位的影响

指令 标志位变化
cbw/cwde/cdqe/cwd/cdq/cqo 不影响任何标志位。
cld DF=0,对CF、OF、ZF、SF、AF和PF的影响未定义。
std DF=1,不影响其他标志位。
inc/dec CF标志不受影响;对OF、SF、ZF、AF和PF的影响依计算结果而定。
add / sub OF、SF、ZF、AF、CF和PF的状态依计算结果而定。
div / idiv 对CF、OF、SF、ZF、AF和PF的影响未定义。
mov/ movs 这类指令不影响任何标志位。
neg 如果操作数为0,则CF=O,否则CF=1;对OF、SF、ZF、AF和PF的影响依
计算结果而定。
xor OF=O,CF=O;对SF、ZF和PF依计算结果而定;对AF的影响未定义。

条件转移指令和CMP

CMP:比较两个操作数的大小。影响到CF、OF、SF、ZF、 AF和PF标志位

cmp ax, bx

条件转移指令:略(太多了)

栈的原理和应用

字符串的定义和累加过程

    jmp start
message db '1+2+3+...+100=';等同于db '1','+','2','+','3','.','.','.','1','0','0','='

start:
	mov ax, 0x7c00;设置数据段的段基地址
	mov ds, ax
	
	mov ax, 0xb800
	mov es, ax
	
	;以下显示字符串
	mov si, message
	mov di, 0
	mov cx, start-message
showmsg:
	mov al, [si]
	mov [es:di], al
	inc di
	mov byte [es:di], 0x07
	inc di
	inc si
	loop showmsg
	
	;以下计算1到100的和
	xor ax, ax	;ax用于存放累加结果
	mov cx, 1;cx用于充当加数
summate:
	add ax, cx
	inc cx
	cmp cx, 100;cx是否等于100
	jle summate;小于等于100时跳转,进行累加
	
	jmp $
	
	times 510-($-$$) db 0
	db 0x55, 0xaa

栈的原理和使用

在内存中划分一块区域给栈,为栈段,由SS寄存器指向其段基址,SP寄存器指向栈顶

;入栈
pop dx
push word [0x2002]
;出栈
pop dx
pop word [0x80]

push 的执行过程:

  • SP<-SP-操作数的大小(字节数);
  • 段寄存器SS左移4位,加上SP里的偏移地址,生成物理地址;
  • 将操作数写入上述地址处。

pop 的执行过程:

  • 段寄存器SS左移4位,加上SP里的偏移地址,生成物理地址;
  • 从上述地址处取得数据,存人由操作数提供的目标位置处;
  • SP<- SP +2

栈在数位分解和显示中的应用

summate:
	add ax, cx
	inc cx
	cmp cx, 100
	jle summate
	
	;一下分解累加和的每个数位
	xor cx, cx;设置栈 段的段基地址
	mov ss, cx;和代码段共用一个段地址
	mov sp, cx
	
	mov bx, 10;用作除数
	xor cx, cx
decompo:
	inc cx
	xor dx, dx
	div bx;dx(高16位) ax(低16位)除以bx,商放在AX,余数在DX
	add dl, 0x30;得到字符编码
	push dx
	cmp ax, 0;查看商是否等于0
	jne decompo;不等于0则继续跳转
	
	;以下显示各个数位
shownum:
	pop dx
	mov [es:di], dl
	inc di
	mov byte [es:di], 0x07;0x07为字符属性
	inc di
	loop shownum
	
	jmp $
	
	times 510-($-$$) db 0
	db 0x55, 0xaa	

在8086中push默认为一个字

栈的推进方向是从高地址到低地址的,据此可以理解push和pop

逻辑或和逻辑与

;or:有一个为1,则输出1,否则为0
;and:两个一样,则输出1,否则为0

8086寻址的方式

寄存器、立即数和立即寻址

;目的操作数是寄存器,因此是寄存器寻址
mov ax, cx
add bx, 0xf000
inc dx
;如果源操作数的内存地址指定的,则是立即数寻址
add bx, 0xf000
mov dx, mydata
;直接内存寻址
mov ax, [0x5c0f]
add word [0x0130], 0x5000
add word [es:di], 0x5000

基址寻址

	mov bx, buffer
lp:
	inc word [bx];bx是基址寄存器

变址寻址

	mov si, buffer
lp:
	inc word [si+0x100];si是变址寄存器

基址变址寻址

	mov bx, buffer
	mov si, 0
lp:
	inc word [bx+si];bx是基址寄存器

猜你喜欢

转载自blog.csdn.net/qq_48322523/article/details/121026962