跳至主要內容
汇编语言一发入魂 0x0C - 解放生产力

在上一篇文章中,老李已经教大家将控制权从汇编语言转移到C 语言,但是我们的活动范围依然受限于512字节的引导扇区。今天老李就带领大家突破这512字节的限制,真正的解放生产力

前置知识

如果你一路跟着老李走过来,那么这些前置知识你应该已经掌握了。忘记也没关系,回过头再去看看就 ok 了。


未央大约 9 分钟汇编语言C 语言32位保护模式C 语言内联汇编
汇编语言一发入魂 0x0B - 拥抱 C 语言

汇编语言的基础已经讲了很多,也带领大家进入了保护模式。想必大家在学习进入保护模式这一章时就发现我们已经涉及了很多数据结构全局描述符表段描述符GDTR等。如果可以使用C 语言,将他们和struct对应起来那将会减少很多的工作量。今天老李就教大家如何从汇编语言过渡到C 语言


未央大约 7 分钟汇编语言C 语言32位保护模式C 语言
汇编语言一发入魂 0x0A - 进入保护模式

保护模式实际上很简单,只是概念比较多。今天老李就带领大家进入保护模式,然后在实操中逐一攻克每个概念。

进入保护模式

进入保护模式总共分三步。

  • 第一步,打开A20地址线。
  • 第二步,加载GDT
  • 第三步,将处理器切换到保护模式

下面我们就来详细讲解一下这三个步骤。

A20 地址线

众所周知,8086处理器有20根地址线,可访问的最大内存地址是0xfffff,即1MB32位处理器具有32根地址线,可访问的最大内存地址是0xffffffff,即4GB。在32位处理器刚面世的时候并没有太多针对32位处理器开发的软件,更多的是为8086开发的软件,计算机制造商为了能够兼容这些软件,便想出了一个办法,在计算机启动后将第21根地址线,即A20,置为0。这样,当地址超过0xfffff后,由于第21根地址线为0,所以地址又会绕回到0x00000开始。从外表上看就好像是一个16位的处理器。


未央大约 12 分钟汇编语言32位保护模式
汇编语言一发入魂 0x09 - 中断

中断

中断就是打断CPU当前的执行流程,让CPU去处理一下别的事情。当然,CPU也可以选择拒绝。

中断的分类

中断按中断源可以分为内部中断外部中断

内部中断

内部中断可以由中断指令int来触发,也可以是因为指令执行中出现了错误而触发,例如运算结果溢出会触发溢出中断;除法指令的除数为0会触发除法出错中断。

外部中断


未央大约 7 分钟汇编语言中断8259a
汇编语言一发入魂 0x08 - 过程调用中的参数传递

通常我们封装过程是为了方便调用,避免写重复的代码。过程调用时通常需要通过传递参数来控制过程的执行,今天我们来讲一讲参数传递时的一些规范和需要注意的地方。

先来看一个例子:

示例一

.code16

movw $0x7c00, %sp

callw set_cursor

jmp .

# 目的: 设置光标位置为 0
#
# 输入: 无
#
# 输出: 无
set_cursor:
  movw $0x3d4, %dx
  movb $0xe, %al
  outb %al, %dx

  movw $0x3d5, %dx
  movb $0, %al
  outb %al, %dx

  movw $0x3d4, %dx
  movb $0xf, %al
  outb %al, %dx

  movw $0x3d5, %dx
  movb $0, %al
  outb %al, %dx

  retw

.org 510
.word 0xAA55

未央大约 6 分钟汇编语言过程调用
汇编语言一发入魂 0x07 - 过程调用

前两篇文章中我们学习了如何控制屏幕光标,如何从硬盘读取数据。这种常用的功能我们希望将它封装成过程调用,类似于高级语言中的函数,这样当我们控制光标或者从硬盘读取数据时就不需要每次都写大段的重复代码了。

CPU中,执行的指令通过cs:ip来确定。过程调用实际上就是通过calllcall指令来修改ipcs:ip来达到跳转到另一段指令中执行的目的。

call指令通过修改ip来实现过程调用,因为只修改ip,所以被调例程与原例程在同一个代码段内,也称为近调用。处理器在执行call指令时先将call后面的第一条指令的偏移地址压栈,再通过操作数计算出新的ip替换当前ip


未央大约 7 分钟汇编语言过程调用
汇编语言一发入魂 0x06 - 硬盘操作

今天我们来学习如何从硬盘读取数据。主要从编程的角度来学习关于硬盘的知识,即学习如何通过端口控制硬盘。

硬盘

从存储数据的介质上区分,硬盘可以分为机械硬盘固态硬盘,机械硬盘采用磁性碟片来存储数据,固态硬盘通过闪存颗粒存储数据。从编程的角度看,固态硬盘是兼容机械硬盘的,所以我们以机械硬盘为例,简要介绍一下硬盘。

基础知识

机械硬盘主要由磁盘盘片、磁头、主轴与传动轴等组成,数据存放在磁盘盘片中。每个盘片分为上下两面,每面由一个磁头(Head)进行读写。磁头统一固定在同一个支架上,由步进电动机控制,同时在盘片的中心和边缘之间来回移动。当盘片高速旋转时,磁头每步进一次,都会从它所在的位置开始,绕着圆心“画”出一个看不见的圆圈,这就是磁道(Track)。磁道是数据记录的轨迹。因为所有磁头都是联动的,故每个盘面上的同一条磁道又可以形成一个虚拟的圆柱,称为柱面(Cylinder)


未央大约 7 分钟汇编语言硬盘操作
汇编语言一发入魂 0x05 - I/O接口技术

I/O接口用于CPU与外部I/O设备进行信息交换。例如与键盘、鼠标、打印机和显示等设备交互。I/O接口电路与总线系统看似很复杂,但是落实到汇编语言代码上实则是很简单的。下面简要介绍一下I/O接口技术。

I/O 接口技术

在计算机中,CPU与外设并不是直接相连的,在它们中间设有I/O接口电路。CPU通过数据总线、地址总线和控制总线与I/O接口电路相连,以实现与外设交换数据信息、状态信息和控制信息。外设的状态信息通过接口电路的状态端口经由数据总线进入CPU,而CPU向外设发出的控制信号也是经由数据总线,通过接口电路的控制端口来实现的。


未央大约 8 分钟汇编语言I/O
汇编语言一发入魂 0x04 - 堆栈

上一篇文章中我们实现了数字各个位的分解并打印在屏幕上。他需要我们知道数字有多少个位,并且提前预留出内存空间保存每个位,这显然不是一个完美的解决方案。现在我们来学习一下堆栈,并使用堆栈来保存分解出的每个位,实现可以分解任意位的数字。

先解释一下堆栈。实际上这个堆栈堆(heap)并没有关系,只是一个纯粹的栈(stack),可能是堆栈这样叫起来更上口一点吧。

堆栈段和其他段一样,只是一段普通的内存空间,只是我们限制了对这部分内存空间操作的行为。我们只允许通过push(压栈)pop(出栈)这两个指令来操作堆栈段的内存空间,以此来实现一些算法。使用堆栈段之前需要先初始化段基址(ss)栈顶指针(sp),例如将ss初始化为0x0000sp初始化为0x7c00。此时堆栈段的逻辑地址为0x0000:0x00000x0000:0x7c00,对应的物理地址为0x000000x07c00


未央大约 6 分钟汇编语言堆栈
汇编语言一发入魂 0x03 - 更多的指令

上一篇文章中我们学习了指令的寻址方式,实际上是借具体的代码总结了一下寻址方式。这篇文章我们将学习更多的指令,通过实际代码的讲解,找到写汇编语言代码的感觉。下面先来讲一下串操作指令。

串操作指令

含义:通过执行一条字符串操作指令,对存储器中某一个连续的内存中存放的一串字或字节均进行同样的操作,称为串操作。字符串操作指令简称为串操作指令。


未央大约 9 分钟汇编语言寻址方式
2