4

I have a DLL written with x86 assembly language. All the exports refer to stdcall functions. All exports are undecorated.

I specifically need this DLL as-is linked to a C project using an import library. LoadLibrary or changing export names etc is not an option.

I have 2 problems

  1. When I create an import library (.lib) file for the DLL from a DEF file with export names, all of the names get decorated to cdecl! I can't find a way to specify them as undecorated stdcall. None of these decorated names exist in the DLL, so by run-time, nothing will work even if compilation was possible.
  2. When I write code to call a DLL function in MSVC, whether specifying stdcall or not, the compiler modifies the names of the functions. So a call to ExampleFunction becomes _ExampleFunction@12, and I need it to be ExampleFunction only.

Fortunately, what I need MUST be possible because Windows system DLLs (e.g. kernel32.dll, user32.dll etc) follow the exact same conventions. Every exported function is stdcall and is undecorated.

I've already read this: https://qualapps.blogspot.com/2007/08/how-to-create-32-bit-import-libraries.html

I encountered these issues:

  1. using extern "C" doesn't apply here as this is a C project. That specifier won't even work and despite this being a C project, names get modified anyway.
  2. Creating a .lib file from a DEF file with just raw function names doesn't work. The names get modified.

The example-lib.def file looks like this:

LIBRARY example-lib.dll
EXPORTS
ExampleFunction

The .lib file is generated with this command:

lib.exe /def:example-lib.def /OUT:example-lib.lib

The entry in the lib file looks like this when using dumpbin.exe /headers example-lib.lib

Version      : 0
Machine      : 14C (x86)
TimeDateStamp: 5CDBA30C Wed May 15 06:26:36 2019
SizeOfData   : 00000016
DLL name     : example-lib.dll
Symbol name  : _ExampleFunction
Type         : code
Name type    : no prefix
Hint         : 20
Name         : ExampleFunction

I'm importing by making declarations this:

extern void __stdcall ExampleFunction(int a, int b, int c);

I call the function like this:

ExampleFunction(1, 2, 3);

The lib file and directory in which it resides is specified in VC project settings.

When the code calling ExampleFunction compiles, the linker won't complete because it can't find _ExampleFunction@12 in my DEF file. And even if that was present in the DEF file, the program won't run because _ExampleFunction@12 isn't exported in the actual DLL's export section. Only plain ExampleFunction is exported.

So how do I achieve having the C program call ExampleFunction from the DLL exactly as is? How is this done when a C project calls a function from user32.dll? Can I use the same procedure for achieving this?

user7348172
  • 153
  • 6
  • Did you see https://stackoverflow.com/questions/9946322/how-to-generate-an-import-library-lib-file-from-a-dll ? – manuell May 15 '19 at 07:17
  • Using a def files work here. Please show a full, but minimal example. – David Heffernan May 15 '19 at 07:21
  • @DavidHeffernan the DEF file for the DLL looks like this. Is there a way to tell `lib.exe` that ExampleFunction is undecorated stdcall? `LIBRARY example-dll EXPORTS ExampleFunction` – user7348172 May 15 '19 at 07:32
  • @manuell yes that was the first thing I saw when I started making the lib file. – user7348172 May 15 '19 at 07:34
  • Can we have a [mcve], in the question, by way of an edit. If you don't know how to do that, please visit the [help] and take the [tour]. – David Heffernan May 15 '19 at 07:35
  • 1
    @DavidHeffernan I've now extended the question to include a reproducible example. – user7348172 May 15 '19 at 08:07
  • Are you sure you feed the lib file to the linker? What happens when you suppress the extern keyword? You say "I'm importing by making declarations"... That's not quite right. You just have to prototype the function (to make the compiler happy) and then give the lib to the linker. – manuell May 15 '19 at 09:17
  • The process you use is exactly how I generate lib files and the resulting lib file has names that are not decorated in any way. I am sure that there is some extra step that you are taking that is not shown in the question. – David Heffernan May 15 '19 at 09:23
  • @DavidHeffernan I just repeated the process step by step as I wrote it. No extra steps. Same output as listed in question where symbol name is prefixed with '_'. If you note in the linked article, the author managed to get `Name type: undecorate`. However I can't seem to get his dummy/stub method working either. `undecorate` is still a thing as e.g. `user32.lib` has all `stdcall` functions and uses it. But how? – user7348172 May 15 '19 at 09:55
  • @manuell Removing `extern` produces the same result. Compiler generates reference to _ExampleFunction@12 but linker can't find that because it doesn't exist (and isn't supposed to). – user7348172 May 15 '19 at 09:56
  • When I do this, I don't observe the behaviour that you report. Of course, you still have not produced a [mcve] which means we can't know for sure what you are actually doing. – David Heffernan May 15 '19 at 10:08

1 Answers1

4

Turns out the information in the article link I posted above does actually work. (https://qualapps.blogspot.com/2007/08/how-to-create-32-bit-import-libraries.html)

I had already created a dummy/stub library as the article mentioned... But I did not add a module definition file to the dummy library in the way I should have. I neglected to do this but also, I don't even see why it would work! I created it outside of Visual Studio and generated the .lib for it outside of Visual Studio. No luck. Doing it all in Visual Studio made it work.

Simply adding a module definition that looks like this...

LIBRARY example-lib.dll
EXPORTS
ExampleFunction

... causes the outputted .lib file to report this instead of what I originally listed in my question:

Version      : 0
Machine      : 14C (x86)
TimeDateStamp: FFFFFFFF
SizeOfData   : 00000019
DLL name     : example-lib.dll
Symbol name  : _ExampleFunction@12
Type         : code
Name type    : undecorate
Hint         : 0
Name         : ExampleFunction

This is very strange! As the article mentions, this is essentially undocumented behaviour but it does solve my problem.

If you're having trouble following the article as I was, the solution to having a .lib file with undecorated stdcall imports is this:

  1. Create a new Visual C DLL project (not static library), name it the same as the DLL you want to create a .lib for.

  2. In the main source code file, which is a C++ file (doesn't matter that this is the case), copy the signatures for required functions as below. For example-lib, this is the entire source file!

    include "stdafx.h"
    extern "C" __declspec(dllexport) void _stdcall ExampleFunction(int a, int b, int c) { }
    
  3. This is the key part. In Visual C's Solution Explorer, right-click Source Files > Add > New Item... In the dialog that appears, select Code > Module Definition File (.def). Make it match your DLL name and export names as below. As this step doesn't require making any settings changes to reference the module definition, I really don't know why this works. But it does... It doesn't seem to be officially documented that this will work but the functionality has been present in MSVC since at least 2005-2007 (when the article was written).

    LIBRARY example-lib.dll
    EXPORTS
    ExampleFunction
    
  4. Set to Release mode and build the library. Navigate to the project directory in Windows Explorer and you should now see the .dll file and the .lib file. You can run dumpbin /headers example-lib.lib to verify that ExampleFunction is undecorated as shown above.

  5. To use the dummy .lib file to reference a real DLL, add it to your original project by going to Project properties > Linker > Input > Additional Dependencies (and add the dependency directory if necessary). Then declare a reference to it in code like this:

    extern void __stdcall ExampleFunction(int a, int b, int c);
    

Build your project and it should work. If you view your project EXE/DLL in a utility, you'll see that the .idata section will be referencing your DLL with undecorated function names. This works because the compiler will always generate a symbol reference like _ExampleFunction@12 but when this reaches Microsoft's linker in combination with the specialised .lib file, it sees that the name type for this is undecorate and it should resolve this symbol to the actual name ExampleFunction.

user7348172
  • 153
  • 6