分类目录归档:汇编什么的

记录一次boot sector的编写

前段时间学了一点点关于操作系统的东西,跟着一本分析Linux 0.11 内核代码的书学习的,刚开始的时候,书中讲了关于编写引导区的东西,于是跟着书本上的内容进行实践,中间遇到了很多问题,不过最后还是一点一点解决了,于是打算记下来。

首先先说说引导区,当然指的是最传统的引导方式,不是新的efi方式啦。它是通过bios将驱动器中前512个字节的数据加载到内存当中,然后进行调用进行引导。

当然因为学识有限,先将自己知道的东西浅显的讲一下吧。在计算机刚上电的时候,处理器应该是初始化的状态,其代码指针会指向BIOS ROM所在的位置,通常是处理器可读内存的最高位之前的64KB。接下来BIOS会将其代码段复制到内存最开始1MB的后64KB当中,然后跳转到这个位置并将处理器调整进入实地址模式,初始化各个外设,等BIOS所有的工作完成之后,它会从硬盘或者其他的可以用来启动的存储设备上将其最前边的512字节加载到内存的0x7C00处,这也就是常说的7C00h或者7C00,我们可以认为,从这里开始,就是执行操作系统代码的最开始的地方。而经常听到的55AA则是这512字节的最后两个字节,只有最后两个字节为55AABIOS才会认为这段代码是正常可加载的。当然关于为什么是55AA,我也是不知道的,我在网上看到很多关于这个问题的讨论,说最开始是IBM公司定下的,也有人说是因为它好检测,也有人说它有一位错了很容易发现,真的没有人觉得有可能是最开始制定这个标准的工程师是一个像我这样逗比的人么?要是我的话我就弄成3838。别问我为什么。

接下来呢就是我们可以发挥想象的地方了,也就是说接下来我们可以对这个地方做手脚,想做什么就做什么,因为既然找到了操作系统的最开始的地方,我们也就有方法自己去修改它。

首先因为前面提到,BIOS在这里进入了实地址模式所以我们就可以参照Intel汇编的实地址编程方法。

以下为一段示例代码,其功能是在屏幕上显示一个字符串,并且实现将键盘输入显示到屏幕:

(双击代码区域复制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
.model small
 
.code
org 7c00h
jmp start
start:
mov ax,0
mov ss,ax
mov sp,7c00h
mov ds,ax
mov es,ax                 ;初始化各个寄存器
mov si, offset msg        ;设置字符串
mov al,[si]
mov cx,35                 ;设置字符串长度
mov dx,1000h              ;设置DH从屏幕起始行,DL从屏幕起始列。
mov bx,000ch              ;设置BH视频页,BL属性值
mov bp,msg                ;设置偏移地址
mov ax,1301h              ;设置为显示字符串功能
int 10h                   ;调用BIOS的10h功能
mov ah, 02h               ;设置复位光标功能
mov dl, 00h               ;复位到0列
mov dh, 00h               ;复位到0行
int 10h
putloop:
mov ah, 10h               ;设置读取键盘缓冲区
int 16h
cmp al, 0dh               ;判断是否为回车
je enterr
mov ah, 09h               ;不是回车则继续显示
mov bh, 00h
mov bl, 71h               ;设置字的颜色
mov cx, 01h
int 10h
mov ah, 03h
mov bh, 00h               ;显示从键盘读入的字符
int 10h
mov ah, 02h
add dl, 01h               ;光标右移
int 10h
jmp putloop
enterr:                   ;是回车
mov ah, 03h
mov bh, 00h
int 10h
mov ah, 02h               ;光标换行
mov dl, 00h
add dh, 01h
int 10h
jmp putloop
finish:
hlt
jmp finish
msg:
db 0dh,0ah
db "This is my boot, by Tifer King!"
db 0dh,0ah
db 00h
org start+200h-2
boot_signature:
db 055h,0aah              ;引导签名55AA
end

接下来就是编译这段代码,这可费了番周折,手头上有的汇编编译器是VS2015自带的MASM14.0,在网上看到很多人都说从MASM6.0以后就不能用来编译引导区了,需要下载MASM5.0版本,但是我觉得这有些荒诞,于是爬了很多帖,最后发现其实可以编译的。

打开VS2015的x86工具命令提示符,当然其实也可以直接打开cmd,不过需要自己手动添加masm的path就比较麻烦,而用VS2015命令行工具的好处就在于不用自己设置。然后将上述代码保存到boot.asm文件里边,然后cd到文件所在目录运行:

ml /omf boot.asm

然后就会生成一个boot.obj文件,当然这里链接就会出现问题,可能半天链接不上,没有关系,下载link16.exe,然后按照提示输入obj还有runfile,剩下的不用理会。

将生成的文件用winhex打开,然后将文件最后的512字节复制到硬盘的最开始。当然建议最好不要用自己的硬盘试,会丢失自己硬盘上的数据,因为相当于重建了mbr表。我是将其写入了虚拟机的虚拟硬盘当中运行。

运行效果:

2016-12-01_15-06-25

(完)

VS2015 搭建汇编编译环境 编译汇编

在编辑汇编程序的时候,可能一般情况下很多人会使用到像记事本或者notepad++这类工具,因为可以进行语法高亮,不过像我这样的懒人如果每次编辑完再去用命令行编译然后链接然后运行,再去找一个专门的调试器调的话,真的会把我烦死。所以我想能不能使用既傻瓜又强大的Visual Studio进行编译链接及调试的话(甚至附带性能分析)那简直是一种享受。不过这一切也不是没有可能。这里使用Visual Studio 2015 Community 版本进行演示

首先新建一个空项目:

vs-asm

再在源文件里边添加新项,注意后缀改为.asm

vs-asm2

然后再在设置里边更改设置如下:

vs-asm3

vs-asm7

在项目中右键选择生成依赖项->生成自定义:

vs-asm4

选择生成masm:

vs-asm5

然后再对着文件右键,选择属性,在项目类型中选择汇编:

vs-asm6

这时候就可以对汇编的代码进行编辑了,而且还可以进行编译和调试。

但是可能在编写的时候,没有语法高亮以及各种提示会显得非常的难用,没关系,有插件可以解决这个问题。即AsmDude。

vs-asm8

这样一来,问题就全部解决了~

vs-asm9

这里是插件的下载地址:AsmDude.vsix