News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

What is wrong in this code

Started by untio, July 13, 2010, 03:37:01 PM

Previous topic - Next topic

untio

Hi,
I have tried to create a procedure to call any function inside a dll with LoadLibrary and GetProcAddress. My problem arises because it works sometimes perfect but sometimes the program does not end. I have a project in development at sourceforge written in assembly and named josecalendar. The last weekend I tried to substitute some calls in the program with this code. The project consists of a dll that calculates a calendar and of an exe that visualizes it. When I use this code in the dll, the program works fine, but when I use it in the exe the window closes but the program remains in the task manager and this with a simple call to PostQuitMessage.
May be someone can help me to understand why this happens.
This is the code:
.486
.model flat, stdcal12
option casemap : none

include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib

.code

;[ebp + 8]->Pointer to the dll name.
;[ebp + 12]->Pointer to the function name.
;[ebp + 16]->Number of arguments to pass to the function.
;[ebp + 20]->First argument to the function.
;[ebp + 24]->Second argument to the function.
;[ebp + 28]->Third argument to the function.
;[ebp + ...]->Nth argument to the function.

public  executefunction
executefunction:
push ebp
mov ebp, esp

sub esp, 12

Invoke LoadLibraryA, dword ptr [ebp + 8]
cmp eax, 0
jz od2a

mov [ebp - 4], dword ptr eax

Invoke GetProcAddress, eax, dword ptr [ebp + 12]
cmp eax, 0
jz od2a

mov [ebp - 8], dword ptr eax

mov ecx, dword ptr [ebp + 16]
mov eax, ecx
shl eax, 2
add eax, 16
od4a:
cmp ecx, 0
jz od3a
push dword ptr [ebp + eax]
sub eax, 4
dec ecx
jmp od4a

od3a:
call dword ptr [ebp - 8]
mov [ebp - 12], dword ptr eax
Invoke FreeLibrary, dword ptr [ebp - 4]
mov eax, dword ptr [ebp - 12]
mov esp, ebp
pop ebp
ret

od2a:
mov eax, 0
mov esp, ebp
pop ebp
ret


end



Thanks in advance.

untio

Hi,
I have retried to include this code in my project and it seems to work perfect. May be the last weekend my computer was silly.
But another question appears. In this manner, importing all the functions, can I save some size to the executable.
Thanks in advance.

hutch--

The code will probably get bigger due to the extra number of LoadLibrary(), GetProcAddress(), FreeLibrary() calls. You can do it this way but its rarely ever any advantage unless you are testing to see if a DLL exists. If for example you want to find out if a DLL is installed on the computer if you use the previously mentioned API functions you know if its there or not where if you just assume its there and its not, then the app will not work.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

untio,

One thing I noticed when I tested the procedure is that it will leave the parameters on the stack. To correct this you can remove them from the stack after each call to the procedure returns with an:

add esp, N

Where N is the total number of parameter bytes (for DWORD parameters the number of parameters * 4), or define the procedure with PROC, for example:

executefunction proc C a1:DWORD,a2:DWORD,a3:DWORD,av:VARARG

;push ebp
;mov ebp, esp

  LOCAL x:DWORD,y:DWORD,z:DWORD
;sub esp, 12

. . .

od3a:
call dword ptr [ebp - 8]
mov [ebp - 12], dword ptr eax
Invoke FreeLibrary, dword ptr [ebp - 4]
mov eax, dword ptr [ebp - 12]
;mov esp, ebp
;pop ebp
ret

od2a:
mov eax, 0
;mov esp, ebp
;pop ebp
ret

executefunction endp


And call it with invoke, in which case ML will generate code to remove the parameters from the stack, for example:

    invoke executefunction, chr$("msvcrt.dll"),
                            chr$("printf"),
                            3,
                            chr$("%d%c"),
                            123456789,
                            10
    ; generated add esp, 24 will go here


Note in the procedure code that I did not bother to replace the [ebp +/- N] operands with the parameter or LOCAL name.

eschew obfuscation

KeepingRealBusy

Note: INVOKE will only generate the stack adjustment if the procedure that is called is declared CDECL, but it will not do this for STDCALL. In this particular case, the call IS CDECL (printf) so that would work.

Note further: If the procedure you call is returning flags, the stack adjustment should be coded as follows to preserve the flags:


    lea esp,[esp+n]


Dave.

untio

Hi,
When I tried this code I called it in a c manner with the add esp, x. The size of the executable in a little project is the same but with this method is really easy to make a mistake.
It was only a test. I shall return to the common manner. I am learning to program in assembly and this was only a probe.
Thanks to all of you for your time.

drizz

The only problem is it's difficult to read  :'(

Using variable names instead of EBP:
executefunction proc C public pDll, pFun, bCCalling, nArgs, vaArgs:VARARG
LOCAL hMod, lpFn, RetV
invoke LoadLibrary,pDll
.if eax
mov hMod,eax
invoke GetProcAddress,hMod,pFun
.if eax
mov lpFn,eax
mov ecx,nArgs
lea eax,vaArgs[ecx*4-1*4]; (ecx-1)*4
.while ecx
push dword ptr [eax]
sub eax,4
dec ecx
.endw
call lpFn
mov RetV,eax
.if bCCalling
mov ecx,nArgs
shl ecx,2
add esp,ecx
.endif
invoke FreeLibrary,hMod
mov eax,RetV
.endif
.endif
ret
executefunction endp


executefunction proto C pDll:DWORD, pFun:DWORD, bCCalling:DWORD, nArgs:DWORD, vaArgs:VARARG


invoke executefunction,T('kernel32.dll'),T('Beep'),FALSE,2,100,1000
invoke executefunction,T('msvcrt.dll'),T('_beep'),TRUE,2,500,1000
The truth cannot be learned ... it can only be recognized.

MichaelW

Quote from: KeepingRealBusy on July 14, 2010, 01:06:35 PM
Note: INVOKE will only generate the stack adjustment if the procedure that is called is declared CDECL, but it will not do this for STDCALL.

Yes, I should have pointed that out instead of expecting the "C" in the definition to tell the story.

QuoteIn this particular case, the call IS CDECL (printf) so that would work.

You've lost me here. In my example printf is not being invoked, it is being called, and the lack of a stack adjustment didn't matter because the enclosing procedure restores ESP to its entry-point value before executing RET.

eschew obfuscation

untio

Hi,
I discard this method. It does not minimizes size and I think that it is slower to call functions in this manner and may be the dll does not exists in the target computer. I shall forgive this probe.

Thanks to all for your time and patience.