前言
和汇编2的所要实现的东西一样,只是换了另外一种实现方法(更简洁),从而学习一些新的知识,新的指令。
代码展示
1 ;代码清单6-1
2 ;文件名:c06_mbr.asm
3 ;文件说明:硬盘主引导扇区代码
4 ;创建日期:2011-4-12 22:12
5
6 jmp near start ;相对偏移,跳到start块地方
7
8 mytext db ‘L’,0x07,‘a’,0x07,‘b’,0x07,‘e’,0x07,‘l’,0x07,’ ‘,0x07,‘o’,0x07,\ ;‘\’代表换行
9 ‘f’,0x07,‘f’,0x07,‘s’,0x07,‘e’,0x07,‘t’,0x07,’:’,0x07
10 number db 0,0,0,0,0
11
12 start:
13 mov ax,0x7c0 ;设置数据段基地址
14 mov ds,ax ;让DS直接指向0x7C0片段
15
16 mov ax,0xb800 ;设置附加段基地址
17 mov es,ax ;这里ES寄存器依然指向显存
18
19 cld ;把DF标志清0
20 mov si,mytext
21 mov di,0
22 mov cx,(number-mytext)/2 ;实际上等于 13
23 rep movsw ;重复执行movsw
24
25 ;得到标号所代表的偏移地址
26 mov ax,number
27
28 ;计算各个数位
29 mov bx,ax
30 mov cx,5 ;循环次数
31 mov si,10 ;除数
32 digit:
33 xor dx,dx
34 div si
35 mov [bx],dl ;保存数位,这里[寄存器]代表以寄存器的内容作为偏移地址
36 inc bx
37 loop digit
38
39 ;显示各个数位
40 mov bx,number
41 mov si,4
42 show:
43 mov al,[bx+si]
44 add al,0x30
45 mov ah,0x04
46 mov [es:di],ax
47 add di,2
48 dec si ;这个运算会影响到标志位SF,如果结果的最高位为0,则SF=0,反之为1
49 jns show ;这个指令指的是如果没有设置符号位(SF为0),则转移到show执行
50
51 mov word [es:di],0x0744
52
53 jmp near $ ;这个dollar符号就代表当前指令的汇编地址,这条语句等效于 infi:jmp near infi
54
55 times 510-(
−
-
−$) db 0 ;这个double dollar符号就代表当前程序端的汇编首地址,也就是0
56 db 0x55,0xaa
一些指令及知识点的说明
movsb和movsw
这两个指令都是把数据从内存的一个地方移到另一个地方,处理器把它们看作是数据串,只不过movsb的传送以字节为单位,而movsw以字为单位。
使用这两个指令需要的一些东西:
原始数据串的段地址由DS指定,偏移地址由SI指定,即DS:SI,目的地址在这个程序是由ES:DI指定的(也就是显示缓冲区),CX代表传送的字节或者字数,每传一个字或者一个字节,CX会减1,类似于计数器。还有一个特殊的寄存器:标志寄存器FLAGS,它的第6位 ZF标志 指定了这个是正向传送(低地址端到高地址端)还是反向传送(高地址端到低地址端)
rep
rep(repeat)命令 代表重复执行,在本程序中 代表CX不为0 则一直重复。
loop
处理器执行这个命令的时候
1.将寄存器CX的内容减去一
2.如果CX的内容不为0 则跳到指定位置处执行,否则执行后面的指令
inc和dec
inc是将目标操作数的内容加1 dec是将目标操作数的内容减1
neg
neg指令的操作数 可以是寄存器 也可以是内存单元
比如 al寄存器中的数为00010010,则neg al 执行之后,al中的内容变为 11101110
(也就是用0减去这个操作数了)
以寄存器的内容作为偏移地址
本程序也用到了,比如[bx],这里bx寄存器是被传入了number标号,也就是对应的一个汇编地址,使用[bx]就直接代表number了,也就是偏移地址了。
注意:在8086处理器上 如果要用寄存器来提供偏移地址 只能用BX SI DI BP,不能使用其他寄存器
SI DI寄存器 也一般被用来当作索引寄存器
计算机中对负数的处理
计算机分为有符号整数和无符号整数,有符号整数会把最高位当作符号位,为0则代表整数,为1代表负数。
计算机中产生的负数可以看作是0减去它对应的负数,然后根据寄存器的大小(比如有的是8位,16位,32位)来保留位数。比如-1 可以看成是0-1,也就是00000000-00000001 然后其实会得到
…11111111,然后左边是无限借位的,如果是8位寄存器,那就只能截取8位保存了,也就是11111111,所以-1在8位寄存器里面实际上是以11111111保存的。用0减去负数,可以得到对应的正数
有一个问题 :
假如AX寄存器中的内容是0xB23C,那么它到底是无符号整数45628,还是-19908?
其实如果是做加减法的话,怎么看待它,取决于自己,只不过在进行加减法的时候,你的角度需要统一。要么都看作无符号的,要么都看作有符号的
但是 div指令只针对无符号的,要想针对有符号,得用idiv
标志位
在处理器进行算术逻辑运算的时候,都会影响到标志寄存器的某些位。
奇偶标志位PF: 当运算结果出来的时候,如果最低8位中 有偶数个1 则PF=1 否则PF=0
mov ax,1000100100101110B
xor ax,3
执行以上两条指令之后,结果是1000100100101101B 低8位是 00101110B ,有偶数个1 所以PF=1
这样的标志位还有很多很多,比如 进位标志CF 溢出标志OF 这里不一 一 列举了。
两个程序的比较
第二个程序更精简,从代码行数就可以看出来,用了循环,把很多实现模块化了,没有用mov指令,一个一个去移动,而是使用到了movsb和movsw指令,用索引进行移动。两个程序主体的思想是基本一样的。