计算机自制操作系统(十三):汇编语言与C语言的混合编程

如题所述

计算机自制操作系统之旅(十三):C与汇编语言的无缝融合


在掌握了C语言的主导后,汇编与C的协同编程成为关键环节。通过链接器,我们将C的obj文件和汇编的obj文件巧妙地结合,形成统一的执行体,如GCC的ld或VS的link工具。为了保持兼容性,我们需要确保与32位汇编程序的协同工作,为此,我们会创建一个专用的32位汇编模块,专为C调用的函数服务。这个过程的核心在于确保函数名称的一致性和链接的准确性。


关键步骤揭示:



    C与汇编的无缝对接:

      首先,编写汇编函数(naskfunc.nas),如一个简单的"C->A"显示函数,编译后为naskfunc.obj。
      接着,在C主程序(Kernelc.c)中,声明并调用这四个外部函数,生成Kernelc.obj。
      然后,用链接器obj2bim.exe将Kernelc.obj和naskfunc.obj融合,生成可执行的Kernelc.bim。


    目标:最终目标是生成二进制文件Kernel.bin,它是程序的基石。

整个过程涵盖了函数声明、编译、链接和输出的各个环节,确保了函数名称的正确引用和调用。


细节解析:


在C程序中,我们巧妙地使用EXTERN和GLOBAL关键字来标识需要调用的汇编函数。通过配置链接器haribote.rul,我们将入口函数HariMain更改为标准的Main,使之符合规范。


当C调用汇编函数时,call指令的参数在链接后会有所调整,但这并未影响到它们的无缝协作。链接器会将汇编代码插入C程序的尾部,确保精确无误的函数调用。


链接器的运作原理如下:



    寻找程序入口:定位到C程序中的Main函数。
    加载机器代码:C程序从0x80+C开始,长度0x0D,汇编程序则在C程序之后,0x24+0x0D=0x31。
    修正函数调用偏移:在call指令中调整汇编函数的偏移,如调用asmfunc。
    最终偏移计算:asmfunc在汇编程序中的偏移值为0x00000000,结合链接后的实际位置,得出偏移值为0x02。
    链接过程的细节变化会在Kernelc.map文件中清晰呈现。

链接过程中,C程序通过"#{include}"指令引用库函数,链接器将它们紧密结合。虽然这通常是自动处理的,但理解这一过程有助于我们更好地控制程序的构建。


参数传递至关重要:C函数通过堆栈区域,通过ESP+8,12,16传递3个参数,但实际值比预期少4字节,因为C编译器使用了PUSH EBP进行保护,正确顺序应调整为ESP+4,8,12。


汇编调用C的精准性不容忽视,每次调用前后堆栈管理的正确性至关重要,以避免程序崩溃。示例汇编代码展示了这个微妙的调用过程和堆栈清理。


总结来说,C与汇编语言的混合编程虽有挑战,但只要妥善处理,就能实现高效且精确的通信。在Linux环境下,我们甚至可以使用C内嵌汇编来实现某些特定功能,如通过SYS_PRINT函数调用系统功能,无需printf。


掌握C调用汇编的技巧,你将能更好地掌控操作系统的核心,而汇编调用C时,务必注意清理堆栈,以免留下隐患。现在,你已经准备好迎接下一个编程挑战,继续你的操作系统构建之旅吧。

温馨提示:答案为网友推荐,仅供参考
相似回答