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里的死循环:




posted @ 2024-07-23 14:20  卡卡发  阅读(132)  评论(0)    收藏  举报