01-3【实现boot跳转到Loader】进入C语言环境并跳到Loader
原理说明

- 
JMP指令:JMP是汇编语言中的无条件跳转指令。无条件跳转指令可转到内存中任何程序段。转移地址可在指令中给出,也可以在寄存器中给出,或在储存器中指出。 
- 
call指令:在汇编语言中,CALL指令的作用是将下一条指令的地址(即程序计数器PC的内容)入栈,并将子程序的起始地址送入PC,从而实现程序跳转到子程序执行。当子程序执行完毕后,程序通过返回指令(如RET)从子程序返回,继续执行主程序中的下一条指令。 
- .s文件 :是一种特殊的源代码文件,主要用于编译和链接软件程序。这种文件通常包含处理器特定的指令集,这些指令集针对特定的微处理器或微架构进行优化。在程序编译过程中,.s文件与.c或.cpp源文件一起使用,最终生成一个可执行文件。在Linux系统中,.s文件也被称为汇编源文件,它们是用汇编语言编写的文本文件,包含了用于生成可执行文件的指令集。此外,在Linux中,还有一种.s类型的文件指的是“套接字文件(socket)”,这是一种特殊的文件,用于进程之间的通信,但与汇编源文件是两种不同的概念
从编译环境进入C语言环境
从start.s到boot.c(此时仍然在boot任务中,而boot函数中即将要编写的功能是:从磁盘找到loader文件然后加载到内存中,并跳转过去)
因为跳转到boot函数中,执行完boot函数后不需要返回,直接加载loader函数,再执行loader函数即可,因此无需返回。因此就不用使用call指令,使用jmp即可。

- 
在博客02中完成了boot工程中利用bios对loader所在磁盘的读取,并加载到内存0x8000中(即:read_loader部分的代码) 
- 
而上面步骤完成了从编译环境进入C语言环境(仍然在boot任务中) 
- 
接下来还未完成的任务是:从boot工程跳转到loader工程(即:boot_entry的编写) 
新建loader工程
首先,新建loader文件夹,再创建几个文件,并写上一些初始代码:

新增加一个工程,需要在cmake的配置文件里说明:

在loader子工程下面也需要一个自己的cmake配置文件,把boot里面的复制一下,再修改即可:

loader在编译后会自动生成一个.bin文件,该文件是放在image目录下的,并且需要将该bin文件写入磁盘映像的第1扇区(从第0扇区开始计算),因此需要通过脚本来处理,如下所示:

编写boot函数的内容(boot_entry:从boot工程跳转到loader工程)
(1) 一些说明
函数指针:
- 
是指向函数的指针变量。 
- 
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。 
- 
函数指针可以像一般函数一样,用于调用函数、传递参数。 
- 
函数指针变量的声明: typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
- 功能:C语言中将绝对地址转换为函数指针来跳转到内存指定位置处执行
参考连接:https://blog.csdn.net/weixin_42590539/article/details/117008138
#define LOADER_START_ADDR 0X8000  //定义一个loader起始地址的宏定义
void boot_entry(void) {
//编写一个函数指针,无返回值无参数
//将这个地址LOADER_START_ADDR强制转换一下,变成一个函数指针类型
((void (*)(void))LOADER_START_ADDR)();
//意思就是在0x8000这个地址处存放了一个无参无返回值的函数,并且调用这个函数。函数名即为函数地址,函数指针存放的就是函数地址。} 
(2) 编写boot_entry函数

修改调试的配置文件
- 
launch.json 文件是 Visual Studio Code (VS Code) 中用于配置调试会话的文件。它定义了调试器如何启动和运行程序。 
- 
告诉JDB在0x8000这个地址处有loader的代码,如下所示 

编译调试运行
断点下一步定位到这里:

最后一步跳转到loader_entry里的死循环:

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号