用x86机器码写hello world(中)

By | 2015年1月17日

前面讲到的都是一些需要了解的基础知识

不过知道上面那些东西还远远不够

本文就将介绍一些编程中必须知道的知识。

在“上”中,我们知道了BIOS程序会将引导程序加载入内存,问题是加载到哪儿呢?

这个问题值得讨论,因为不知道程序在内存中的位置,我们就很难控制程序的执行。

这个问题的答案是0x7c00

为什么会选择这样一个奇葩地址,而不是0x0000之类的方便易记的地址,当然是有原因的。这里就不介绍了,有兴趣希望了解的可以使用百度、谷歌搜索。

086的寻址方式

因为8086的cpu是16位的,理论上来说,16位的总线最多能访问2^16=64KB的内存(16根总线一共可以表示65536种不同的地址,因为内存是字节寻址,一个字节1Byte,所以就是64KB),这么点内存在当时也是捉襟见肘的。

为了能让cpu控制更多的内存,就必须增加控制总线的数量,于是乎8086就设计出了20位的寻址总线,也就是2^20=1MB,这样内存总算够用了。但是寄存器还是16位的呀,怎么办呢。8086就使用了一种非常奇葩的方法,一个寄存器不够,那我们就用两咯,一个叫做段地址,一个则是偏移地址

我们把一栋楼房当作一块内存,一共有2000个房间,房间按照0000-2000顺序编号(这就是物理地址)。

但是由于偷工减料,现在一个门牌号只能写三个数字。为了解决门牌号的问题,我们可以把这栋楼分成多个单元(段)一个单元又分成多个房间。

假设一个单元有100个房间,那么0106号房间就是“二单元006”,其中二单元写在门牌A上,006则写在B上,这就是逻辑地址。

知道了逻辑地址,我们就可以把它换成物理地址,你应该看得出来,换算关系就是把门牌A的值-1,然后乘100,再加上门牌B的值。(2-1)*100+006=0106

在CPU中,门牌A就是段寄存器,保存的地址叫做段地址。门牌B则是指针寄存器,保存的值叫偏移地址。

在访问内存时,cpu将段地址左移四位,再加上偏移地址,就合成了20位的地址

如段地址为0x72,偏移地址为0x25,段地址偏移后的值为0x720,加上偏移地址就成了0x745.

因为16位最大是65536,也就是64kb,因此我们可以得出结论,每一个段最多是64k。

和上面楼房的地址不同,段是可以重叠的,比如你可以将0x100-0x1ff作为一个段,将0x101-0x200作为另一个段。也就是说一个物理地址对应多个逻辑地址

如何显示内容

在c语言中,我们可以很简单的使用printf来输出一个字符串

但是在汇编下可没有这东西。

我们需要直接控制显示器按照我们的需要显示信息。

如果你凑近看的话,就会发现显示器上有很多个小点,我们只需要控制这些小点,让他们以字符的样子显示出来就行了

你可能会跳起来说,这怎么控制!

别急嘛,且听我慢慢说。

对显示器来说,文字也好,图形也好,都是一堆堆的像素点,区别仅仅是他们的组合不同而已。但是如果让我们来控制这些像素,就显得非常困难并且麻烦了。

于是人们就制造了一个专门的硬件,让他来负责控制这些像素点。这就是显卡

显卡有一块内存,叫显存,我们只需要把字符写入显存,显卡就会帮助我们将他显示在屏幕上。字符使用的是ASCII码

由于显存是位于显卡上的,如果访问显存也需要通过显卡这个外围设备打交道的话,就显得有些麻烦了,毕竟多了一道手续了嘛!

于是聪明的人们想出来一个叫做“映射”的方法。即将显存当作内存(毕竟都是ram),映射到内存地址中,这样就可以直接使用cpu访问显存了。这块“内存”和普通内存没什么两样,唯一的区别就是你写在里面的数据显卡经过一定的处理显示在屏幕上而已。

086下0X00000-0X9FFFF是留给普通内存的,后面的0XF0000-FFFFF则是存放BIOS的芯片。中间0XA0000-EFFFFF的320k字节,则由各种外围设备提供,比如显卡。

显存的范围是0xB8000-0XBFFF,除非你的显卡出了毛病。否则这个地址肯定是可以访问的!

由于历史原因,显卡在启动后,会自动的被初始化为80×25的文本模式,一共两千个字符。

0xB8000就对应屏幕的左上角第一个字符,然后是往右依次类推

和用c语言的printf输出不同的是,一个字符并不是占用一个字节,而是两个。

第一个字节是字符的ASCII,第二个字节指定了字符的显示属性,比如颜色,是否闪烁(某些人想尽各种办法希望给命令行窗口中的文字加上不同的颜色,殊不知操作显存控制颜色竟是如此方便)

颜色分为前景色和背景色,格式如下

显示属性的格式

显示属性的格式

RGB控制颜色,它们对应的意义都在下表中给出(数据摘自《X86汇编语言从实模式到保护模式》李忠、王晓波、余洁著,P51)

文本模式颜色表

文本模式颜色表

比如我们要黑底白字无闪烁(也就是用的最多的模式),他的属性值就是

K=0,RGB=000;I=0,RGB=111,合起来就是00000111b

换成16进制则是0x07

假设我们需要显示一个黑底白字的无闪烁字母H,0xb8000的位置就是H的ASCII码(0x48),后面接着的0XB8001就是显示属性0x07.

你可能会好奇,屏幕上一片漆黑,啥都没有的时候显存里面是什么东西?还能是什么?空格呗!

One thought on “用x86机器码写hello world(中)

  1. Pingback: 用x86机器码写hello world(上) | 仰望苍天思寰宇

发表评论

电子邮件地址不会被公开。 必填项已用*标注