-
[RESOLVED] DLL exported functions
As far as I understand, a DLL's exported function table can contain either function names or ordinal numbers (perhaps both). When an exe gets launched, how does Windows match it up to the functions in the DLL? Does it start by searching for a matching function name, then, if it doesn't find one, match the ordinal numbers somehow?
The reason I'm asking is that our (VC built) app links to a DLL built using MinGW. Every time the MinGW developer brings out a new version, our app stops working (with Windows putting up a message box about missing ordinals in his updated DLL). The MinGW developer isn't building with reference to a .DEF file so I'm guessing that might be part of the problem.
Having said that, all his exported functions are standard 'C' functions - so unless MinGW is decorating them, I'd expect them to be found if Windows starts off by trying to match the function names. Hope this makes sense! :)
[Edit...] Or is this something I need to specify at link time? Do I need to link our exe so that it'll load functions in his DLL by name, rather than by number?
-
Re: DLL exported functions
AFAIK, if your application is linked to third-party dll through .lib file, you need to rebuild this application with new .lib. Otherwise, I think, it is undefined behavior.
If you need to have runtime compatibility with different third-party dll versions, use LoadLibrary/GetProcAddress technique.
-
Re: DLL exported functions
Thanks Alex. Something new has just come to light....
I've noticed that in the 3rd-party DLL, plain 'C' functions seem to be getting exported with a leading underscore. So for example, the function jack_client_open is getting exported as _jack_client_open (note the prepended underscore). I wonder if this is causing the ordinal values to get chosen at run time, instead of the function names?
In the back of my mind I remember once reading something about the significance of these leading underscores and how to turn them off. I'm blowed if I can remember the details though.... :(
-
Re: DLL exported functions
All these details are handled by linker, when it works with a .lib file. I don't know much about this process, hopefully somebody else can say more.
I only know, this linking with a .lib file doesn't give forward compatibility with future dll versions. In such situation, immediate crash is the better thing that can happen.
-
Re: DLL exported functions
Doesn't a .DEF file help with this though? I thought it allowed the exe to have fixed ordinal offsets for each of the exported functions. So as long as the ordinal values remain the same (and the function signature doesn't change) the original EXE should carry on working with the updated DLL. Or have I msunderstood it?
-
Re: DLL exported functions
On the DLL end:
1. Functions are exported by name. If no number is assigned to it, then one is arbitrarity assigned.
2. Functions can be exported by _dllexport, but if they are C functions, they will automatically have an underscore prepended (all C compilers do that). Also, watch out for C++ functions which have the arguments postpended.
3. DEF files, although MS is trying to get rid of them, is still the best way to export functions from a DLL. They are then portable between all compilers and the number may be specified.
4. Don't forget the WINAPI in the declaration! This makes it compatible with all compilers.
5. That being said, C++ classes exported from a DLL are almost impossible to use unless you have the matching class header and the SAME compiler. C++ does not work from the DEF file.
On the EXE end:
1. LIB files, built by IMPLIB, contain indexes to the locations of the functions inside the DLL. Any rebuild of the DLL requires a new LIB. If you have an old LIB, the linker will attempt to fix problems via the ordinal numbers, but changed function names or number representation will kill the build.
2. DLL functions may be dynamically imported with LoadLibrary and MakeProcInstance. This is actually the only way to use many older DLLs that have outdated LIB files from old compilers. It will also let your app run without the DLL present. If you aren't using a standard MS compiler, this is necessary. Some of the big compiler companies create their own type of LIB files (which are NOT compatible with the MS ones) that are built with a custom version of IMPLIB.
3. It used to be common to use an import DEF file (vs the DLL export one) and specify the ordinal numbers. That hasn't been used by anyone in a decade though.
=========
Looking at your issue, it appears that the MinGW compiler generates its own libraries, and since the DLL is rebuilt by the other C compiler, the custom LIB file from MinGW is then invalid. The functions from the DLL are probably dynamically exported (not using a DEF) and thus a recompile generates different ordinal number exports and invalidates the LIB.
You need to either:
1. Find the IMPLIB for your compiler/linker and rebuild the LIB file.
2. Dynamically link the DLL via LoadLibrary.
Good Luck,
-Erik
-
Re: DLL exported functions
Many thanks for the explanation Erik. The only bit I didn't understand was this:-
Quote:
Originally Posted by
egawtry
Any rebuild of the DLL requires a new LIB. If you have an old LIB, the linker will attempt to fix problems via the ordinal numbers, but changed function names or number representation will kill the build.
Surely this would need to happen at run time? As long as the lib and its header files match each other, the exe build will always work just fine. The linker can't know if there's a more recent DLL available.
Which brings me back to the DEF file.... If the MinGW dev was building against a DEF file (and as long as he kept the same ordinal numbers for each build) there shouldn't be any need to rebuild the exe each time a new DLL gets built. For example, the system DLLs on my machine might not be the same as those on your machine. We might not even have the same OS's - but a given exe (say, Microsoft Excel) will run fine on both machines. I don't need to keep updating all my apps every time I do a system update.
-
Re: DLL exported functions
...oh, and this too :-
Quote:
Originally Posted by
egawtry
if they are C functions, they will automatically have an underscore prepended (all C compilers do that)
I'm sure I've read somewhere that there's a way to turn that off (and some circumstances when it's desirable to do so). Can't remember where I read it though.... :(
[Edit...] Or does the underscore depend on the calling convention? I've definitely read something about this.....
[Edit 2...] I just looked it up on Wikipedia. A leading underscore without any other decoration is used by the _cdecl calling convention.
So that at least eliminates one mystery !
-
1 Attachment(s)
Re: DLL exported functions
Quote:
Originally Posted by
John E
As far as I understand, a DLL's exported function table can contain either function names or ordinal numbers (perhaps both). When an exe gets launched, how does Windows match it up to the functions in the DLL? Does it start by searching for a matching function name, then, if it doesn't find one, match the ordinal numbers somehow?
It searches exactly for what has been provided in import library for the function prototype. If name, then it's name. If number, then it's number.
Quote:
The reason I'm asking is that our (VC built) app links to a DLL built using MinGW. Every time the MinGW developer brings out a new version, our app stops working (with Windows putting up a message box about missing ordinals in his updated DLL). The MinGW developer isn't building with reference to a .DEF file so I'm guessing that might be part of the problem.
That's really weird, as the only way to suppress export name emission I'm aware of is DEF file. Though, I might be wrong here, need to refresh my knowledge of linker options.
Quote:
Having said that, all his exported functions are standard 'C' functions - so unless MinGW is decorating them, I'd expect them to be found if Windows starts off by trying to match the function names. Hope this makes sense! :)
As I said, import section contains exactly what .lib file provided. So, it's more about .lib file generation rather than runtime issue.
Quote:
[Edit...] Or is this something I need to specify at link time? Do I need to link our exe so that it'll load functions in his DLL by name, rather than by number?
Again, the only "something" at link time you operate with is .lib file, i.e. import library.
A simple demo attached.
There are three dll built from the same source three different ways
Code:
D:\Temp\24>exports 24dll.dll
ModuleType:
PE executable (DLL)
Subsystem:
Win32 GUI
ModuleName:
24dll.dll
Exported Info: BaseOfOrdinals = 1
NumberOfNames = 2
NumberOfFunctions = 2
RelVirtAddr Ord Hint ExportedFuncName
0x00001000 1 0 foo1
0x00001030 2 1 foo2
D:\Temp\24>exports 24dll_noname.dll /f
ModuleType:
PE executable (DLL)
Subsystem:
Win32 GUI
ModuleName:
24dll_noname.dll
Exported Info: BaseOfOrdinals = 2
NumberOfNames = 1
NumberOfFunctions = 2
RelVirtAddr Ord Hint ExportedFuncName
0x00001000 2 1 (null)
0x00001030 3 0 foo2
D:\Temp\24>exports 24dll_noname.2.dll /f
ModuleType:
PE executable (DLL)
Subsystem:
Win32 GUI
ModuleName:
24dll_noname.dll
Exported Info: BaseOfOrdinals = 3
NumberOfNames = 1
NumberOfFunctions = 2
RelVirtAddr Ord Hint ExportedFuncName
0x00001000 3 1 (null)
0x00001030 4 0 foo2
The first case is using no DEF file at all. There are both functions exported by names.
The second case is ordinals shifted, with foo1 name suppressed.
The third case is similar to second one but with ordinals shifted by two.
There are two EXEs built for corresponding dll versions (with corresponding .lib files). Now, in spite of seeming resemblance, 24dll_noname.2.dll been renamed cannot substitute 24dll_noname.dll because it has wrong ordinal for foo1.
Code:
---------------------------
24cln_noname.exe - Ordinal Not Found
---------------------------
The ordinal 2 could not be located in the dynamic link library 24dll_noname.dll.
---------------------------
OK
---------------------------
-
Re: DLL exported functions
Quote:
Originally Posted by egawtry
4. Don't forget the WINAPI in the declaration! This makes it compatible with all compilers.
...and introduces a very special name mangling in case of VC++, if no DEF in use.
Code:
#include <windows.h>
extern "C" __declspec(dllexport)
void WINAPI foo1()
{
}
extern "C" __declspec(dllexport)
void foo2()
{
}
Code:
D:\Temp\25>exports 25dll.dll
ModuleType:
PE executable (DLL)
Subsystem:
Win32 GUI
ModuleName:
25dll.dll
Exported Info: BaseOfOrdinals = 1
NumberOfNames = 2
NumberOfFunctions = 2
RelVirtAddr Ord Hint ExportedFuncName
0x00001000 1 0 _foo1@0
0x00001010 2 1 foo2
-
Re: DLL exported functions
Thanks for that very comprehensive reply Igor. I'm just about to try your examples but just out of curiosity... I know that I can use the linker's /DEF to specify a module definition file to be used while building a DLL but what about the other way aorund? Can VC++ actually generate a .DEF file at build time? I've never needed to do it but am just curious.
-
Re: DLL exported functions
Quote:
Originally Posted by
John E
Many thanks for the explanation Erik. The only bit I didn't understand was this:-
Surely this would need to happen at run time? As long as the lib and its header files match each other, the exe build will always work just fine. The linker can't know if there's a more recent DLL available.
True, it would link, but then immeadiately do the function missing popup when run. Sorry for the confusion, I was thinking of a special case.
-Erik
-
Re: DLL exported functions
Quote:
Originally Posted by
John E
Can VC++ actually generate a .DEF file at build time? I've never needed to do it but am just curious.
There are 3rd party programs to do this, but most people just dynamically export functions with _dllexport if they are too lazy to use a DEF file.
Quote:
Originally Posted by
Igor Vartanov
...and introduces a very special name mangling in case of VC++, if no DEF in use.
That is why I ALWAYS use a DEF file.
:)
-Erik
-
Re: DLL exported functions
Thanks guys, this has been really helpful. One more question if I may...
If I see this in a DEF file:-
will the LIB / DLL tables contain BOTH the function name and the ordinal or just the ordinal? I'm assuming both - because I noticed in Igor's example that he specified this:-
which obviously prevents the name from getting exported. But what about the first case?
-
Re: DLL exported functions
Quote:
Originally Posted by
John E
Thanks guys, this has been really helpful. One more question if I may...
If I see this in a DEF file:-
will the LIB / DLL tables contain BOTH the function name and the ordinal or just the ordinal? I'm assuming both - because I noticed in Igor's example that he specified this:-
which obviously prevents the name from getting exported. But what about the first case?
There are quite a few parameters that can be added to a DEF export, most of them unnecessary.
The NONAME is for the paranoid, I assume that Igor did it out of habit.:)
The most commonly used extension is to put PRIVATE in place of the ordinal number for predefined Windows exports like DllGetVersion().
Code:
EXPORTS
; Explicit exports can go here
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
;DllRegisterServerCheck PRIVATE
DllGetVersion PRIVATE
-Erik
-
Re: DLL exported functions
Quote:
Originally Posted by John E
what about the other way aorund? Can VC++ actually generate a .DEF file at build time?
It never is other way round with VC. DEF file always is an input information, and VC never generates it. It's always programmer who does. Though I can recall, Borland indeed had the tool, but not VC.
Quote:
Originally Posted by John E
If I see this in a DEF file:-
will the LIB / DLL tables contain BOTH the function name and the ordinal or just the ordinal? I'm assuming both
It will be both, yes.
Quote:
Originally Posted by egawtry
The NONAME is for the paranoid, I assume that Igor did it out of habit.
Sorry, the NONAME is for those who know exactly what they do. ;) I used it precisely for demonstrating how conflict of ordinals may occur. Other people may use it for getting rid of export names table, because they have their own reasons for that, and being paranoid might be the last one. You know, sometimes people intentionally design all the aspects of the dlls they release. :D
Quote:
Originally Posted by egawtry
The most commonly used extension is to put PRIVATE in place of the ordinal number for predefined Windows exports like DllGetVersion().
Well, talking about PRIVATE, again it is for those who know exactly what they do. It's used strictly to prevent existing export entries from appearing in import library. And frankly, I cannot see how PRIVATE could relate to the subject we discuss here, as it affects neither export name nor ordinal.
Quote:
Originally Posted by John E
As long as the lib and its header files match each other, the exe build will always work just fine. The linker can't know if there's a more recent DLL available.
And if the prototype stays unchanged, and .lib file contains export by name, and export really exists in the .dll, it doesn't matter how old the .lib is, as .exe is going to work just fine.
-
Re: DLL exported functions
Quote:
Originally Posted by
Igor Vartanov
Sorry, the NONAME is for those who know exactly what they do. ;) I used it precisely for demonstrating how conflict of ordinals may occur. Other people may use it for getting rid of export names table, because they have their own
reasons for that, and being paranoid might be the last one. You know, sometimes people intentionally
design all the aspects of the dlls they release. :D
The only reason I have ever seen, in spite of the "size" issue, is for people who are paranoid about security. It removes all possibility of easily hacking the DLL without having to disassemble it. These are the same people who strip then bootstrap their EXE files with encryption.:rolleyes:
For someone learning, and for most of the rest of us, a simple export without any extra gunk is just fine.:D I have had no cause to use any extension besides PRIVATE in twenty years of Windows programming.
-Erik
-
Re: DLL exported functions
Quote:
The only reason I have ever seen, in spite of the "size" issue, is for people who are paranoid about security. It removes all possibility of easily hacking the DLL without having to disassemble it.
Well, to deduce the function name behind the ordinal it's enough to inspect the .lib file. So it's somewhat weak approach to secure your dll by stripping export names. Of course, if the intention really was that. :)
Code:
D:\Temp\24>dumpbin /exports 24dll_noname.2.lib
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file 24dll_noname.2.lib
File Type: LIBRARY
Exports
ordinal name
3 _foo1
_foo2
Summary
D2 .debug$S
14 .idata$2
14 .idata$3
4 .idata$4
4 .idata$5
12 .idata$6
D:\Temp\24>dumpbin /exports 24dll_noname.2.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file 24dll_noname.2.dll
File Type: DLL
Section contains the following exports for 24dll_noname.dll
00000000 characteristics
4F04C94C time date stamp Thu Jan 05 01:49:00 2012
0.00 version
3 ordinal base
2 number of functions
1 number of names
ordinal hint RVA name
4 0 00001030 foo2
3 00001000 [NONAME]
Summary
4000 .data
5000 .rdata
2000 .reloc
11000 .text
-
Re: DLL exported functions
Quote:
Originally Posted by
Igor Vartanov
Well, to deduce the function name behind the ordinal it's enough to inspect the .lib file.
But the LIB file isn't distributed to end users.:ehh:
-
Re: DLL exported functions
Quote:
For someone learning, and for most of the rest of us, a simple export without any extra gunk is just fine. I have had no cause to use any extension besides PRIVATE in twenty years of Windows programming.
If you were right, John never would have any problem with ordinals. And we would lose such an opportunity to talk about dll quirks and perks. :D
-
Re: DLL exported functions
-
Re: DLL exported functions
Quote:
Originally Posted by
egawtry
But the LIB file isn't distributed to end users.:ehh:
So you are talking about some common case. While I'm still trying to stay in context of the original issue, when problem happened to developer, not end user.
-
Re: DLL exported functions
Okay, here's what's puzzling me now....
I opened my exe in the Dependency Walker. It links to around 30 "primary" DLLs (some of which link to other DLLs of course). Except for the main system DLLs (kernel32.dll etc) all the primary DLLs were built with reference to a .DEF file but in the EXPORTS section, they typically show only function names, like so:-
Code:
g_array_new
g_array_ref
g_array_unref
etc, etc. Note, no ordinal numbers specified. Does this mean that the function will get imported by name?
The reason I'm asking is that in every case where I've built the DLL myself (using MSVC) Dependency Walker shows that my app is importing the DLL functions by name (even though the DLL was referenced to a DEF file just like the above example). But with the (thankfully small) number of 3rd party MinGW DLLs, every imported function is being imported by ordinal value.
For an MSVC-built app to import using ordinal values, they seem to have to be explicitly specified in the DEF file when building the DLL. This contradicts several things I've read elsewhere today - which suggested that a DEF file effectively suppresses exporting by name and instead, forces exporting by ordinal value. If no ordinal value was stipulated in the DEF file, default ones get substituted according to what I've read. That seems to be slightly wrong. From what I've observed, specifying only a name will place both a name and a (default) number into the DLL but forces the eventual app to import by name. Specifying both a name and number does broadly the same but forces the app to import by the specified number. Finally, specifying NONAME exports only a number. Am I on the right lines with all that?
-
1 Attachment(s)
Re: DLL exported functions
Quote:
Originally Posted by John E
This contradicts several things I've read elsewhere today - which suggested that a DEF file effectively suppresses exporting by name and instead, forces exporting by ordinal value.
DEF file just instructs how export tables need to be formed. If ordinals provided, it really forces the name to be bound to the explicit ordinal. And only NONAME instructs to prevent the name from appearing in export names. Where can you see a contradiction? Please note, here we talk only about dll exports, not about how the import entries get resolved on exe launch.
Quote:
If no ordinal value was stipulated in the DEF file, default ones get substituted according to what I've read. That seems to be slightly wrong. From what I've observed, specifying only a name will place both a name and a (default) number into the DLL but forces the eventual app to import by name. Specifying both a name and number does broadly the same but forces the app to import by the specified number. Finally, specifying NONAME exports only a number. Am I on the right lines with all that?
Everything is correct. Ordinal once specified in DEF appears in LIB, and thus, becomes a sole criterion for entry resolution while loading exe. This never means that app linked with differently formed .lib, which instructs to import entry by name, will fail to load the DLL. Just because the DLL has the name exported as well.
Another little sample. Two EXEs are built with two different .lib files, one instructing to import by name, and another doing by ordinal. With both the EXEs both DLLs can be used interchangeably (I mean, of course 26dll_ord.dll should be renamed to 26dll.dll).
-
Re: DLL exported functions
Thanks again Igor. I had a loose understanding of this, right at the start but now I feel my understanding is much better. Just to clarify one thing for you...
Quote:
Originally Posted by
Igor Vartanov
Where can you see a contradiction?
I don't mean in this thread. I was talking about information I'd read on other sites.
-
Re: DLL exported functions
One little detail in addition.
Quote:
Originally Posted by John E
As far as I understand, a DLL's exported function table can contain either function names or ordinal numbers (perhaps both).
There are actually few tables in export section making 1) an index of function relative addresses, which you can take as 'ordinal to RVA', and 2) an index of function names to ordinals (physically comprised of two vectors of the same size), referencing the previous table. That's why it's possible to have both types of exports in the same DLL.
BTW, saving on name-to-ordinal resolution (linear search through names index!) to improve dll load time might appear to be another reason to use NONAMES. ;)
-
Re: DLL exported functions