x86汇编学习历程5----更紧凑科学的显示文字和数字
Posted 4nc414g0n
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了x86汇编学习历程5----更紧凑科学的显示文字和数字相关的知识,希望对你有一定的参考价值。
新知识点
定义存放字符串的数据区
当传送 文本和显示他们的指令过多时 便会显得臃肿
所以定义一个存放字符串的数据区,
当我们要使用他们的时候再用指令显示出来
这样负责显示的指令和显示的内容就无关了.
注意:换行可以使用 续行符‘\\’,
但我们通常在下一行加上一个 db 而不是使用‘\\’
如下所示
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',\\
0x07,'l',0x07,' ',0x07,'o',0x07,
db 'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
设置数据段基地址
mov ax,0x7c0
mov ds,ax
数据串传送指令movsb,movsw和标志寄存器FLAGS
注:8086以上处理器可以按双字及更多进行操作
在8086处理器中
movsb:按字节(byte)只能执行或传送一次
movsw:按字(word)只能执行或传送一次
要重复操作要加上rep前缀 如 rep movsw
rep重复的次数由寄存器cx指定
-------------------------------------------------------------
16位标志寄存器FLAGS:
按位:
|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
| | | | | |DF| | |SF|ZF| | | | | | |
DF: 方向标志
SF: 符号位
ZF: 零标志
(判断最近一次运算的结果是零或非零,如果是非零这一位为零反之为1)
传送前的准备工作:
DS:SI 原始数据串的段地址:偏移地址
ES:DI 目标位置的段地址:偏移地址
正向传送时,每进行一次movsb或movsw SI和DI的值自动加上传送的字节数
自动指向下一个传送的位置
反向传送时,每进行一次movsb或movsw SI和DI的值自动减去传送的字节数
自动指向下一个传送的位置
-------------------------------------------------------------
cld: 方向标志DF清零指令,将flags寄存器DF标志清零以指示传送为正方向
std: 与cld相反
$ 和 $$
这两个标记为NASM编译器特有的
$: 当前行的汇编地址
$$: 当前程序段的汇编地址
loop指令
用法:
loop 标号
如:
loop digit
loop指令编译之后操作码为E2 后面是8位相对偏移量
所以标号的位置不能太远
执行过程:
将cx减一,cx不为0,转到标号位置执行,
如为0,则顺序执行后面的指令
inc和dec指令
每个寄存器的用途参见计算机寄存器分类简介
在8086处理器中要使用寄存器提供偏移地址只能使用
BX SI DI BP 其他的都是非法的
inc:加一操作
用法:inc r/m
如:inc al 或 inc byte [0x2002]
dec:减一操作
用法:dec r/m
如:dec di 或 dec byte [0x2002]
代码
jmp start
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,
db 'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
start:
mov ax,0x7c00 ;//设置数据段基地址,此处ax只是一个介质
;//(主引导扇区加载的逻辑段地址为0x7c0)
mov ds,ax
mov ax,0xb800 ;//设置附加段基地址
mov es,ax
cld
;//方向标志清零指令,将flags寄存器DF标志清零以指示传送为正方向(与其相反的std)
mov si,mytext ;//由于设置了数据段基地址 mytext汇编地址为偏移地址
mov di,0 ;//文本的传送是从显存的起始位置开始的 即es附加段,di为偏移地址即为0
mov cx,(start-mytext)/2
;//设置cx,cx的值为rep的次数实际上等于13
rep movsw ;//按字操作
mov ax,number
mov bx,ax ;//得到标号所代表的汇编地址
mov cx,5 ;//loop循环次数
mov si,10 ;//除数10传送到寄存器si
digit:
xor dx,dx ;//dx清零
div si
mov [bx],dl ;//访问的偏移地址来自bx寄存器
inc bx ;//[bx]指向下一个0的地址
loop digit
;//开始显示各个数位
mov cx,5
show:
dec bx
;//在上一部分操作中最后我们把dx指向number的最后一个0处
;//所以显示时从尾部开始显示
mov al,[bx]
add al,0x30 ;//转换数字为字符编码
mov ah,04 ;//黑底红字
mov [es:di],ax ;//前面已将显存地址传给es且di位置为最后一个字符属性的位置
add di,2 ;//一个字符一个属性共一个字
loop show
jmp $ ;//跳到本行
number db 0,0,0,0,0 ;//用于临时存放余数
times 510-($-$$) db 0
db 0x55, 0xaa
使用bochs调试
我们设置断点来到指令’cld‘,指令r观察寄存器si和di内容
多次执行单步执行命令s后发现的确是按我们的逻辑进行
注:eflags为32位标志寄存器 如图小写代表为0 大写为1
基址变址寻址和条件转移指令
在8086处理器中
只允许以下几种基址变址组合:
bx + si
bx + di
bp + si
bp + di
标志寄存器FLAGS的第7位SF符号位
如果最近一次逻辑运算结果二进制最高位为1则将SF置为1反之置为0
(不一定是符号位处理器不管你是不是符号位只管最高位)
jns指令跳转指令:
如果标志寄存器FLAGS的第7位SF位为0就跳转为1就不跳转
我们改写loop digit后的代码
;//开始显示各个数位
mov bx,number
mov si,4
show:
mov al,[bx+si] ;//si的作用相当于索引
;//所以显示时从尾部开始显示
add al,0x30 ;//转换数字为字符编码
mov ah,04 ;//黑底红字
mov [es:di],ax ;//前面已将显存地址传给es且di位置为最后一个字符属性的位置
add di,2 ;//一个字符一个属性共一个字
dec si ;//最后一次si为-1
jns show ;//基于SF位决定是否跳转
jmp $ ;//跳到本行
number db 0,0,0,0,0
times 510-($-$$) db 0
db 0x55, 0xaa
第一次执行 dec si 后 si 为3 二进制为:0000 0000 0000 0011 SF位为0
最后一次执行 dec si 后 si 为-1 二进制为:1111 1111 1111 1111 SF为1
调试bochs虚拟机
设置断点到0x7c58 键入info eflags命令 可以看到位sf为0
多次执行c命令 可以看到最后SF为1
最后我们在vbox上直接显示结果
以上是关于x86汇编学习历程5----更紧凑科学的显示文字和数字的主要内容,如果未能解决你的问题,请参考以下文章