自制操作系统笔记-第四章

4.1 用C语言实现内存写入

想要在屏幕上画点东西的话,只要在VRAM里写点什么,但是C语言没有直接写入内存地址的语句(其实有),我们创建一个这种函数。

修改一下前面的naskfunc.nas,这是添加的部分:

_write_mem8:    ; void write_mem8(int addr, int data);
        MOV        ECX,[ESP+4]        ; [ESP+4]中存放的是地址,将其读入ECX
        MOV        AL,[ESP+8]        ; [ESP+8]中存放的是数据,将其读入AL
        MOV        [ECX],AL
        RET

类似C语言中的write_mem8(0x1234,0x56),动作上相当于 MOV BYTE[0x1234], 0x56。addr是address的缩写,表示地址。

在C语言中如果用到write_mem8函数,就会跳转到_write_mem8(这个应该也是规定,书上并没有解释)。 参数指定的数字就会存放在内存中(又是规定):

第一个参数存在 [ESP + 4]

第二个参数存在 [ESP + 8]

第三个参数存在 [ESP + 12]

第四个参数存在 [ESP + 16]

在指定内存地址的地方,如果使用16位寄存器指定[CX] 或 [SP] 之类的就会出错,但使用32位寄存器,[ECX]、[ESP]等都OK。基本上没有不能用的寄存器。指定地址时还可以往寄存器里加一个或减一个常数的方式,如上面的 [ESP + 4] 。

与C语言联合使用的话,能自由使用的只有EAX、ECX、EDX这3个,至于其它寄存器只能使用其值,而不能改变其值,因为这些寄存器在C语言编译后生成的机器语言中,用于记忆非常重要的值。

所以上面代码中读取第一个参数(即 MOV ECX, [ESP+4] )中用的是ECX,ECX就是与C语言联合使用时可以自由使用的寄存器,而这句中的ESP则只是使用(读取)其值。

---------------------------------------------------------------------------------

naskfunc.nas 还加了一行  INSTRSET指令,告诉nask这个程序是给486用的,也就是说,EAX会被解释成寄存器,否则会把EAX理解为标签或常数。

[FORMAT "WCOFF"]                ; 创建一个目标文件    
[INSTRSET "i486p"]          ; 要使用486的指令(即这是32位CPU的程序),我猜i486p代表intel 486 program
[BITS 32]                        ; 制作32位的机器码
[FILE "naskfunc.nas"]            ; 源文件名

 这里虽然写着i486p,但并不是说386不能用,但必须是32位以上CPU,286以下的是16位CPU。

----------------------------------------------------------------------

接下来修改C语言代码,这次导入变量:

void io_hlt(void);
void write_mem8(int addr, int data);

void HariMain(void)
{
    int i; /* 变量声明,i是一个32位整数*/
  //0x0000是显示内存的开始地址,见第二章的内存分布图,
    for (i = 0xa0000; i <= 0xaffff; i++) { //一共是65536个点,320*200 = 64000
    // 1111b = 15 (b 表示 binary 即二进制),这应该是4位色,一共只能表示16种颜色 write_mem8(i,
15); /* MOV BYTE [i],15 */ } for (;;) { io_hlt(); } }
for (;;) {}就是无限循环
上面利用for循环,将内存的0xA0000到0xAFFFF,全部设为了15(白色),其实在asmhead.nas中,分辨率设的是320*200,也就是64000,十六进制也就是FA00, 所以将上面代码上的0xaffff改为0xafa00,启动后也一样是全白屏。如果改为0xa7d00( 0x7D00 = 3200 = 64000/2),则启动画面是半个白屏:如下:
-----------------------------------------------------

-------------------------------------------------------

2.2 条纹图案 

上面的代码会显示为全屏白色,修改bootpack.c,显示为垂直条纹图案:

    for (i = 0xa0000; i <= 0xaffff; i++) {
        write_mem8(i, i & 0x0f); /* MOV BYTE [i],15 */
    }

& 表示按位与算 ,可将指定位转为0, A & B ,B中的要转换为0的位要设为0,不变的位设为1。IP地址中子网掩码用的就是这个特性。

| 表示按位或运算, 可将指定位转为1,A | B,B中的要转换为1的位要设为1,不变的为设为0。

异或,XOR, 可将指定位反转, A XOR B,B中的要转换位要设为1,不变的位设为0.

i & 0x0f 就是 i & 00001111与运算,也就是 i 的低4位不变,高4位变0,(再高的位因为没有值,也是按0处理的,我理解)。所以,所有的 i 经过运算后:

0xa0000 & 0x0f,就变成了 0x00000 (即0)

0xa0001 & 0x0f ,就变成了 0x00001 (即1)

0xa0002 & 0x0f ,就变成了 0x00002,(即2)

...

0xa000f & 0x0f,就变成了 0x0000f,(即15)

0xa0010 & 0x0f,就变成了 0x00000,(即0)

也就是说都是只有最后一位不变,(这里说的是十六进制,其实0x0f二进制是00001111,对于二进制其实是低4位不变)。最后的结果就是:

00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 01 02 03 04 ...

每16个数就循环一次,效果就是:

4.3 挑战指针

write_mem8(i, i & 0x0f);

这句可以换成:

*i = i & 0x0f; //这里i是个地址值,*i在C语言中表示这个地址指向的内存空间,*i=x 就是往这个地址中写入x这个值。

但这样写会报错。因为上面这句C语句与下面这句汇编语句 编译成“机器码”后是等价的:

MOV [i], (i & 0x0f)

MOV [x],y 这样写会报错,因为指定内存[x]时不知道要写入目标内存的数据类型是BYTE、WORD、还是DWORD,只有在后一个操作数y也是寄存器时才能省略类型。

因为不知道[i]是BYTE、WORD、还是DWORD,所以就会出错。

char *p;  //变量p是用于内存地址的变量,也就是指针

p里放入与i相同的值,然后执行:

*p =  i & 0x0f;

这样C编译器认为 “p是地址专用变量,用于存放char类型的,所以是BYTE,另外:

char i  是BYTE 1字节

short i 是 WORD  2字节

int i      是 DWORD  4字节

因为我们是一个字节一个字节写入内存,所以使用char,也就是BYTE。

但是

char *p 、short *p、int *p 变量p都是4字节,因为这里p是记录地址的变量,在汇编语言中地址像ECX一样用4字节的寄存器来指定。

------------------------------------------------------------

bootpack.c:

void io_hlt(void);

void HariMain(void)
{
    int i; /* 变量声明,i是一个32位整数 */
    char *p; /* 变量p用于 BYTE型 地址 */

    for (i = 0xa0000; i <= 0xaffff; i++) {
        p = i; /* 代入地址 */
        *p = i & 0x0f;
        /* 这可以替代 write_mem8(i, i & 0x0f);  */
    }

    for (;;) {
        io_hlt();
    }
}

执行make run 后可以正常运行,但是命令行 中有个警告:

指针是表示内存地址的数值,类型转换是改变数值类型的命令。C语言中不用内存地址,而是用”指针“。在C语言中如果将普通整数值赋给内存地址变量(指针),就会警告,所以可以这样写:

p = (char *) i;

这就对i 进行了类型转换,使之成为了表示内存地址的整数,(其实数值没变,但对C编译器来说,类型不同差别很大),这样就不会再警告了。

现在实现了用C语言写内存功能。write_mem8没用可以删了。(naskfunc.nas)。

学习到72页 to continue...

原文地址:https://www.cnblogs.com/johnjackson/p/12327671.html