汇编语言有关在屏幕区显示字符的四种方法(推荐)

李忠老师的《x86汇编语言:从实模式到保护模式》中第五章到第七章的部分,每一章在讲述知识点的同时,分别使用了三种不同的显示字符的方法,加上调用BIOS的10h中 断的方法,这里做出一次简单梳理:

一:第五章,最基础的直接用mov 的方法

代码如下:

;代码清单5-1
     ;文件名:c05_mbr.asm
     ;文件说明:硬盘主引导扇区代码
     ;创建日期:2011-3-31 21:15 

     mov ax,0xb800         ;指向文本模式的显示缓冲区
     mov es,ax

     ;以下显示字符串"Label offset:"
     mov byte [es:0x00],'L'
     mov byte [es:0x01],0x07
     mov byte [es:0x02],'a'
     mov byte [es:0x03],0x07
     mov byte [es:0x04],'b'
     mov byte [es:0x05],0x07
     mov byte [es:0x06],'e'
     mov byte [es:0x07],0x07
     mov byte [es:0x08],'l'
     mov byte [es:0x09],0x07
     mov byte [es:0x0a],' '
     mov byte [es:0x0b],0x07
     mov byte [es:0x0c],"o"
     mov byte [es:0x0d],0x07
     mov byte [es:0x0e],'f'
     mov byte [es:0x0f],0x07
     mov byte [es:0x10],'f'
     mov byte [es:0x11],0x07
     mov byte [es:0x12],'s'
     mov byte [es:0x13],0x07
     mov byte [es:0x14],'e'
     mov byte [es:0x15],0x07
     mov byte [es:0x16],'t'
     mov byte [es:0x17],0x07
     mov byte [es:0x18],':'
     mov byte [es:0x19],0x07

     mov ax,number         ;取得标号number的偏移地址
     mov bx,10

     ;设置数据段的基地址
     mov cx,cs
     mov ds,cx

     ;求个位上的数字
     mov dx,0
     div bx
     mov [0x7c00+number+0x00],dl  ;保存个位上的数字

     ;求十位上的数字
     xor dx,dx
     div bx
     mov [0x7c00+number+0x01],dl  ;保存十位上的数字

     ;求百位上的数字
     xor dx,dx
     div bx
     mov [0x7c00+number+0x02],dl  ;保存百位上的数字

     ;求千位上的数字
     xor dx,dx
     div bx
     mov [0x7c00+number+0x03],dl  ;保存千位上的数字

     ;求万位上的数字
     xor dx,dx
     div bx
     mov [0x7c00+number+0x04],dl  ;保存万位上的数字

     ;以下用十进制显示标号的偏移地址
     mov al,[0x7c00+number+0x04]
     add al,0x30
     mov [es:0x1a],al
     mov byte [es:0x1b],0x04

     mov al,[0x7c00+number+0x03]
     add al,0x30
     mov [es:0x1c],al
     mov byte [es:0x1d],0x04

     mov al,[0x7c00+number+0x02]
     add al,0x30
     mov [es:0x1e],al
     mov byte [es:0x1f],0x04

     mov al,[0x7c00+number+0x01]
     add al,0x30
     mov [es:0x20],al
     mov byte [es:0x21],0x04

     mov al,[0x7c00+number+0x00]
     add al,0x30
     mov [es:0x22],al
     mov byte [es:0x23],0x04

     mov byte [es:0x24],'D'
     mov byte [es:0x25],0x07

  infi: jmp near infi         ;无限循环

 number db 0,0,0,0,0

 times 203 db 0
      db 0x55,0xaa

这里采用的最基础的做法,就是对字符进行一个一个的处理。先将显示缓存区的地址0xb800赋给es寄存器,然后通过 mov byte[es:0x00],'L' 的形式,来处理后续的字符。这种方法较为简单,这里不再赘述。

    二:第六章,采用了批量处理的方法

代码如下:

;代码清单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

这里采用的办法是批量传送,后续用loop循环挨个处理。这样的写法明显比上一种写法要高明一些,减少了工作量。这段代码中值得注意的地方是   mov si,mytext  (其中mytext是声明的字符的地址),这里值得留意的原因之一是在做显示时间的编码中,有过下列这样的写法,所以会格外的留心。

org 7c00h
start1:
  mov  ax, cs       ; 置其他段寄存器值与CS相同
  mov  ds, ax       ; 数据段
  mov es, ax
  mov bl, 10h
  mov bp, Message1
  mov ah, 02h
  int 1ah
  xor ax, ax
  mov al, ch
  div bl
  add al, 0x30
  mov [es:bp+2], al
  add ah, 0x30
  mov [es:bp+3], ah
  xor ax, ax
  mov al, cl
  div bl
  add al, 0x30
  mov [es:bp+5], al
  add ah, 0x30
  mov [es:bp+6], ah
  xor ax, ax
  mov al, dh
  div bl
  add al, 0x30
  mov [es:bp+8], al
  add ah, 0x30
  mov [es:bp+9], ah
  mov dh, 3
  mov dl, 0
  mov ax, 1301h   ; 功能号
  mov bp, Message1
  mov cx, MessageLength1
  mov bx, 0007h
  int 10h
;  ret
Message1:
db ' 00:00:00'
MessageLength1 equ ($-Message1)
   times 510-($-$$) db 0  ; 用0填充引导扇区剩下的空间
  db   55h, 0aah        ; 引导扇区结束标志

(上面的那段代码的功能是调用BIOS中断显示系统时间)这段代码中对于“00:00:00”的处理方法,代码二中批量处理si处的mytext字段有异曲同工之妙,这里mark一下。

关于代码二中显示数字的方法,是用到了loop循环。先将数字按照“除以10”的方法得到每一位的值,然后将其加上0x30(有关ASCII的知识可解释这一点是为什么),然后将最终值赋予  依次递增的显存地址对应的内容,直到将之前处理的每一位数字都显示出来,over.

      三:第七章,使用栈来操作

这一章的代码的特殊之处在于通过将字符串按照一个一个的顺序分别取到之后,将其按照顺序压栈,然后再依次出栈再处理而显示。

;代码清单7-1
     jmp near start
 message db '1+2+3+...+100='
 start:
     mov ax,0x7c0      ;设置数据段的段基地址
     mov ds,ax
     mov ax,0xb800     ;设置附加段基址到显示缓冲区
     mov es,ax
     ;以下显示字符串
     mov si,message
     mov di,0
     mov cx,start-message
   @g:
     mov al,[si]
     mov [es:di],al
     inc di
     mov byte [es:di],0x07
     inc di
     inc si
     loop @g
     ;以下计算1到100的和
     xor ax,ax
     mov cx,1
   @f:
     add ax,cx
     inc cx
     cmp cx,100
     jle @f
     ;以下计算累加和的每个数位
     xor cx,cx       ;设置堆栈段的段基地址
     mov ss,cx
     mov sp,cx
     mov bx,10
     xor cx,cx
   @d:
     inc cx
     xor dx,dx
     div bx
     or dl,0x30
     push dx
     cmp ax,0
     jne @d
     ;以下显示各个数位
   @a:
     pop dx
     mov [es:di],dl
     inc di
     mov byte [es:di],0x07
     inc di
     loop @a
     jmp near $
times 510-($-$$) db 0
         db 0x55,0xaa

对于代码段四,第一部分显示“1+2+3+4+...+100=”的部分是沿用了上面的代码二中的做法,使用loop循环处理。

而下面处理数字的部分,是一种新的处理方式。这里是将数字依次“除以10”得到每一位的数之后,将其加上0x00(原因:ASCII显示字符需要)压入栈中,然后在下一个循环中,依次出栈并且处理使得其能够显示出来。

     四:调用BIOS的10h中断来显示字符

以上,无论是最简单的mov的做法,还是movbw的做法,异或压栈出栈的做法,都难免分别处理每一个字符的圈子。这里介绍一种调用BIOS中断的做法,直接处理一串字符串,较为简单,可参考性高。

org 07c00h ; 告诉编译器程序加载到 7c00处
  mov ax, cs
  mov ds, ax
  mov es, ax
  call DispStr ; 调用显示字符串例程
  jmp $ ; 无限循环
DispStr:
  mov ax, BootMessage
  mov bp, ax ; es:bp = 串地址
  mov cx, 16 ; cx = 串长度
  mov ax, 01301h ; ah = 13, al = 01h
  mov bx, 000ch ; 页号为 0(bh = 0) 黑底红字(bl = 0Ch,高亮)
  mov dl, 0
  int 10h ; 10h 号中断
  ret
BootMessage:
  db "Hello, OS world!"
  times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为
  dw 0xaa55 ; 结束标志 

这里的做法是调用BIOS的10h中断来显示“Hello,OS world!”,其中bp为字符串地址,cx为串长度,ah为功能号,al指示光标置于串尾,bx指示页号为0然后字符显示属性为黑底红字,dh为行号,dl为列号(如果不做处理的话,默认dh,dl皆为0,即在第0行第0列显示),参数设置完之后则调用10h中断显示字符串。

总结:以上的四种方法,通过学习不仅了解显示的方法,更重要的是对汇编语言有了更多的认识。以上方法在实际操作中介于方便与否,大多采用的直接调用BIOS的10h 中断来操作。

以上所述是小编给大家介绍的汇编语言有关在屏幕区显示字符的四种方法,希望对大家有所帮助!

(0)

相关推荐

  • 使用汇编实现字符串的大小写转换

    使用汇编编程,可以直接访问内存中的数据,对数据进行相关操作,现在需要通过汇编指令and,or对字符串数据进行大小写转换.如下例,将BaSiC转换成大写,将iNforMaTiOn转换成小写. 例子: assume cs:codesg,ds:datasg datasg segment db 'BaSiC' db 'iNforMaTiOn' datasg ends codesg segment start: mov ax,datasg mov ds,ax mov cx,5 mov bx,0 s1: m

  • 汇编语言实现在指定字符串中搜索字符'A'的方法

    我也不知道我以前怎么会写这种东西的,留个纪念- ;用串操作指令设计程序,实现在指定字符串中搜索字符'A', ;若该字条串中有字符'A', ;则将第一个'A'字符在该字符串中的位置记录在BX寄存器中, ;若不包含,则使BX=0FFFFH. ;在程序开始查找指定字符前要求在屏幕上输出提示信息: ;The program is running!查找结束后输出信息:the program is over! DATAS SEGMENT STRING DB 'CDAFX246hk' NO DW 10 FAL

  • 汇编语言有关在屏幕区显示字符的四种方法(推荐)

    李忠老师的<x86汇编语言:从实模式到保护模式>中第五章到第七章的部分,每一章在讲述知识点的同时,分别使用了三种不同的显示字符的方法,加上调用BIOS的10h中 断的方法,这里做出一次简单梳理: 一:第五章,最基础的直接用mov 的方法 代码如下: ;代码清单5-1 ;文件名:c05_mbr.asm ;文件说明:硬盘主引导扇区代码 ;创建日期:2011-3-31 21:15 mov ax,0xb800 ;指向文本模式的显示缓冲区 mov es,ax ;以下显示字符串"Label of

  • Python删除字符串中字符的四种方法示例代码

    目录 一.删除字符串两端的一种或多种字符 二.删除字符串中单个固定位置的字符 三.删除字符串中任意位置的一种或多种字符 四.同时删除字符串内的多种不同字符 一.删除字符串两端的一种或多种字符 #strip().lstrip().rstrip()方法:(默认删除空格符) A.list.strip(字符):删除字符串两端的一种或多种字符: 例:删除字符串s两端 a 或 b 或 c 字符: s = 'abbmmmcccbbb' s1 = s.strip('abc') print(s1) #输出:mmm

  • PHP去除字符串最后一个字符的三种方法实例

    前言 本文讲讲PHP中如何正确的去除字符串中的最后一个字符,之前跟大家分享过一篇关于PHP去除字符串最后一个字符的三种方法的文章,但是没给出实例,下面话不多说,直接上代码,相信一眼就能看出来了,直接将下面代码复制粘贴到自己本地服务器下,运行即可. 实例代码 $a = 'http://www.mafutian.net/'; $b = 'http://www.mafutian.net'; // 错误的方式: $len = strlen($a) - 1; $a{$len} = ''; // $a[$l

  • 解决EditText不显示光标的三种方法(总结)

    解决方法有以下3种 1.在Edittext中加入以下属性 android:cursorVisible="true" android:textCursorDrawable="@null" 2.在Edittext中加入以下属性 android:cursorVisible="true" android:textCursorDrawable="@drawable/test_cursor" 对应的drawable文件 <?xml

  • python实现每次处理一个字符的三种方法

    本文实例讲述了python每次处理一个字符的三种方法.分享给大家供大家参考. 具体方法如下: a_string = "abccdea" print 'the first' for c in a_string: print ord(c)+1 print "the second" result = [ord(c)+1 for c in a_string] print result print "the thrid" def do_something(

  • 总结PHP删除字符串最后一个字符的三种方法

    一.前言 从数据库中select()读取一对多的信息时,经常需要将取出的数组用某个特定的字符分割,然后拼接成字符串. 常见的语法格式: foreach ($arr as $key => $value) { $arr_str = $arr['x_id'] . ',' . $arr_str; } 假设字符数组 $arr 中的字符分别为 arr[0] = 'a'; arr[1] = 'b'; arr[2] = 'c'; 则,拼接后的 $arr_str 字符串为 a,b,c, 这个时候,就需要我们对最后

  • 区分中英文字符的两种方法(正则和charCodeAt())

    比如这次用到的我先前介绍过的Vanadium表单验证插件, 因为是E文中不存在占2个字符的字, 所以, 区分中英文字符就得自己扩展. 本文就将介绍两种区分中英文字符的方法: 利用正则和charCodeAt方法区分中英文字符. 区分中英文字符的两种方法: 正则和charCodeAt()方法@Mr.Think /*reset css*/ body{font-size:0.8em;letter-spacing:1px;font-family:\5fae\8f6f\96c5\9ed1;line-heig

  • Python 打印中文字符的三种方法

    方法一: 现在用 notepad++,在 UTF-8 格式下编写以下语句: #coding=utf-8 print"打印中文字符" 方法二: 用encode和decode 如: import os.path import xlrd,sys Filename='/home/tom/Desktop/1234.xls' if not os.path.isfile(Filename): raise NameError,"%s is not a valid filename"

  • Python 列表反转显示的四种方法

    第一种,使用reversed 函数,reversed返回的结果是一个反转的迭代器,我们需要对其进行 list 转换 listNode = [1,2,3,4,5] newList = list(reversed(listNode)) print(newList) #结果 [5,4,3,2,1] 第二种,使用sorted函数,sorted是排序函数,它是对一个列表进行排序后生成一个新的list列表,而sort则是在原来的列表上直接进行排序. listNode = [1,2,3,4,5] newLis

  • python读取并显示图片的三种方法(opencv、matplotlib、PIL库)

    前言 在进行图像处理时,经常会用到读取图片并显示出来这样的操作,所以本文总结了python中读取并显示图片的3种方式,分别基于opencv.matplotlib.PIL库实现,并给出了示例代码,介绍如下. OpenCV OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux.Windows.Android和Mac OS操作系统上. 它轻量级而且高效--由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口

随机推荐