views:

92

answers:

2

I am exporting a function [using _declspec(dllexport)] from a C++ exe. The function works fine when invoked by the exe itself. I am loading this exe (lets call this exe1) from another exe [the test project's exe - I'll call this exe2] using static linking i.e I use exe1's .lib file while compiling exe2 and exe2 loads it into memory on startup just like any dll. This causes the function to fail in execution.

The exact problem is revealed in the disassembly for a switch case statement within the function.

Assembly code when exe1 invokes the function

   switch (dwType)
0040FF84  mov         eax,dword ptr [dwType] 
0040FF87  mov         dword ptr [ebp-4],eax 
0040FF8A  cmp         dword ptr [ebp-4],0Bh 
0040FF8E  ja          $LN2+7 (40FFD2h) 
0040FF90  mov         ecx,dword ptr [ebp-4] 
0040FF93  jmp         dword ptr  (40FFE0h)[ecx*4] 

Consider the final two instructions. The mov moves the passed in argument into ecx. At 40EFF0h we have addresses to the various instructions for the respective case statements. Thus, the jmp would take us to the relevant case instructions

Assembly code when exe2 invokes the function

   switch (dwType)
0037FF84  mov         eax,dword ptr [dwType] 
0037FF87  mov         dword ptr [ebp-4],eax 
0037FF8A  cmp         dword ptr [ebp-4],0Bh 
0037FF8E  ja          $LN2+7 (37FFD2h) 
0037FF90  mov         ecx,dword ptr [ebp-4] 
0037FF93  jmp         dword ptr [ecx*4+40FFE0h]

Spot whats going wrong? The instruction addresses. The code has now been loaded into a different spot in memory. When exe1 was compiled, the compiler assumed that we will always be launching it and hence it would always be loaded at 0x0040000 [as is the case with all windows exes]. So it hard-coded a few values like 40FFE0h into the instructions. Only in the second case 40FFE0 is as good as junk memory since the instruction address table we are looking for is not located there.

How can I solve this without converting exe1 to a dll?

+1  A: 

just don't do it. It doesn't worth the bother.

I've tried doing what you're trying a while ago. You can possibly solve the non-relocatable exe problem by changing the option in the properties window under "Linker->Advenced->Fixed base address" but then you'll have other problems.
The thing that finally made me realize its a waste of time is realizing that the EXE doesn't have a DllMain() function. This means that the CRT library is not getting initialized and that all sorts of stuff don't work the way you expect it to.

Here's the question I posted about this a while back

shoosh
A: 

Have you considered another way of doing this? Such as making the 2nd .exe into a .dll and invoking it with rundll32 when you want to use it as an executable?

Otherwise: The generated assembly is fine. The problem is that Win32 portable executables have a base address (0x0040000 in this case) and a section that contain details locations of addresses so that they can be rebased when required.

So one for two things is happening: - Either the compiler isn't including the IMAGE_BASE_RELOCATION records when it builds the .exe. - Or the runtime isn't performing the base relocations when it dynamiclaly loads the .exe - (possibly both)

If the .exe does contain the relocation records, you can read them and perform the base relocation yourself. You'll have to jump through hoops like making sure you have write access to the memory (VirtualAlloc etc.) but it's conceptually quite simple.

If the .exe doesn't contain the relocation records you're stuffed - either find a compiler option to force their inclusion, or find another way to do what you're doing.

Edit: As shoosh points out, you may run into other problems once you fix this one.

Joe Gauterin