Hello,
Some C compilers are not allowing inline 64-bit assembly instructions. A workaround is to define an array of machine code and copying this to a memory portion allowed to execute code.
Code assembled with Poasm V12.00.1 :
.code
CallFunc64 PROC function:QWORD,ArgNumb:QWORD,ArrayOfParams:QWORD
NumbOfArgs TEXTEQU <QWORD PTR [rsp+16+136]>
func TEXTEQU <QWORD PTR [rsp+8+136]>
sub rsp,8+16*8 ; 8 bytes = stack alignment
; 16 params = reserve shadow space
; for maximum 16 params
; Store the parameters rcx and rdx in the shadow space
; as they will be overwritten later
mov QWORD PTR [rsp+8+136],rcx ; store the function
mov QWORD PTR [rsp+16+136],rdx ; store the number of args
mov rax,r8
mov rcx,QWORD PTR [rax]
add rax,8
OneArg:
cmp rdx,1 ; rdx -> ArgNumb
je finish
TwoArgs:
mov rdx,QWORD PTR [rax]
add rax,8
cmp NumbOfArgs,2
je finish
ThreeArgs:
mov r8,QWORD PTR [rax]
add rax,8
cmp NumbOfArgs,3
je finish
FourArgs:
mov r9,QWORD PTR [rax]
add rax,8
cmp NumbOfArgs,4
je finish
MoreArgs:
mov r10,32
sub NumbOfArgs,4
@@:
mov r11,QWORD PTR [rax]
mov QWORD PTR [rsp+r10],r11
add rax,8
add r10,8
dec NumbOfArgs
jnz @b
finish:
call func
add rsp,8+16*8
ret
CallFunc64 ENDP
END
The code above accepts 3 parameters. The first is the function to be called from the inline code. The two others are the number of the arguments to be passed to the function and the address of the first element of the paramater array.
Extracting the flat binary code from the object module with the GNU binary tool objcopy. This can be obtained from a MSYS2 installation :
objcopy --dump-section .text=CallFunc64.bin CallFunc64.obj
Dumping the binary file CallFunc64.bin with MrBcx's Dump utility :
https://bcxbasiccoders.com/smf/index.php?topic=936.msg4740#msg4740The BCX code :
' Compile only to 64-bit
FUNCTION WINMAIN()
LOCAL hMod AS HMODULE
LOCAL ArrayOfParams[6] AS LONGLONG
LOCAL Asm64 AS void PTR
ArrayOfParams[0] = (LONGLONG) NULL
ArrayOfParams[1] = (LONGLONG) "This message box will be destroyed after 4 seconds."
ArrayOfParams[2] = (LONGLONG) "Hello"
ArrayOfParams[3] = (LONGLONG) MB_ICONWARNING
ArrayOfParams[4] = (LONGLONG) LANG_NEUTRAL
ArrayOfParams[5] = (LONGLONG) 4000 ' Timeout after 4 seconds
hMod = LOADLIBRARY("user32.dll")
SET InlineAsm [] AS UCHAR
72, 129, 236, 136, 0, 0, 0, 72, 137, 140, 36, 144, 0, 0, 0, 72, 137, _
148, 36, 152, 0, 0, 0, 76, 137, 192, 72, 139, 8, 72, 131, 192, 8, 72, _
131, 250, 1, 116, 95, 72, 139, 16, 72, 131, 192, 8, 72, 131, 188, 36, _
152, 0, 0, 0, 2, 116, 77, 76, 139, 0, 72, 131, 192, 8, 72, 131, 188, 36, _
152, 0, 0, 0, 3, 116, 59, 76, 139, 8, 72, 131, 192, 8, 72, 131, 188, 36, _
152, 0, 0, 0, 4, 116, 41, 73, 199, 194, 32, 0, 0, 0, 72, 131, 172, 36, _
152, 0, 0, 0, 4, 76, 139, 24, 78, 137, 28, 20, 72, 131, 192, 8, 73, 131, _
194, 8, 72, 255, 140, 36, 152, 0, 0, 0, 117, 231, 255, 148, 36, 144, 0, 0, _
0, 72, 129, 196, 136, 0, 0, 0, 195
END SET
Asm64 = VirtualAlloc(NULL, SIZEOF(InlineAsm), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
memcpy(Asm64, InlineAsm, SIZEOF(InlineAsm))
((void (*)())Asm64)(GetProcAddress(hMod, "MessageBoxTimeoutA"), 6, ArrayOfParams)
VirtualFree(Asm64, 0, MEM_RELEASE)
FreeLibrary(hMod)
FUNCTION = 0
END FUNCTION
This application displays a message box destroying itself after 4000 miliseconds. MessageBoxTimeout is an undocumented function :
https://www.codeproject.com/Articles/7914/MessageBoxTimeout-APIWith thanks to MrBcx, here is a better method to implement DYNACALL :
https://bcxbasiccoders.com/smf/index.php?topic=952.0Attached is the project containing the source files and the compiled executable.