are you a DLL expert?

From Visual Basic to GNU C, this is the place to talk programming.

Moderators: SecretSquirrel, just brew it!

are you a DLL expert?

Postposted on Thu May 07, 2009 5:10 pm

Anyone have experience with C++ DLL's acting strange when built from Visual Studio? (2008)

- If DLL is built in Debug mode, the DLL is loadable and works fine.
- If DLL is built in Release mode, the DLL appears to build perfectly just as in Debug mode, but the created DLL won't load with a win32 LoadLibrary call.

I've gone over the project settings making sure that the Debug settings are similar to the Release settings (except for example DEBUG vs NDEBUG symbol definitions). No help.

If I run dumpbin /exports on the DLLs, I see:

Debug DLL (loads fine):
Code: Select all
C:\...>dumpbin /exports arbrslink.dll
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file arbrslink.dll

File Type: DLL

  Section contains the following exports for ArbRSLink.dll

    00000000 characteristics
    4A035B04 time date stamp Thu May 07 17:04:52 2009
        0.00 version
           1 ordinal base
           3 number of functions
           3 number of names

    ordinal hint RVA      name

          1    0 00103209 LinkEnd = @ILT+16900(?LinkEnd@@YGKXZ)
          2    1 0010A018 LinkStart = @ILT+45075(?LinkStart@@YGKK@Z)
          3    2 001036D2 SetCommLink = @ILT+18125(?SetCommLink@@YGKPAXK@Z)

  Summary

       1C000 .data
        1000 .didat
        6000 .idata
       57000 .rdata
       18000 .reloc
        6000 .rsrc
      21A000 .text
       FE000 .textbss


Release DLL (won't load):
Code: Select all
C:\...>dumpbin /exports arbrslink.dll
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file arbrslink.dll

File Type: DLL

  Section contains the following exports for ArbRSLink.dll

    00000000 characteristics
    4A0356AA time date stamp Thu May 07 16:46:18 2009
        0.00 version
           1 ordinal base
           3 number of functions
           3 number of names

    ordinal hint RVA      name

          1    0 000023F0 LinkEnd = ?LinkEnd@@YGKXZ (unsigned long __stdcall Lin
kEnd(void))
          2    1 000062F0 LinkStart = ?LinkStart@@YGKK@Z (unsigned long __stdcal
l LinkStart(unsigned long))
          3    2 00001250 SetCommLink = ?SetCommLink@@YGKPAXK@Z (unsigned long _
_stdcall SetCommLink(void *,unsigned long))

  Summary

       16000 .data
        E000 .rdata
        9000 .reloc
        4000 .rsrc
       4D000 .text


I notice the symbol names in the 2nd dump look different, but I'm not sure what to make of it. LoadLibrary+GetLastError returns a bizzare error code 3221225501 when loading the release DLL.

Suggestions appreciated!
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 5:53 pm

Name mangling?
http://en.wikipedia.org/wiki/Name_mangling There is an example of DLLs to avoid name mangling on the wiki article
_Sigma
Gerbil
Silver subscriber
 
 
Posts: 60
Joined: Sun Mar 16, 2008 12:20 am

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 5:59 pm

Usually it is because of dependencies. Can you do a dumpbin /imports as well on both of them (or run the Depends utility)? The DLL itself may depend on another DLL(s) that is not present in all the folders in the DLL search path. Though it is a bit hard to imagine you have the debug versions of the dependent DLL(s) but not the release versions.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24416
Joined: Mon May 24, 2004 2:19 am

Dependency Walker

Postposted on Thu May 07, 2009 6:57 pm

Flying Fox wrote:Usually it is because of dependencies. ... (or run the Depends utility)?


Dependency Walker has the same thing to say about both DLLs:

Code: Select all
Warning: At least one delay-load dependency module was not found.
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.


Nice tool, but I don't see how this helps me. I figure "delay-load" means the DLLs aren't strictly needed, so my own DLL should at least load even if it later had trouble finding a delay-load DLL. (Right?)
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 7:11 pm

Is there any dependent DLL flagged in red (the dependency tree on the left)?

What does dumpbin /imports say?
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24416
Joined: Mon May 24, 2004 2:19 am

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 7:27 pm

Flying Fox wrote:Is there any dependent DLL flagged in red (the dependency tree on the left)?

What does dumpbin /imports say?


DWMAPI.DLL is missing, which according to http://stackoverflow.com/questions/173433/how-to-fix-dwmapidll-delay-load-dependency-under-winxp is a common but (probably?) harmless issue for Win XP systems with IE7 installed. Also flagged are "not bound" symbols in C:\WINDOWS\SYSTEM32\SHLWAPI.DLL and C:\WINDOWS\SYSTEM32\MPR.DLL.

The dumpbin /imports prints out a ton of stuff. I can't find any errors in the dump. The /imports for the Debug DLL is similar to the Release DLL but not identical.
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

decimal 3221225501 equals hex 0xc000001d

Postposted on Thu May 07, 2009 7:30 pm

Decimal 3221225501 equals hex 0xc000001d and I found somebody with apparently that same error, here: http://www.bailopan.net/blog/?p=33

I think it's possible that this project of mine (which I inherited from somebody else no longer available) is using SSE instructions not supported by my aging Athlon XP workstation?
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

Re: decimal 3221225501 equals hex 0xc000001d

Postposted on Thu May 07, 2009 8:19 pm

sparkman wrote:Decimal 3221225501 equals hex 0xc000001d and I found somebody with apparently that same error, here: http://www.bailopan.net/blog/?p=33

I think it's possible that this project of mine (which I inherited from somebody else no longer available) is using SSE instructions not supported by my aging Athlon XP workstation?



Confirmed: hex 0xc000001d is a poorly-documented LoadLibrary return code called EXCEPTION_ILLEGAL_INSTRUCTION indicating something along the lines of "you tried to load an SSE2 DLL on an SSE1 processor, numnutz!" In my project settings for the release mode the code generation "Enable Enhanced Instruction Set" option was set to SSE2. Changing it to SSE fixed the problem.

Thanks for the help! All the comments were educational for me.
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 8:56 pm

I'm curious. Why was SSE2 used in the release build but not the debug build? Was the compiler automatically optimizing something? Or did the code have a preprocessor #IF DEBUG directive?
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 9:33 pm

wibeasley wrote:I'm curious. Why was SSE2 used in the release build but not the debug build? Was the compiler automatically optimizing something? Or did the code have a preprocessor #IF DEBUG directive?


A different section of this software uses SSE2 assembly code to accelerate some mundane tasks. So SSE2 is a requirement for this software and I'm moving to a more-modern workstation to continue development. In the C++ DLL that wouldn't load, there doesn't appear to be any explicit SSE2 code, but the Release settings enabled SSE2 code generation, I suppose just in case the compiler could find some benefit in SSE2, since SSE2 support was already required for the software.
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 9:49 pm

So the release build had the "Streaming SIMD Extensions 2 (/arch:SSE2)" compiler option, but the debug build didn't?

It would be nice if Visual Studio had a built-in tool that displayed (on one screen) all the differences in compiler options between build configurations. When I'm troubleshooting my mistakes, I hate flipping through that 'Configuration' combo box for all 80,000 Project property pages. Off the top of their head, does anyone know of a tool that does this?
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 9:52 pm

wibeasley wrote:I'm curious. Why was SSE2 used in the release build but not the debug build? Was the compiler automatically optimizing something? Or did the code have a preprocessor #IF DEBUG directive?

Compiler optimization is disabled by default in debug builds, so there is no SSE2 instructions generated in the machine code. I'm curious, do you know which function(s) is using the SSE2 stuff? Performance could suffer. In that case you may be better off doing a CPU specific check (google the code it should be everwhere) and run 2 pieces of code depending on whether SSE2 is supported. You can explicitly force it to compile to SSE but using /arch:SSE or whatever project options. Interesting though that VS2008 seems to have gotten rid of the switch to generate "P6 blend" code. Looks like you have to go all the way back to VS.NET 2003 to disable SSE altogether.

sparkman wrote:A different section of this software uses SSE2 assembly code to accelerate some mundane tasks. So SSE2 is a requirement for this software and I'm moving to a more-modern workstation to continue development. In the C++ DLL that wouldn't load, there doesn't appear to be any explicit SSE2 code, but the Release settings enabled SSE2 code generation, I suppose just in case the compiler could find some benefit in SSE2, since SSE2 support was already required for the software.
Your application probably needs to check that requirement to be sure, plus the relevant documentation. Alternatively, provide a downlevel implementation if you need to support those older processors.

wibeasley wrote:It would be nice if Visual Studio had a built-in tool that displayed (on one screen) all the differences in compiler options between build configurations. When I'm troubleshooting my mistakes, I hate flipping through that 'Configuration' combo box for all 80,000 Project property pages. Off the top of their head, does anyone know of a tool that does this?
If I really want to study that list I usually go the other way by looking up the alphabetical listing of the compiler options and then work backwards. ;)
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24416
Joined: Mon May 24, 2004 2:19 am

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 10:22 pm

Flying Fox wrote:Compiler optimization is disabled by default in debug builds, so there is no SSE2 instructions generated in the machine code.
Yea, that was one of the possibilities I was thinking of. It's also possible that the legacy code explicitly called SSEs with intrinsics or assembly code. Recently I spent a few days learning SSE intrinsics . I was trying to learn from his experiences since I run my simulations on any dinosaur I can find (Just today I added 256MB RAM to a Pentium III -which lacks SSE2).
Flying Fox wrote:If I really want to study that list I usually go the other way by looking up the alphabetical listing of the compiler options and then work backwards. ;)
I'm dizzy thinking about that process. I tried that approach once and informally concluded I was more error-prone that way than the other tedious approach. But it sounds like you're a more experienced C++ programmer than I am. So maybe the compiler options aren't as cryptic to you.
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 10:24 pm

wibeasley wrote:So the release build had the "Streaming SIMD Extensions 2 (/arch:SSE2)" compiler option, but the debug build didn't?

Exactly.

wibeasley wrote:It would be nice if Visual Studio had a built-in tool that displayed (on one screen) all the differences in compiler options between build configurations. When I'm troubleshooting my mistakes, I hate flipping through that 'Configuration' combo box for all 80,000 Project property pages. Off the top of their head, does anyone know of a tool that does this?


I feel your pain. Sometimes I resort to opening the .vcproj file in Wordpad to search for buried options.
Intel i7-4770K, Corsair 16 GB DDR3 1333, MSI GeForce GTX 770, Samsung SSD 840 Pro 512 GB, WD Black HDD 1 TB, Asus Z87-A, Corsair HX850, Hyper 212 EVO, Corsair Carbide 200R
sparkman
Gerbil First Class
Gold subscriber
 
 
Posts: 101
Joined: Mon May 12, 2003 8:36 am
Location: Houston, TX

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 10:41 pm

If you don't mind Sparkman, I have one more question. Was the SSE issue located in the DLL you were calling, or the in the assembly that called the DLL?

FF, do you think the error message would be the same in both cases?
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 10:53 pm

wibeasley wrote:If you don't mind Sparkman, I have one more question. Was the SSE issue located in the DLL you were calling, or the in the assembly that called the DLL?
I am guessing it is the DLL that he's calling. Since the error was thrown with the LoadLibrary call, so the original process executable/assembly is already loaded.

wibeasley wrote:FF, do you think the error message would be the same in both cases?
If the process fails to start, one should see a different message (an error popup with some other message?). I never really dabble in SSE instructions as I deal with mostly "regular" applications (well, I do multithreading and some Windows specific stuff including the GUI, so it is not hello world regular I suppose) so I would not know the exact error message. I would venture a guess that if you start the process from another with CreateProcess you may get the same cryptic error code too. Don't quote me on that though.

In a real application that error should never be seen, your application should check for it and handle the situation as designed (either provide a downlevel code path, or warn the user before loading the offending code).
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24416
Joined: Mon May 24, 2004 2:19 am

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 11:12 pm

Ahh, the joys of Visual Studio option settings and debug vs. release builds. I've wasted many an hour back in the day chasing down problems due to these. :lol:
(this space intentionally left blank)
just brew it!
Administrator
Gold subscriber
 
 
Posts: 37705
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 11:16 pm

Flying Fox wrote:In a real application that error should never be seen, your application should check for it and handle the situation as designed (either provide a downlevel code path, or warn the user before loading the offending code).
What do you think about distributing two different dlls? One with SSE2 (or maybe higher) and one without? In the calling assembly, the SSE capability would be checked only once (maybe soon after the program loads) and then determine the correct dll version for all future calls.

From an OO/encapsulation perspective, this would a bad approach. It would be better to have the called DLL handle/hide these compatibility issues, right?

But from a performance perspective, I'd hope this approach is beneficial because it avoids repeated calls to the CPUID instruction, which I've read is an expensive operation. (I'm assuming the call to the function is brief enough that the CPUID call isn't effectively amortized).

Of course if numerical performance wasn't a concern, I guess the release configuration shouldn't even have the SSE compiler option.

Am I thinking about these (robustness vs. performance) tradeoffs the right way? Any big issues that would blindside me if I used this approach?

Off topic, but I'm excited about the upcoming AVX instructions.
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 11:17 pm

just brew it! wrote:Ahh, the joys of Visual Studio option settings and debug vs. release builds. I've wasted many an hour back in the day chasing down problems due to these. :lol:
How are you able to avoid it now? Different IDE?
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK

Re: are you a DLL expert?

Postposted on Thu May 07, 2009 11:47 pm

wibeasley wrote:
just brew it! wrote:Ahh, the joys of Visual Studio option settings and debug vs. release builds. I've wasted many an hour back in the day chasing down problems due to these. :lol:

How are you able to avoid it now? Different IDE?

Not doing anywhere near as much Visual C++ stuff as I used to. I used to do quite a bit of it, but most of the code I write at my current job is either C code for embedded systems, or Python scripts. Yeah I realize that is kind of an odd combination, but I have a job where I have to wear a lot of different hats. I'm nominally a software engineer, but I regularly get sucked into other areas -- electrical design, databases / IT support, the occasional mechanical design review, even trips to support the marketing department on demos. So having to jump back and forth between embedded C and Python is the least of it. Gets kind of crazy sometimes, but at least it keeps things interesting! :lol:

We do use Visual C++ to implement simulators for our embedded products; being able to use a standard desktop PC to simulate a $150K piece of avionics gear really helps keep development costs down! But I don't need to deal with that much these days since the simulators are fairly mature now... and we're also migrating some of our stuff to Linux.
(this space intentionally left blank)
just brew it!
Administrator
Gold subscriber
 
 
Posts: 37705
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: are you a DLL expert?

Postposted on Sat May 09, 2009 8:58 am

wibeasley wrote:
Flying Fox wrote:In a real application that error should never be seen, your application should check for it and handle the situation as designed (either provide a downlevel code path, or warn the user before loading the offending code).
What do you think about distributing two different dlls? One with SSE2 (or maybe higher) and one without? In the calling assembly, the SSE capability would be checked only once (maybe soon after the program loads) and then determine the correct dll version for all future calls.

From an OO/encapsulation perspective, this would a bad approach. It would be better to have the called DLL handle/hide these compatibility issues, right?
It depends on where in the call chain you are applying the OO/encapsulation perspective so it is a design issue. One way is that you can hide the SSE vs SSE2 stuff in separate DLLs (like drivers) and use a class hierarchy to hide the choice:
Code: Select all
class FunkyCalculationBase
{
public:
  virtual Answer Run(InputData input) = 0;
};

class FunkyCalculationGeneric : public FunkyCalculationBase
{
public:
  FunkyCalculationGeneric()
  {
      LoadGenericFunctionDLL();
  }

  virtual Answer Run(InputData input)
  {
    // do stuff with generic DLL
  }
};

class FunkyCalculationSSE2 : public FunkyCalculationBase
{
public:
  FunkyCalculationSSE2()
  {
      LoadSSE2FunctionDLL();
  }

  virtual Answer Run(InputData input)
  {
    // do stuff with SSE2 DLL
  }
};
Then there will be one place you make that check and you can keep reusing it. You can also use a factory pattern to further enhance this. You can split that stuff slightly differently too, there are many approaches.

wibeasley wrote:But from a performance perspective, I'd hope this approach is beneficial because it avoids repeated calls to the CPUID instruction, which I've read is an expensive operation. (I'm assuming the call to the function is brief enough that the CPUID call isn't effectively amortized).
You can cache that result of this check and use it throughout. Besides, the check may happen in a performance non-critical part of the code (GUI?) so you don't necessarily have to optimize prematurely.

wibeasley wrote:Of course if numerical performance wasn't a concern, I guess the release configuration shouldn't even have the SSE compiler option.
That will depend on whether they want to support downlevel processors. After all there will be 2 code paths and not all companies want to support multiple code paths as this costs more.

wibeasley wrote:Am I thinking about these (robustness vs. performance) tradeoffs the right way? Any big issues that would blindside me if I used this approach?
That is certainly one factor to consider.

wibeasley wrote:
just brew it! wrote:Ahh, the joys of Visual Studio option settings and debug vs. release builds. I've wasted many an hour back in the day chasing down problems due to these. :lol:
How are you able to avoid it now? Different IDE?
In the old days I was like JBI too, checking and double-checking debug vs release builds. It's a bitch but we have sort of learned to accept it. These days however, we have inherited a code base where the debug config does not even compile! :o We have been working with release builds (with symbols, so you can at least try to debug it. That's another bag of fun.) for the last while plus with our use of TDD, the need for going to the debugger all the time has diminished significantly. It's actually a good thing.

Edit: classes are meant to be inherited, duh. :oops:
Last edited by Flying Fox on Sat May 09, 2009 3:59 pm, edited 1 time in total.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24416
Joined: Mon May 24, 2004 2:19 am

Re: are you a DLL expert?

Postposted on Sat May 09, 2009 1:13 pm

Thanks FF, that helped my understanding. I hadn't considered caching the result and/or inserting a middle layer. By the way, in the example code, were the classes 'FunkyCalculationGeneric' and 'FunkyCalculationSSE2' supposed to inherit from 'FunkyCalculationBase' or implement some interface?

When I picked up programming eight years ago, I was doing a lot GUIs and reading a lot OO and catious books like this, this, and this. But now most of my programs are simulations that barely have a console interface and I'm reading books like this. Now when I face a robustness/performance tradeoff in a time-critical piece of code, it's tough for me to decide (1) if I should be safe and add that extra 'Assert' or try-catch block, or (2) if I should go for speed and hope my unit & integration tests address all the potential problems. So I try to steal ideas from people like you.
wibeasley
Gerbil Elite
Gold subscriber
 
 
Posts: 952
Joined: Sat Mar 29, 2008 3:19 pm
Location: Norman OK


Return to Developer's Den

Who is online

Users browsing this forum: No registered users and 1 guest