《30天自制操作系统》 day4 小结

1. 用C语言往内存写入

Naskfunc.nas中增加了一个函数可供C语言调用的函数_write_mem8,用于实现直接写入指定内存地址的语句。
_write_mem8
如果C语言中write_mem8(0x1234,0x56);语句,
则动作上相当于汇编的MOV BYTE[0x1234],0x56

第一个数字在内存里的存放地址[ESP+4] 下一个数字的存放就依次累加4

值得注意的是,如果和C语言联合使用的话,有底寄存器能自由使用,有的寄存器不能自由使用。能自由使用的只有EAX、ECX、EDX这三个。至于其他寄存器,只能使用其值而不能改变其值。因为这些寄存器在C语言编译后生成的机器语言中,用于记忆非常重要的值。

这段代码中还增加了INSTRSET指令,是用来告诉nask这个程序是给486使用的,不然会被默认解释成8086机器使用(偶尔使用)的标签(label)或者常数。最后代码如下:

; 用彙編語言寫了一個名叫io_hlt的函數,因為之後要與bootpack.obj鏈接,所以也需要編譯成目標文件。因此將輸出格式設定為WCOFF模式,且設定成32位機器語言模式。

; naskfunc
; TAB=4

[FORMAT "WCOFF"]                ; 製作目標文件的模式
[INSTRSET "i486p"]       ; 告诉nask这个程序是给486使用的
[BITS 32]                       ; 製作32位模式用的機械語言

; 製作目標文件的信息
[FILE "naskfunc.nas"]           ; 源文件名信息
        GLOBAL      _io_hlt,_write_mem8     ; 程序中包含的函數名

; 以下是實際的函數
[SECTION .text]                 ; 目標文件中寫了這些之後再寫程序

; C语言对汇编函数HLT的调用
_io_hlt:    ; void io_hlt(void);
        HLT
        RET

; 写入指定内存地址的语句  C语言实现的汇编接口
; 这个函数类似于C语言中"write_mem8(0x1234,0x56);"语句,动作上相当于"MOV BYTE[0x1234],0x56"
_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

话说[INSTRSET "i486p"]这一句的添加位置作者没有详细说明,同时要记得在bootpack.c中的GLOBAL声明中加上新写的函数_write_mem8如下:

GLOBAL      _io_hlt,_write_mem8     ; 程序中包含的函數名

CPU家谱:
8086→80186→286(16)→386(32)→486→Pentium→PentiumPro→PentiumⅡ→PentiumⅢPentium4→……

然后修改bootpack.c里的代码:

/*在下面使用函数前需要先声明函数,相当于告訴C編譯器,有一個函數在別的文件里*/
void io_hlt(void);
void write_mem8(int addr, int data);

/*是函數聲明卻不用{ },而用;,這表示的意思是:函數在別的文件中,你自己找一下吧!*/

void HariMain(void)
{
    int i;              /*变量声明:i是一个32位整数*/

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

    for(;;) {
        io_hlt();    /*執行naskfunc里的_io_hlt*/
    }
}

2. 条纹图案

只需要在bootpack.c中修改写入值”15”为”i&0x0f”:

write_mem8(i, i & 0x0f);

对图形来说,0和1并不是作为数字来使用,重点是0和1 的排列方式。对于0和1的互相变化,有位运算”或”(OR)运算、”与”(AND)运算和”异或”(XOR)运算。
简单来说:

1 2 3
OR 有1得1 如 0100 OR 0010 → 0110
AND(&) 同1为1 如 0100 AND 1101 → 0100
XOR 不同得1 如 1010 XOR 0010 → 1000

将写入内存的数值经过&之后每隔16个像素,色号就反复一次,屏幕就能显示条纹了。

4-22

这个效果有点丧病啊,表示眼睛已经花了= =、

3. 挑战指针

前面提到的“C语言中没有直接写入指定内存地址的语句”是因为C语言中有替代这种命令的语句,也就是使用指针。
指针符号是”*”,*p中的p是地址,而*p是p指向地址的内容。
使用*i = i * 0x0f可直接将i*0x0f写入i指向的内存地址中。
*i = i * 0x0f对应汇编的MOV [i], ( i * 0x0f),但如果直接这样写就不清楚[i]到底是BYTE还是WORD还是DWORD。
由于MOV指令的两个对象必须是相同字节长度,即同类型(BYTE/WORD/DWORD),除非另一方是寄存器才可以省略。同理,在使用指针时需要事先声明它的类型,即指针所指向内容的类型。
char i是类似AL的1字节变量,short i是类似于AX的2字节变量,int i是类似于EAX的4字节变量。

char p ; / 用于BYTE类地址 * /
short p; / 用于 WORD 类 地 址* /
int p ; / 用于DWORD 类 地 址 * /

以上指针中的p都是4字节,因为p是用于记录地址的变量。在汇编语言中,地址也像ECX一样,用4字节的寄存器来指定,所以也是4字节。

p = i; /带入地址/
p = i & 0x0f; /这可以替代write_mem8(i, i&0x0f)*/

在执行make run之后出现了“warning: assignment makes pointer from integer without a

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值