自制操作系统04

在今天的学习开始之前,先把windows下make环境搞好。之前以为要先安装MinGW才可以执行make命令,所以没有用windows下的make。而昨天看到要运行作者的代码,必须使用上作者的工具,而这些工具的使用并不需要第三方软件。
而make.exe也是其中一个工具,那么可能windows下的make命令只用这个文件就可以了。下面就主要在windows下做这些事情了。每个项目文件夹下有一个make.exe,再看makefile文件里有../z_tools/这样的相对路径。
那么我们每天首先需要做的事情就是把z_tools文件夹复制到每天的文件夹下,这样就可代码要求的路径一样了。
环境搭好后,再运行作者的代码真是太轻松了,控制台进入一个项目文件夹,输入make,回车,搞定。可以用虚拟机来运行生成的映像文件了。
说到这里,我有点失望了。说好自制的呢,怎么还得用工具?而且是作者写的专用工具,不是开源项目。作者的nask其实有源码,但又怎么样呢,以我现在的技术也不能编译和运行...
算了吧,还是搞点能搞明白的东西。作者即然改了编译器,那么原始的编译器是啥样的呢?

windowslinux
汇编C汇编C
ml.exe(编译器)

link.exe(连接器)


cl.exe vc编译,连接器

gcc mingw环境下编译,链接为exe文件

gcc  cygwin环境下编译,链接为linux下文件

nasmgcc


windows下可以从这里下载一个masm
http://www.masm32.com/download.htm
然后写一个masm的汇编程序:
.386
.model flat,stdcall
option casemap:none
;说明
includelib  msvcrt.lib
printf  PROTO C :ptr sbyte,:VARARG
;数据区
.data
szMsg   byte    "Hello World!",0ah,0
;代码区
.code
start:
    invoke printf,OFFSET szMsg
    ret
end start

可以注意到,这和我们之前写的汇编格式不一样。我们第一天的可以用nasm编译,这个可不行。可见我们的汇编程序并不是所有平台都可用,这也就是现在java能流行的原因,那个年代能做到一段代码能到多个平台运行的语言不多。
回到我们的自制操作系统问题上来,作者的HariMain(main)函数,离开了他的编译器就无法运行了。但我感觉还是要看下去,因为他也会从制作操作系统的角度来解释C语言,中断,IO,内存,并发等知识。但并不需要去详细分析每一句代码,
就算搞明白了,别的地方也用不上。所以后面的学习看到是通用的,就记下来,不是的就略过了。
好了,开始今天的内容。
先来一段汇编程序:
_write_mem8:    ; void write_mem8(int addr, int data);
        MOV        ECX,[ESP+4]        ; [ESP+4]にaddrが入っているのでそれをECXに読み込む
        MOV        AL,[ESP+8]        ; [ESP+8]にdataが入っているのでそれをALに読み込む
        MOV        [ECX],AL
        RET

这个和我们的高级语言的区别较大,明明是个_write_mem8函数,但两个参数 (addr,data)却根本没用,那还要他干啥?
哈哈,关键点在于这个ESP,回到第二天,有这么一句:
SP--stack pointer,栈指针寄存器
ESP就是extend stack pointer了,原来这就是函数的地址,函数地址+4就是addr的值(是个地址值),+8就是data的值。然后再把data写进addr。调用的c语言是这样:
for (i = 0xa0000; i <= 0xaffff; i++) {
    write_mem8(i, 15); /* MOV BYTE [i],15 */
}

i的范围应该是显卡的显示的地址范围,15表示是白色,最后就是全白了。
如果颜色值改成i&0x0f,那么低4位不变,高4位会变。
write_mem8(i, i&0x0f);
效果如下图 :


把i地址的改成指针,居然就代替了内存修改,顺便把颜色值改下:
int *p;
for (i = 0xa0000; i <= 0xaffff; i++) {
    //write_mem8(i, i&0x0f); /* MOV BYTE [i],15 */
    p=i;
    *p=i&0x02;
}
效果如下图 :


后面还有一个知识点:
如果p是指针(char *p),那么p[i]与*(p+i)等价。还有p[i]与i[p]等价。
c语言中,本文件后面的函数,其声明放前面。
后面设计到了中断,PUSHFD是push flags double-word(将EFLAGS的值保存进栈), POPFD是pop flags double-word(从栈里取值)。
_io_cli:    ; void io_cli(void);
        CLI    ;中断标志置为0
        RET
_io_sti:    ; void io_sti(void);
        STI ;中断标志置为1
        RET        
_io_load_eflags:    ; int io_load_eflags(void);
        PUSHFD        ; PUSH EFLAGS という意味
        POP        EAX
        RET

_io_store_eflags:    ; void io_store_eflags(int eflags);
        MOV        EAX,[ESP+4]
        PUSH    EAX
        POPFD        ; POP EFLAGS という意味
        RET
简单来说,就是cpu中间要插个任务,就要做做这些事。
能出条纹当然就能画矩形了,不过地址不一样。

同理,再画个windows的基本桌面样子。

看到这个样子,还是有点想去点的冲动。
文/中中 浏览次数:0次   2020-04-07 11:40:03

相关阅读


评论: