Share via


Weird side affect of the day: #defines can be used in your .def file

I found this one out the hard way today. I was experimenting with the KMDF loader driver (wdfldr.sys). I added the following #define to my sources file so that I could share code between wdfldr and another component and control some functionality based on who was including the file

 sources:
    TARGETNAME=wdfldr
    TARGETTYPE=EXPORT_DRIVER

    C_DEFINES=$(C_DEFINES) -DWDFLDR=1

    [...]

I then compiled my test driver (wdfrawbusenumtest.sys), but it failed to load! I was getting a code 39 (which meant Windows could not load my driver). I previously wrote on how to debug a missing export at runtime, and I tried to use that technique. It told me that "KeGetCurrentIrql" was unresolved, but that is not possible since hal.dll has exported this function since NT 3.1. It finally occurred to me look at the imports for my test driver to see if there was anything weird. Here is what I saw:

     link /dump /imports WdfRawBusEnumTest.sys

    [...]
        HAL.dll
                     18014 Import Address Table
                     1C290 Import Name Table
                         0 time date stamp
                         0 Index of first forwarder reference

                       4C KeGetCurrentIrql

        1.SYS
                     18000 Import Address Table
                     1C27C Import Name Table
                         0 time date stamp
                         0 Index of first forwarder reference

                        7 WdfVersionBind
                        9 WdfVersionUnbind

Huh? 1.sys? Where did that come from? I went back and checked the src file (which when compiled becomes the def file) and there were no changes there. This is what the def file looks like:

 wdfldr.src:
    NAME WDFLDR.SYS

    EXPORTS
        WdfVersionBind
        WdfVersionUnbind
        [...]

Since I didn't change the def file, what was making the compiler think that the exports should resolve to 1.sys? I finally realized that my C_DEFINE of -DWDFDLR=1 was the culprit. When wdfldr.src was being built into wdfldr.def, my define changed NAME WDFLDR.SYS into NAME 1.SYS. Little did I know that the C preprocessor was used when compiling the src file. To fix the problem, all I needed to do was change the define to something else, C_DEFINES=$(C_DEFINES) -D_WDFLDR_=1, and then update my shared headers to use the new define.

Comments

  • Anonymous
    November 06, 2006
    In the previous article you linked to, some people were complaining about the distribution of DEPENDS.EXE. I did a search of your blog, and it seems you've not talked about Dependency Walker. So I thought I should point it out to you and your readers. It's free ! http://www.dependencywalker.com/

  • Anonymous
    November 06, 2006
    That looks like a great tool, I am going to check it out when I have a free moment. d

  • Anonymous
    November 09, 2006
    Doron, I think the whole point of the .src file is that it's pre-processed, otherwise you can simply use a run of the mill .def. From the documentation: <<< Additionally, there is a standard inference rule that will run the C preprocessor over the .def or .src file in the current directory to create build-specific .def files in the object subdirectory. The same compiler define directives that you key off of in your source code can be used in the root .def or .src file to create the export list. To enable it, use something like: DLLDEF=$Omydll.def Here is an example of what mydll.src might look like: ; mydll.src LIBRARY mydll EXPORTS #if defined(X86) X86Routine #elseif defined(IA64) IA64Routine #else #error Unknown platform #endif // Grab some other exports from another file #include "master.src" >>> Best regards, Alex Ionescu

  • Anonymous
    November 09, 2006
    yes, it is obvious after the fact and once I remembered the contents of other *.src files, but at the time, it was a bit perplexing and the way that the preprocessor changed things made it completely non obvious what was going on ;). d