本文最后更新于:2024-12-01T08:55:14+08:00
OS专题-了解函数和字符串
为了更高效的开发,我们肯定需要将一些公共代码封装起来,这样就可以减少很多代码量。为此我们需要了解函数这个概念。
字符串
首先先来说一下字符串吧!他也是非常常用的一个东西。我们知道在C语言中,字符串就是字符数组组成的,并且最后一位总是\0
。汇编中也是一样的,一般情况下我们定义字符串是这样定义的:
上面的代码被单引号包围的文本会被汇编器转换成ASCII码,最后那个0
会被直接当成0x00
处理。
控制流程
我们还要学习一些控制流程,不然我们写不出向C那样的条件分支语句和循环语句。
之前我们已经学习过一个控制语句了,就是jmp $
!它的作用是跳转到当前语句位置继续执行,说白了就是死循环。跳转语句非常有用,就是它实现了我们C中的分支语句。汇编中的跳转条件是基于 上一条 指令的计算结果来执行的。例如:
这些东西都非常重要,了解了这些才能完成较为复杂的逻辑语句。里面的汇编指令需要各位自行百度或Google,有时间我会整理一份指令说明的~
函数
现在我们来聊聊函数,和你预想的一样,他跟我们调用字符串没什么区别,调用函数就是跳转到函数对应的位置并执行。这里有一个值得注意的点,就是如何传递参数?我们可以用两种传递方式:
- 事先规定使用某一个寄存器或地址来共享数据
- 需要更多的代码逻辑,抽象一个共享区域
第一种很简单,我们规定使用AX寄存器来存储参数:
上述代码虽然实现了参数传递,但是这个代码却不能复用。因为print函数中存在跳转回去的代码,所以只能在这里使用。那该怎么修改呢?我们需要改进两处位置:
- 通过一个寄存器或空间保存需要返回执行的代码地址
- 保存寄存器的当前状态,让子函数可以修改寄存器,而不影响其他的函数调用
这些功能CPU都已经实现,我们可以使用call
指令和ret
指令来代替jmp
指令完成对函数的调用。用pusha
和popa
指令来保存和恢复寄存器信息。
这里提一个小知识点,我们可以像C语言那样将不同的模块分成不同的文件。
在需要的地方用%include "file.asm"
去引入这个文件
实现打印函数
现在我们来封装一下打印函数,新建两个文件lib/print.asm
和lib/print_hex.asm
。代码如下:
修改mbr.asm
中的代码,调用上述函数:
若你真的这么做了…那么代码编译时会出现如下错误:
这是因为我们没有告诉编译器,这些函数文件的位置,我们需要修改一下CMakeLists.txt
文件。在add_executable(loader boot/mbr.asm)
前面增加include_directories(lib)
即可。