百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

一步步编写操作系统 76 用汇编语言编写字符打印函数

citgpt 2024-08-05 13:50 7 浏览 0 评论

之前咱们介绍显卡上那么多的寄存器终于发挥用处了,我们看看前文中介绍的表CRT Controller Data Registers中索引为0Eh的 Cursor Location High Register寄存器和索引为0Fh的Cursor Location Low Register寄存器,这两个寄存器都是8位长度。分别用来存储光标坐标的低8位和高8位地址。

访问CRT controller寄存器组的寄存器,需要先往端口地址为0x3D4的Address Register寄存器中写入寄存器的索引,再从端口地址为0x3D5的Data Register寄存器读、写数据。

一步步编写操作系统 76 用汇编语言编写字符打印函数

接着解释之前的代码(本文是连载,没看过前面,估计本节是蒙逼的)

 1 TI_GDT equ 0
 2 RPL0 equ 0
 3 SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0
 4
 5 [bits 32]
 6 section .text
 7 ;------------------------ put_char -----------------------------
 8 ;功能描述:把栈中的1个字符写入光标所在处
 9 ;-------------------------------------------------------------------
 10 global put_char
 11 put_char:
 12 pushad ;备份32位寄存器环境
 13 ;需要保证gs中为正确的视频段选择子,
 ;为保险起见,每次打印时都为gs赋值
 14 mov ax, SELECTOR_VIDEO ; 不能直接把立即数送入段寄存器 
 15 mov gs, ax
 16
 17 ;;;;;;;;; 获取当前光标位置 ;;;;;;;;;
 18 ;先获得高8位
 19 mov dx, 0x03d4 ;索引寄存器
 20 mov al, 0x0e ;用于提供光标位置的高8位
 21 out dx, al
 22 mov dx, 0x03d5 ;通过读写数据端口0x3d5来获得或设置光标位置
 23 in al, dx ;得到了光标位置的高8位
 24 mov ah, al
 25
 26 ;再获取低8位
 27 mov dx, 0x03d4
 28 mov al, 0x0f
 29 out dx, al
 30 mov dx, 0x03d5
 31 in al, dx
 32
 33 ;将光标存入bx
 34 mov bx, ax
 35 ;下面这行是在栈中获取待打印的字符
 36 mov ecx, [esp + 36] ;pushad压入4×8=32字节,
 ;加上主调函数4字节的返回地址,故esp+36字节
 37 cmp cl, 0xd ;CR是0x0d,LF是0x0a
 38 jz .is_carriage_return
 39 cmp cl, 0xa
 40 jz .is_line_feed
 41
 42 cmp cl, 0x8 ;BS(backspace)的asc码是8
 43 jz .is_backspace
 44 jmp .put_other

在代码第17~31行用来获取光标值,先在第19~21行设置待操作的寄存器索引,我们先获取的是坐标的高8位,所以要将索引0x0e写入Address Register寄存器,其端口为0x03d4。

确定了要操作的寄存器是Cursor Location High Register后,我们在第22~24行通过Data Register寄存器,其端口是0x3d5,将坐标读入到al寄存器,由于al中是坐标的高8位,所以第24行将其存储在ah寄存器。也许您心存疑惑,既然要把坐标的高8位存到寄存器ah中,为什么不把in指令中的al换成ah,变成in ah, dx?还多捣腾一次干吗?真的抱歉,对于in指令,如果源操作是8位寄存器,目的操作数必须是al,如果源操作数是16位寄存器,目的操作数必须是ax。

第26~32行用同样的方法获取到坐标的低8位,至此,寄存器ax中是光标完整的16位坐标值。

第35行是将光标值从ax寄存器中复制到bx,这么做的原因是习惯用寄存器bx做基址寻址,还记得吗,在16位实模式下基址寄存器必须是bx或bp,变址必须是寄存器si或di。在32位保护模式下没必要这么做了,基址和变址寄存器可以是全部的32位的通用寄存器,就是刚才用pushad指令压入的那8个,忘了往上翻翻。以后的处理都要基于bx寄存器了,在此知道bx现在已经是光标坐标值就行了,它是下一个可打印字符的位置。

第36行是获取栈中压入的字符的ascii码,也就是待打印的字符,这是1字节的数据。栈中除了调用put_char函数的返回地址占4字节外,还有最开始的pushad指令压入的8个32位的通用寄存器共32字节的数据,所以待打印的字符在栈顶偏移36字节的位置。

之后的第36~44行开始判断参数是什么字符,咱们这里只把回车符CR(carriage_return)、换行符LF(line_feed)和退格键backspace当做不可见字符,按照其实际控制意义来处理,其它字符暂时一律认为是可见字符。回车符的ascii码是0xd,换行符的ascii码是0xa,我们这里的处理是,不管参数是回车符,还是换行符,一律按我们平时所理解的回车换行符(CRLF)处理(linux中就把换行符处理成回车+换行),即这两个动作的合成:光标回撤到行首+换到下一行。

本文是连续剧哦,所以得看过之前的文章才行。下班。

【再续】

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: