flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > extended import and stdcall/invoke macroses

Author
Thread Post new topic Reply to topic
IronFelix



Joined: 09 Dec 2004
Posts: 141
Location: Russia, Murmansk region
IronFelix 24 Apr 2009, 08:23
Hi all!
I have made some small update in import, stdcall, invoke, ccall and cinvoke macroses for next reasons:
1. In case when some of application functions should be placed in separate DLL and still used in that application all "stdcall"s with such functions must be replaced with "invoke"s - not so easy, IMHO. With this macro update direct/indirect calls are detected automatically and are based on if function is actually imported or not.
2. Some of DLLs have exported functions with same names. For example ntdll.dll and kernel.dll both have RtlMoveMemory and some other functions.
With such macro no errors will be in case of import all of those DLL's contents. So it is enough to use some DLL converter programm which will make whole DLL contents import file in FASM syntax without need to modify such file almost always.

Here is the code :
Code:
format PE GUI 4.0
entry Main

 include "win32a.inc"

 ; Updated import macro
 ; Here additional forward-referenced constants are set in order to
 ; detect direct/indirect call needed in stdcall/invoke
 ; it also exclude earlier imported functions with same name, for example
 ; ntdll.dll and kernel.dll both have RtlMoveMemory and some other functions
 ; with such macro no errors will be in case of import all of those DLL's
 ; contents
 macro import name,[label,string]
 {
   common
   DONE equ NO
   ; check, if we have at least one function which is not
   ; defined in earlier DLL imports
   forward
    match any , label#_importdone
    \{
     restore DONE
     DONE equ YES
    \}
   common
   ; if we have at least one function which is not
   ; defined in earlier DLL imports - make import table
   match =YES, DONE
   \{
    if defined name\#.referred
     name#.lookup:
    forward
     match any , label\#_importdone
     \\{
      if used label
       if string eqtype ''
        local _label
        dd RVA _label
       else
        dd 80000000h + string
       end if
      end if
     \\} 
    common
      if $ > name\#.lookup
       name\#.redundant = 0
       dd 0
      else
       name\#.redundant = 1
      end if
      name\#.address:
    forward
      match any , label\#_importdone
      \\{
       if used label
        if string eqtype ''
         label dd RVA _label
        else
        label dd 80000000h + string
        end if
        label\\#_dllimport = 1 ; mark function as DLL-imported
       end if
      \\} 
    common
      if ~ name\#.redundant
       dd 0
      end if
    forward
      match any , label\#_importdone
      \\{
       if used label & string eqtype ''
       _label dw 0
             db string,0
          rb RVA $ and 1
       end if
       ; mark function name as imported in order not to
       ; process it in next possible imports
       label\\#_importdone equ
      \\} 
    common
     end if
   \}
   restore DONE   
 }

; macro to choose call type based on imported constant definition
macro call_by_declare name
{
 ; match is used here to get proper name in cases like this:
 ; MessageBox  equ MessageBoxA
 ; ...
 ; import user32 ,\
 ;         MessageBoxA,   'MessageBoxA',\
 ;         MessageBoxW,   'MessageBoxW'
 match _name, name
 \{
  ; if function is imported - make indirect call
  if defined _name\#_dllimport
   call near [_name]
  ; otherwise - direct call
  else
   call near _name
  end if
 \}
}

; updated function call macroses with direct/indirect call detection

macro stdcall proc,[arg]               ; directly call STDCALL procedure
 { common
   match all, arg
   \{
    reverse
     pushd arg
    common
   \}
   call_by_declare proc}

macro invoke proc,[arg]                ; indirectly call STDCALL procedure
 { common
   match all, arg
   \{
    reverse
     pushd arg
    common
   \}
    call_by_declare proc}

macro ccall proc,[arg]                 ; directly call CDECL procedure
 { common
    size@ccall = 0
    match all, arg
    \{
     reverse
      pushd arg
     size@ccall = size@ccall+4
     common
    \}
    call_by_declare proc
    if size@ccall
     add esp,size@ccall
    end if }

macro cinvoke proc,[arg]               ; indirectly call CDECL procedure
 { common
    size@ccall = 0
    match all, arg
    \{
     reverse
      pushd arg
     size@ccall = size@ccall+4
     common
    \}
    call_by_declare proc
    if size@ccall
     add esp,size@ccall
    end if }

; now we are free to use stdcall or invoke with all functions in code -
; appropriate call type will be chosen automatically

; now let use UNICODE name to control ASCII/Unicode function calls
; if "UNICODE equ " is not specified - we have ASCII versions

; UNICODE equ

match =UNICODE, UNICODE
{
 MessageBox equ MessageBoxA
}

match  , UNICODE
{
 MessageBox equ MessageBoxW
}

; just a test function
proc TestFunction
 ; actually used MessageBox version depends on UNICODE name
 invoke MessageBox, 0, szOk, szTitle, MB_ICONINFORMATION
 ret
endp

Main:

 invoke TestFunction ; <- here stdcall actually used, so - no error till execution

 invoke ExitProcess, 0

; if we are not use Unicode
match =UNICODE, UNICODE
{
 szTitle  db "Test",0
 szOk     db "Call is successful.",0
}

; if Unicode is used
match  , UNICODE
{
 szTitle  du "Test",0
 szOk     du "Call is successful.",0
}

align 16
data import
 library kernel32,           'kernel32.dll',\
         user32,             'user32.dll'

 include "api\kernel32.inc"
 ; here we are free to import all contents of DLL
 ; but for example - only MessageBox'es
 import user32 ,\
         MessageBoxA,    "MessageBoxA",\
         MessageBoxW,    "MessageBoxW"

end data
    


Thanks.

_________________
Flat Assembler is the best!
Post 24 Apr 2009, 08:23
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.