Hi,
I already posted this macro to the masm32forum, but haven't got any reply. Aditionally I know that these both sites visit different members, so I post it here too.

For some specific reason I need to assemble the CALL instruction myself using the following MASM macro "call2opcd".
I've tested this macro (with examples given in the code section) and it seems to be working well, but I appreciate your comments :)
There's a bunch of macros used by this macro, so if you want to compile this sample, download the package here: http://www.webpark.cz/mazegen/call2opcd_res.zip (4.5 KB), please (it seems that it is impossible to open this link directly from this site, so use cut&paste in new panel/window, it should work). It also contains the following asm source code file.


; assumptions:
; o memory-access size is always 32 bits (i.e. CALL AX returns compile-time error)
; - if the operand size is 32-bit, it is therefore near call
; o if the argument references undefined symbol, it is either an user error or
; a forward-referenced label: macro always assumes it is the label

call2opcd MACRO arg:VARARG
local arg
local curreip ;; current EIP to fix relative offset
local start, end
local pos, tmp

IF @InStr (, <arg>, <,>)
ErrorEcho <"call &arg" instruction, call2opcd macro>, <too many arguments to call: arg>
EXITM
ENDIF

IF @InStr (, arg, <$>) ;; label relative to EIP? (e.g. CALL $+5)
BYTE 0E8H ;; relative direct call
DWORD arg - 1 - curreip ;; minus 1 byte

ELSE

IFE $IsNoError (arg) ;; is it an user error or a forward-referenced label?
BYTE 0E8H ;; always assume it is forward-referenced label
DWORD arg - curreip

ELSE

IF $IsCodeLabel (arg) ;; is it backward-referenced label?
BYTE 0E8H ;; relative direct call
DWORD arg - curreip

ELSE ;; it is indirect call

IF $IsReg (arg)
IFE ($IsGeneralReg (arg)) AND ($GetSizeOf (arg) GT TYPE BYTE)
ErrorEcho <"call &arg" instruction, call2opcd macro>, <invalid operand : arg>
EXITM
ENDIF
IF TYPE (arg) NE TYPE DWORD
ErrorEcho <"call &arg" instruction, call2opcd macro>, <only DWORD operand supported : arg>
EXITM
ENDIF

start:
not arg ;; assemble needed opcode extension 010
end:

ORG start
BYTE 0FFH ;; make call near
ORG end

ELSE ;; it is indirect call, address given in memory
IF TYPE (arg) EQ TYPE BYTE
ErrorEcho <"call &arg" instruction, call2opcd macro>, <invalid operand : arg>
EXITM
ENDIF
IFE (TYPE (arg) EQ TYPE DWORD) OR (TYPE (arg) EQ TYPE FWORD)
ErrorEcho <"call &arg" instruction, call2opcd macro>, \
<only DWORD or FWORD operand supported : arg>
EXITM
ENDIF

start:
IF TYPE (arg) EQ TYPE DWORD
;; if 32-bit operand, always assume it is near call
not arg ;; assemble needed opcode extension 010
ELSE

;; else it is far call: always add "dword ptr" because of NEG instr

pos INSTR $lcase (arg), <ptr> ;; is there any "ptr" already?
IF pos ;; yea, replace this whole string
tmp CATSTR <dword ptr>, @SubStr (arg, pos + @SizeStr (<ptr>))
ELSE
tmp CATSTR <dword ptr>, <arg>
ENDIF

neg tmp ;; assemble needed opcode extension 011
ENDIF
end:

ORG start
BYTE 0FFH ;; make call
ORG end
ENDIF

ENDIF
ENDIF
ENDIF

curreip = $

ENDM

.DATA

neartarget DWORD ?
fartarget FWORD ?

.CODE
Start:

; tests:

call $+5
call2opcd $+5 ; explicit EIP-relative call to next instruction
nop

call somelabel
call2opcd somelabel ; forward-referenced label, relative call
nop

call Start
call2opcd Start ; backward-referenced label, relative call
nop

call edi
call2opcd edi ; absolute indirect near call, address given in register
nop

call [neartarget]
call2opcd [neartarget] ; absolute indirect near call, address given in memory
nop

call [fartarget]
call2opcd [fartarget] ; absolute indirect far call, address given in memory
nop

call dword ptr [edi]
call2opcd dword ptr [edi] ; absolute indirect near call, address given in memory
nop

call fword ptr [edi]
call2opcd fword ptr [edi] ; absolute indirect far call, address given in memory

somelabel:

; error-trapping tests:

; call2opcd Start, somelabel
; call2opcd al
; call2opcd cs
; call2opcd byte ptr [eax]
; call2opcd word ptr [eax]

END Start
Posted on 2004-12-17 07:30:06 by MazeGen