I\'m stuck as to why I can\'t load my dll \"interfac\" using LoadLibrary. It seems to be failing when loading a dependency but I\'m not sure why.
Here\'s the code: <
One likely explanation for the ERROR_BAD_EXE_FORMAT
error from LoadLibrary
is that INTERFAC.DLL
was linked with a PCDLRN.LIB
import library that declares PCDLRN
exports, but the PCDLRN.EXE
found at runtime does not have an exports table.
The gflags (x86)'s loader snaps
shows that the error is triggered while loading PCDLRN.EXE
, specifically while resolving the import table of INTERFAC.DLL
:
18a0:2a40 @ 06859098 - LdrpHandleOneOldFormatImportDescriptor - INFO: DLL "C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL" imports "PCDLRN.exe" [...] 18a0:2a40 @ 06859597 - LdrpHandleOneOldFormatImportDescriptor - ERROR: Loading "?????" from the import table of DLL "C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL" failed with status 0xc000007b
Status 0xc000007b
is STATUS_INVALID_IMAGE_FORMAT:
{Bad Image} %hs is either not designed to run on Windows or it contains an error. Try installing the program again using the original installation media or contact your system administrator or the software vendor for support.
NTSTATUS STATUS_INVALID_IMAGE_FORMAT
is mapped to Win32 error code ERROR_BAD_EXE_FORMAT
per INFO: Mapping NT Status Error Codes to Win32 Error Codes.
I was able to duplicate the same ERROR_BAD_EXE_FORMAT with a mockup of the given scenario: link INTERFAC.DLL
to a PCDLRN.LIB
that declares an exported foo
, then substitute a PCDLRN.EXE
without an exports table, and finally attempt to LoadLibrary
INTERFAC.DLL
.
As a side note, linking a DLL
to the import library of another EXE
is uncommon and fraught with pitfalls. In the case here, even if error 193 is fixed, the functions in the EXE
would not be directly usable from the DLL
. See for example Load EXE as DLL: Mission Possible for more details.
Edit: Though what follows makes sense it is actually incorrect. I'm keeping it here just for reference, but I may delete the answer later.
Note however that (at least on Windows 10, which I used to check) even if relocation information is available in the file, if the module is not a DLL it is not applied, so even if you didn't get that error, unless your INTERFAC.DLL applies relocations to PCLDRN.exe after loading it, trying to use it is likely to break somewhere along the way.
With the loader snaps output the situation seems pretty obvious to me.
The loader snaps output once the file is found are (I numbered the lines):
(1) 18a0:2a40 @ 06859098 - LdrpMapViewOfSection - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\PCDLRN.exe
(2) 'CNCServer.exe': Loaded 'C:\QA\Pcdlrn\Win32\Release\PCDLRN.exe', Symbols loaded.
(3) 18a0:2a40 @ 06859597 - LdrpMapViewOfSection - RETURN: Status: 0x40000003
(4) 'CNCServer.exe': Unloaded 'C:\QA\Pcdlrn\Win32\Release\PCDLRN.exe'
(5) 18a0:2a40 @ 06859597 - LdrpFindOrMapDll - RETURN: Status: 0xc000007b
(6) 18a0:2a40 @ 06859597 - LdrpLoadImportModule - ERROR: Loading DLL PCDLRN.exe from path C:\QA\Pcdlrn\CNCSERVER\Win32\Release;C:\Windows\system32;C:\Windows\system;C:\Windows;.;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\NativeBinaries\x86;C:\windows\system32;C:\windows;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:
(7) 18a0:2a40 @ 06859597 - LdrpLoadImportModule - RETURN: Status: 0xc000007b
(8) 18a0:2a40 @ 06859597 - LdrpHandleOneOldFormatImportDescriptor - ERROR: Loading "?????" from the import table of DLL "C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL" failed with status 0xc000007b
(9) 18a0:2a40 @ 06859613 - LdrpUnloadDll - INFO: Unmapping DLL "C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL"
(10) 'CNCServer.exe': Unloaded 'C:\QA\Pcdlrn\Win32\Release\INTERFAC.dll'
(11) 18a0:2a40 @ 06859613 - LdrpLoadDll - RETURN: Status: 0xc000007b
(12) 18a0:2a40 @ 06859613 - LdrLoadDll - RETURN: Status: 0xc000007b
LdrpMapViewOfSection
returns an error code (0x40000003) on line 3 which causes the module to unload (line 4) and then LdrpMapViewOfSection
's caller - LdrpFindOrMapDll
- translates the error code to 0xc000007b (STATUS_INVALID_IMAGE_FORMAT).
But the error that caused the load to fail was 0x40000003 - STATUS_IMAGE_NOT_AT_BASE
. The description of this NTSTATUS is:
{Image Relocated} An image file could not be mapped at the address that is specified in the image file. Local fixes must be performed on this image.
(Source: NTSTATUS Values)
By default, EXEs don't contain relocation information (as was mentioned in the comments). Usually that's not a problem as the address space is rather free when the EXE is loaded into it. But your address space isn't free. To make matters worse, all EXEs compiled by Visual C++ share the same base address by default:
The /BASE option sets a base address for the program, overriding the default location for an .exe or DLL file. The default base address for an .exe file is 0x400000 for 32-bit images or 0x140000000 for 64-bit images. For a DLL, the default base address is 0x10000000 for 32-bit images or 0x180000000 for 64-bit images.
(Source: Linker Options: /BASE (Base Address))
That's probably the situation you have. CNCServer.exe already occupies 0x400000 and that's the only place PCDLRN.exe can go. LdrpMapViewOfSection
can't map PCDLRN.exe to 0x400000 because it isn't free and fails to map in anywhere else because there's no relocation information.
And from there it goes up the call stack and changes the error, but not the underlying problem. Which is lack of relocation information.
You can see what happened when this error is encountered for a DLL with relocation information in your output too. When INTERFAC.dll is initially loaded:
18a0:2a40 @ 06858989 - LdrpFindOrMapDll - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL DLL path: C:\QA\Pcdlrn\CNCSERVER\Win32\Release;C:\Windows\system32;C:\Windows\system;C:\Windows;.;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\NativeBinaries\x86;C:\windows\system32;C:\windows;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows
18a0:2a40 @ 06858989 - LdrpSearchPath - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL DLL path: C:\QA\Pcdlrn\CNCSERVER\Win32\Release;C:\Windows\system32;C:\Windows\system;C:\Windows;.;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\NativeBinaries\x86;C:\windows\system32;C:\windows;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\s
18a0:2a40 @ 06858989 - LdrpResolveFileName - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL
18a0:2a40 @ 06858989 - LdrpResolveFileName - RETURN: Status: 0x00000000
18a0:2a40 @ 06858989 - LdrpResolveDllName - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL
18a0:2a40 @ 06858989 - LdrpResolveDllName - RETURN: Status: 0x00000000
18a0:2a40 @ 06858989 - LdrpSearchPath - RETURN: Status: 0x00000000
18a0:2a40 @ 06859036 - LdrpMapViewOfSection - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL
'CNCServer.exe': Loaded 'C:\QA\Pcdlrn\Win32\Release\INTERFAC.dll', Symbols loaded.
18a0:2a40 @ 06859098 - LdrpMapViewOfSection - RETURN: Status: 0x40000003
18a0:2a40 @ 06859098 - LdrpRelocateImage - ENTER: DLL name: C:\QA\Pcdlrn\Win32\Release\INTERFAC.DLL
18a0:2a40 @ 06859098 - LdrpProtectAndRelocateImage - RETURN: Status: 0x00000000
18a0:2a40 @ 06859098 - LdrpRelocateImage - RETURN: Status: 0x00000000
18a0:2a40 @ 06859098 - LdrpFindOrMapDll - RETURN: Status: 0x00000000
When LdrpMapViewOfSection
returns STATUS_IMAGE_NOT_AT_BASE
, it's caller (LdrpFindOrMapDll
) goes ahead and calls LdrpRelocateImage
, something it apparently can't to for PCDLRN.exe.