本文介绍如何在驱动程序的C文件中调用ASM文件中导出的汇编函数
引言
Windows驱动程序使用DDK或者IFSDDK(以下简称DDK)中的Build.exe程序对源文件进行编译和链接,操作时只需启动相应的DDK命令行程序,进入待编译的源文件目录,执行Build命令即可得到.sys文件。
Build命令实际上是调用了一个nmake程序,nmake程序随后调用cl.exe和link.exe,并指定所有的编译和链接选项,与应用程序不同,程序员在使用build命令时无法对编译链接选项进行修改,从而无法在build命令中干预编译或者链接过程。
64位平台不再支持内嵌式的汇编代码,为了使驱动程序中仍然可以使用汇编语言,通常的做法是将汇编代码写成独立的函数放入单独的汇编文件中,并对汇编文件进行编译形成obj文件,而后在链接期对所有目标文件(包括驱动C代码的目标文件)进行链接。但是DDK内置的Build程序并不直接支持对汇编文件的编译和链接(也可能我还没有发现这样的方法)。因此需要通过其他手段将汇编代码目标文件和C代码目标文件进行链接。本文讲述的方法是通过修改SOURCE文件和强制指定外部函数调用约定的方式来达到在Windows驱动程序中调用独立汇编函数的目的。
需要注意的问题
1.32位平台和64位平台中调用约定的不同
32位平台下,驱动程序默认采用__stdcall调用约定,该约定编译生成的函数名均带有后缀@xxx,而汇编代码采用__cdecl调用约定,用汇编器编译生成的函数名并不带后缀,从而导致C代码无法引用汇编文件中的函数(链接器会报错:unresolvedexternalasm_rng_available@xxx)。解决这一问题的方法是强制指定调用外部的汇编函数为__cdecl调用约定,即如果在C文件中调用汇编文件中的asm_rng_available函数,声明方式应如下:
externint __cdecl asm_rng_available() ;
强制指定__cdecl调用约定后可以保证C编译器生成的asm_rng_available函数名和汇编文件中生成的函数名是一样的。
64位体系结构中只有一个本机调用约定和一个__cdecl约定可以被编译器忽略,其他的调用约定都已经被清除,所以64位下的DDK编译器生成的函数名和汇编器生成的函数名是一致的,函数名不会带有后缀,因此不必修改。即如果在C文件中调用汇编文件中的asm_rng_available函数,声明方式如下:
externint asm_rng_available() ;
2.SOURCE文件的修改
由于Build命令不会自动关联汇编文件的目标文件,为了将编译后的汇编目标文件和C目标文件进行链接,可以在SOURCE文件的TARGETLIBS宏中进行指定。具体方法如下:
TARGETLIBS=.\instr_32.obj
这样就可以使用Build命令直接对所有目标文件进行链接了。
3.64位和32位中一些系统调用的差异
64位DDK中的lib库并没有导出KeInitializeSpinLock,KeQueryInterruptTime函数,因此不能直接调用,必须通过MmGetSystemRoutineAddress得到函数的指针,利用函数指针进行调用。
驱动中调用汇编函数
下面对整个过程进行完整的描述:
1.将汇编文件和驱动程序的C文件放在同一个目录下(简称驱动目录);
2.修改SOURCE文件,在SOURCE文件中添加TARGETLIBS = *.obj,其中*表示汇编文件的文件名(不加扩展名);
3.在驱动程序C文件中声明外部汇编文件的函数名,如果是32位体系结构,声明时需强制指定汇编函数为__cdecl调用约定;
4.编译汇编文件,在驱动目录下生成obj目标文件(编译器可以采用nasm或者masm);
5.在DDK编译环境下对整个驱动工程执行Build命令,从而生成.sys文件。
OK...