跳过非指令的数据区
一般来说,所有处理器指令都应当按顺序存放,在它们中间不允许夹杂非指令的普通数据,因为他们不能作为指令执行,所以要想办法让处理器执行不到这些非指令的内容,比如jmp指令等
在数据声明中使用字面值
char db 'L', 0x07 \
'a', 0x07
编译阶段会将这些字面值转换成等价的ASCII代码,在NASM中\
是续行符,表明下一行应该与当前行合并
段之间的批量数据传送
批量数据传送的指令是movsb 和 movsw
,b表示传送以字节为单位,w表示传送以字为单位
这两个指令执行时的前置条件:
- DS:SI指向原始数据串,ES:DI指向传送的目的地址
- 传送次数由CX指定
- 传送的方向由标志寄存器的DF位决定,0---正向,1---反向
- 正向传送,低地址--->高地址,执行cld
指令将DF置0
- 反向传送,高地址--->低地址,执行std
指令将DF置1
; 数据
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\
'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
number db 0,0,0,0,0
...
...
; 批量数据传送的代码
cld
mov si,mytext ; 设置原数据串的偏移位置
mov di,0 ; 设置目的地址的位置位置
mov cx,(number-mytext)/2 ; 实际上等于 13,除以2是因为一次传送2个字节
rep movsw ; rep表示重复执行,知道cx为0
使用循环分解数位
loop指令也相当于跳转指令,跳转的是相对量,循环次数由CX指定
并且loop指令是先将CX的值减1,在跳转,若CX的值为0,则退出循环
我们可以将loop指令的循环理解为先执行,后判断
;得到标号所代表的偏移地址
mov ax,number
;计算各个数位
mov bx,ax
mov cx,5 ;循环次数
mov si,10 ;除数
digit:
xor dx,dx
div si
mov [bx],dl ;保存数位
inc bx ; inc 指令表示加1,dec指令表示减1
loop digit ; 跳转到digit标号处继续执行
无符号数和有符号数
- neg 指令:
neg al
,表示用0减去al中的值,并将其存储到al中 - idiv 指令: 与div用法相同,不同的是idiv是用于有符号数的计算,而div用于无符号数的计算(注意有符号数的扩展)
- 有符号数的扩展:计算机根据最高位来判断有符号数的正负,1位负,0为正,所以当16为有符号数扩展到32位时,正数没什么问题,高16位全是0,负数就要注意了,高16位应该全是1
- cbw指令,将AL中的有符号数扩展到整个AX(convert byte to word)
- cwd指令,将AX的有符号数扩展到DX:AX(convert word to double word)
其他标志位和条件转移指令
- 标志位
- 奇偶标志位PF: 运算结果低8位有偶数个1的比特,PF=1,反之,PF=0
- 进位标志位CF:进行算术操作时,最高位有向前进位或借位时,CF=1.反之,CF=0 (inc指令和dec指令无需记录)
- 溢出标志位OF:超出目标操作数所能容纳的范围,OF=1,反之,OF=0
- 条件转移指令
- 可以根据实际计算结果的标志位进行条件转移
- cmp指令:用于比较操作数,不同的是cmp仅仅根据比较结果设置标志位,而不保留计算结果,不改变原有的内容
cmp 目的操作数, 源操作数
,重点关心目的操作数,比如cmp ax, bx
,我们关心的是ax的内容是大于bx还是等于bx,bx仅仅是一个测量基准
NASM编译器的$和$$标记
$
标记:可以看成是当前行行首的标号 (即 当前行的汇编地址)$$
标记:代表当前汇编段的起始汇编地址
bochs调试命令
n
命令:可以跳过循环, 但对条件转移指令造成的循环无效u
命令:反汇编,将机器码翻译成可读的汇编指令,u/n 0xb8000
表示从0xb8000这个地址开始反汇编n条指令- 如何越过条件转移指令构造的特殊循环体:
- 先用u命令反汇编,找到条件转移指令的下一条指令A
- 在用b命令对指令A设置断点
- 在用c命令继续执行到断点处
- 用
info
命令查看标志位
输入info eflags
,会跳出标志位的名称,大写表示为1,小写表示为0
思考题
以下程序会执行多少次
mov cx, 0
delay: loop delay
首先loop会将cx的值减1,也就是cx的值为-1,即0xFFFF, 执行1次
然后loop在将cx的值减1,也就是cx的值为-2,即0xFFFE, 执行2次
...
最后.......................cx的值为-65535,即0x1 0000, 舍去最高位1(超出16位), cx的值为0x0000即0,跳出循环,执行65535次
在 x86 的寄存器中,减一操作(SUB 指令)会按照二进制补码进行运算。当寄存器的值为 0 时,再次减一会导致它变成全1的补码形式。因此,CX 寄存器的值会从0xFFFF 到 0x0000
在我想来应该是这样,有错误请大家纠正
完整源码
;代码清单6-1
;文件名:c06_mbr.asm
;文件说明:硬盘主引导扇区代码
;创建日期:2011-4-12 22:12
jmp near start
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\
'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
number db 0,0,0,0,0
start:
mov ax,0x7c0 ;设置数据段基地址
mov ds,ax
mov ax,0xb800 ;设置附加段基地址
mov es,ax
cld
mov si,mytext
mov di,0
mov cx,(number-mytext)/2 ;实际上等于 13
rep movsw
;得到标号所代表的偏移地址
mov ax,number
;计算各个数位
mov bx,ax
mov cx,5 ;循环次数
mov si,10 ;除数
digit:
xor dx,dx
div si
mov [bx],dl ;保存数位
inc bx
loop digit
;显示各个数位
mov bx,number
mov si,4
show:
mov al,[bx+si]
add al,0x30
mov ah,0x04
mov [es:di],ax
add di,2
dec si
jns show
mov word [es:di],0x0744
jmp near $
times 510-($-$$) db 0
db 0x55,0xaa
标签:0x07,cx,段间,chapter6,mov,指令,------,ax,bx
From: https://www.cnblogs.com/winter-z/p/18340845