一、回顾及存在问题
前面我们讲了, bootloader的作用有三个:一是收集系统状态信息;二是将设置系统状态,以满足操作系统运行要求;三是加载和执行操作系统(kernel)。
我们已经完成了:
1. 驻留内存的引导程序;
2. 驻留在第1个引导扇区的bootloader编写,将内核程序加载到内存执行;
3. 完成了由汇编转向C语言入口程序cstart_()地方(asm如何调用C,如何编译链接16位实模式下的C语言),现正式进入C语言世界!
本节首先我们需要用C语言从头实现一个调试工具——printf。
二、:基本的函数调用过程分析
1. CDECL 调用规则:https://en.wikipedia.org/wiki/X86_calling_conventions .
(1)基本规则
-参数:自右向左压入堆栈
-调用者(汇编语言)负责将参数从堆栈中取走
- 返回值:整数,指针是放在EAX中,浮点是STO
- 使用的寄存器:EAX,ECX,EDX由调用者保存原始值,函数调用结束,返回前恢复
自动在c语言函数名称前加一个“_”,转变为汇编函数名称。
(2)CDECL汇编示例
asm调用c函数的实际代码执行情况(堆栈变化)
1)首先保存原来上下文,将参数、返回地址压入堆栈;
2)进入子函数(被调用函数),保存旧的堆栈结构地址,并将bp指向新的堆栈底 (mov bp, sp),到这里我们已经准备好执行被调用函数内部了。
3) 在被调用函数内部,因为bp不变,所以输入的参数使用[bp-n]代替,首先空出一块区域存放子函数的返回值 (sub sp,2; 用于存放lengthSq函数中的r临时变量)
4) 子函数内部执行
执行完将sp中的值修正为 r (mov [sp-2], ax)