News:

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

Using _imp__ in a macro with INVOKE

Started by sinsi, August 17, 2006, 06:02:05 AM

Previous topic - Next topic

sinsi

I wanted to use "mov esi,FindWindow" and then "call esi" a few times...
After much wailing and gnashing of teeth I made the following macro

xyzzy macro n,a,c
    local s,t,u,x,y
    y textequ <>
    ifnb <c>
     y textequ < :DWORD>
     rept (c/4)-1
      y catstr y,<,:DWORD>
     endm
    endif
    t CATSTR <pr>,<n>
    t TYPEDEF PROTO STDCALL y
    u CATSTR <P>,<n>
    u TYPEDEF PTR t
    s CATSTR <_imp__>,<n>,<a>,<@>,<c>
    EXTERNDEF s:u
    n TEXTEQU <s>
endm

So all I do in my windows.inc is

xyzzy GetClientRect,,8
xyzzy GetCommandLine,A,0

and I can use "INVOKE GetCommandLine"

Is this a good way of doing it?
The main reason was to do

push 0
jmp ExitProcess

instead of

INVOKE ExitProcess,0

which gets assembled as

push 0
call ExitProcess
ret

at the end of my main proc...
And it saves a byte here and there.

Then there is

push 0
call GetModuleHandle

which gets translated to

push 0
call jmp_GetModuleHandle
...
jmp_GetModuleHandle PROC
  jmp _imp__GetModuleHandleA@4
jmp_GetModuleHandle ENDP

which seems to be a bit indirect as well as wasting bytes...
Light travels faster than sound, that's why some people seem bright until you hear them.

ToutEnMasm

Hello,
Why don't use the FUNC macro


      FUNC MACRO parameters:VARARG
        invoke parameters
        EXITM <eax>
      ENDM


and then


mov esi,FUNC (FindWindow,addr ClassName,addr WindowName )
;return the handle of the window


                 ToutEnMasm


Boucly

ToutEnMasm, I think sinsi was talking about having to call API functions through jmp instructions. I was confused about that myself too. I found something on Google about it, but doesn't help me much... Calling Win32 API Routines from HLA Can someone explain what it means in plainner English?

Boucly

Tedd

What Sinsi is actually talking about:
When you build an exe (using ml and microsoft's link) calls to api functions are translated into a call to an-indirect-jump-to-the-function.
What he would prefer is to cut out this indirection and be able to either call the api function directly, or get its address and call it indirectly through a register (for a sequence of many calls to the same function.)

Sinsi:
Firstly, the reason it's done like this is down to the way the exe is built; the assembler doesn't know where the api functions will be so it produces a table for the linker to fix when it does its stuff. I seem to remember that there is a way around it, without needing to play around with a heap of macros, but I don't remember what that is off the top off my head.
You should also keep in mind that since the api functions come from dlls, and dlls are dynamic, the function entry-points themselves are not at known addresses until after your exe has been loaded. So some indirection is necessary (therefore, so is the table) otherwise the loading process could not be dynamic. However, this should not prevent you from obtaining the address out of the table (it's filled in before your program starts execution) and using the address directly. Though you wouldn't want to jmp to these functions, otherwise where would they return to?
No snowflake in an avalanche feels responsible.

Boucly

Tedd,
Calling Win32 API Routines from HLA The page that this link goes to says something about turning the pointer to the API instructions into an extern thingy to solve the problem. What does that mean?
Boucly

Tedd

Quote from: Boucly on August 17, 2006, 01:07:45 PM
The page that this link goes to says something about turning the pointer to the API instructions into an extern thingy to solve the problem. What does that mean?

It's how to solve the problem from HLA, using HLA specific features. What it means is that, normally, functions are called directly (you already know their address). But for api functions, you don't know the address in advance, so you have to call them indirectly, and have the address filled-in by the loader when it loads your exe. Specifying the api function as 'extenal' causes HLA to make the call indirect (you don't know the address of an external function in advance), and so it fixes the calls to the api functions.
(This is may not be precisely what it talks about - I only browsed the page, I'm not going to read it all :P)
No snowflake in an avalanche feels responsible.

ToutEnMasm


Masm use STANDARD call (stack return inchanged), HLA pascal call.See the agner site for explanation on this differents call.
For the first question, If it is to make a direct call (a jmp is not enough,there is always something to return) linking dynamically is needed.Use getprocadress.
                     

ToutEnMasm

HLA with is pascal call seem to have a problem
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core___stdcall.asp
                                ToutEnMasm

Obsolete Calling Conventions
Home |  Overview |  How Do I

The __pascal, __fortran, and __syscall calling conventions are no longer supported. You can emulate their functionality by using one of the supported calling conventions and appropriate linker options.

WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.

Boucly

Tedd, Appreciate it and ToutEnMasm, I finally understood. But how does the API functions know where to return to even if I don't use a direct JMP. I mean, where is the pointer to the original calling instructions stored: in the stack, register?

Boucly

mnemonic

Quote from: Boucly on August 17, 2006, 02:19:03 PM
I mean, where is the pointer to the original calling instructions stored: in the stack, register?

You may have a further look at the CALL instruction.
CALL pushes EIP onto the stack and then JMPs to the label given to CALL. On the other side RET pops the value back to EIP and the execution continues there. That is the main reason why you have to watch out that the stack is always balanced when fiddling between procedures and functions. If your stack is not balanced you just JMP back to an "random" address and Windows will close down your App (or your Real-Mode OS crashes, DOS e.g.).
Be kind. Everyone you meet is fighting a hard battle.--Plato
-------
How To Ask Questions The Smart Way

Boucly

If the ret function pop the next value in the stack into EIP (I thought it was forbidden to change EIP), doesn't that points to the instruction that called the function in the first place?

Boucly

ToutEnMasm


The better maner to see how it's work is to used a debugger.
First,follow a call (or invoke) to a proc in your source code and  then follow the call to a library function,debug it step by step.
You can also disassemble a little code that you have made with this two forms off call.
You will see that for calling a function in the library,the linker create a list at the end of the code.But the result is the same.
                                     ToutEnMasm

Boucly

Okay, thank you very much everyone.

With gratitude, Boucly

mnemonic

Boucly,

don't take my words as rules that are set in stone. I just wanted to keep it simple stupid. :wink
All I did was breaking the instructions CALL and RET down into instructions you might know (PUSH, JMP and POP).
And for sure you cannot PUSH or POP EIP manually, but that is the thing CALL and RET do internally.
And yes, the address that gets PUSHed is the address of the instruction after the RET.

But anyway, my first hint was to have a deeper look at the documentation for CALL (Intel Docs and the like), because that is the bible where CPUs live after.  :wink
Be kind. Everyone you meet is fighting a hard battle.--Plato
-------
How To Ask Questions The Smart Way

Boucly

Okay. Mnemonic.

I have the Intel documents. I will read every word. Its not like I won't have time to read a 4 × 500 pages of .pdf file.  :P

Anyway, this is what the manual said:

QuoteRET—Return from Procedure

Description

Transfers program control to a return address located on the top of the stack. The address is
usually placed on the stack by a CALL instruction, and the return is made to the instruction that
follows the CALL instruction.

The optional source operand specifies the number of stack bytes to be released after the return
address is popped; the default is none. This operand can be used to release parameters from the
stack that were passed to the called procedure and are no longer needed. It must be used when
the CALL instruction used to switch to a new procedure uses a call gate with a non-zero word
count to access the new procedure. Here, the source operand for the RET instruction must
specify the same number of bytes as is specified in the word count field of the call gate.

I should have read before I post. Sorry.

Last question, what is an opcode?

Boucly

Edit: it is mentioned in the manual