I finally tried moving to 64bit code.. I've been avoiding it like the plague for ages!
I took one of the base samples, and extended it with some working 32bit masm code I had which includes some nice memory related features not present in the std windows.inc/kernel32.inc... I also had to extract a load of the functions from masm32lib and macros.asm to and manually make them 64bit/jwasm friendly.. all included in this source for reference.
Hope this is helpful to someone start, I wish I had the time to fully port the available macros.asm/m32lib to jwasm 64bit :)
;--- Win64 console application with exception handler, uses WinInc v2+
;--- assemble: jwasm -c -win64 -Zp8 Win64_5.asm
;--- link: link /subsystem:console /Libpath:\WinInc\Lib64 Win64_5.obj
;--- UPDATE (Must ensure you have latest WinInc, PellesC, run POLIB as per details to generate Lib64 in WinInc):
;--- assemble: jwasm -c -Zi -Zd -Zf -win64 -Zp8 Win64_5.asm
;--- link: link /subsystem:console /debug /pdb:win64_5.pdb /Libpath:"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\x64" /Libpath:"c:\jwasm\wininc\lib64" /Libpath:"c:\masm32\lib" win64_5.obj
option win64:1
option casemap:none
option frame:auto
.mmx
.xmm
.nolist
.nocref
WIN32_LEAN_AND_MEAN equ 1
include ..\WinInc\Include\windows.inc
.list
.cref
include ..\WinInc\Include\shellapi.inc
includelib msvcrt.lib
externdef printf : near
externdef kbhit : near
externdef strlen : near
includelib <kernel32.lib>
includelib <gdi32.lib>
includelib <user32.lib>
includelib <shell32.lib>
PROCESS_MEMORY_COUNTERS STRUCT
dwLength DWORD ?
PageFaultCount DWORD ?
PeakWorkingSetSize dq ?
WorkingSetSize dq ?
QuotaPeakPagedPoolUsage dq ?
QuotaPagedPoolUsage dq ?
QuotaPeakNonPagedPoolUsage dq ?
QuotaNonPagedPoolUsage dq ?
PagefileUsage dq ?
PeakPagefileUsage dq ?
PROCESS_MEMORY_COUNTERS ENDS
StdOut64 proto lpszText:QWORD
dwtoa proto :DWORD, :QWORD
GetPhysicallyInstalledSystemMemory PROTO :QWORD
K32GetProcessMemoryInfo PROTO :DWORD, :DWORD, :DWORD
GetProcessMemoryInfo EQU <K32GetProcessMemoryInfo>
; -----------------------------------------------------------
; This macro replaces quoted text with a DATA section OFFSET
; and returns it in ADDR "name" format. It is used by other
; macros that handle optional quoted text as a parameter.
; -----------------------------------------------------------
reparg MACRO arg
LOCAL nustr
quot SUBSTR <arg>,1,1
IFIDN quot,<"> ;; if 1st char = "
.data
nustr db arg,0 ;; write arg to .DATA section
.code
EXITM <ADDR nustr> ;; append name to ADDR operator
ELSE
EXITM <ADDR arg> ;; else return arg
ENDIF
ENDM
print MACRO arg1:REQ,varname:VARARG ;; display zero terminated string
invoke StdOut64,reparg(arg1)
IFNB <varname>
invoke StdOut64,CStr(varname)
ENDIF
ENDM
ustr$ MACRO DDvalue ;; unsigned integer from string
LOCAL rvstring
.data
rvstring db 20 dup (0)
align 4
.code
invoke dwtoa,DDvalue,ADDR rvstring
; invoke crt__ultoa,DDvalue,ADDR rvstring,10
EXITM <OFFSET rvstring>
ENDM
.data?
memStatus MEMORYSTATUSEX <?>
procMem PROCESS_MEMORY_COUNTERS <?>
totalMem dq ?
;--- CStr(): macro function to simplify defining a string
CStr macro Text:VARARG
local szText
.const
szText db Text,0
.code
exitm <offset szText>
endm
; ------------------------------------------------
; Function return value version of the above macro
; ------------------------------------------------
rv MACRO FuncName:REQ,args:VARARG
arg equ <invoke FuncName> ;; construct invoke and function name
FOR var,<args> ;; loop through all arguments
arg CATSTR arg,<,reparg(var)> ;; replace quotes and append arg
ENDM
arg ;; write the invoke macro
EXITM <eax> ;; EAX as the return value
ENDM
.CODE
align 4
dwtoa proc dwValue:DWORD, lpBuffer:QWORD
; -------------------------------------------------------------
; convert DWORD to ascii string
; dwValue is value to be converted
; lpBuffer is the address of the receiving buffer
; EXAMPLE:
; invoke dwtoa,edx,ADDR buffer
;
; Uses: eax, ecx, edx.
; -------------------------------------------------------------
push rbx
push rsi
push rdi
mov eax, dwValue
mov rdi, [lpBuffer]
or eax,eax
jnz sign
zero:
mov word ptr [rdi],30h
ret
sign:
jns pos
mov byte ptr [rdi],'-'
neg eax
inc rdi
pos:
mov ecx, 3435973837
mov rsi, rdi
.while (eax > 0)
mov ebx,eax
mul ecx
shr edx, 3
mov eax,edx
lea edx,[edx*4+edx]
add edx,edx
sub ebx,edx
add bl,'0'
mov [rdi],bl
inc rdi
.endw
mov byte ptr [rdi], 0 ; terminate the string
; We now have all the digits, but in reverse order.
.while (rsi < rdi)
dec rdi
mov al, [rsi]
mov ah, [rdi]
mov [rdi], al
mov [rsi], ah
inc rsi
.endw
pop rdi
pop rsi
pop rbx
ret
dwtoa endp
StdOut64 proc FRAME lpszText:QWORD
LOCAL hOutPut :QWORD
LOCAL bWritten :DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut,rax
mov rsi,lpszText
invoke lstrlen,rsi
mov edi,eax
invoke WriteConsole,hOutPut,rsi,edi,ADDR bWritten,NULL
mov eax, bWritten
ret
StdOut64 endp
exchdl proc pRecord:ptr, ulframe:qword, pContext:ptr, x4:ptr
add qword ptr [r8].CONTEXT.Rip_, 1 ;1=size of "in EAX, DX" opcode
mov eax, 0 ;0=continue execution?
ret
exchdl endp
VMwareInstalled proc FRAME:exchdl
mov eax, 0564D5868h
mov ebx, 08685D465h
mov ecx, 10
mov dx, 05658h
in eax, dx
cmp ebx, 564D5868h
setz al
movzx eax,al
ret
VMwareInstalled endp
main proc FRAME uses rbx rsi rdi
local dwWritten:DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov rbx,rax
invoke VMwareInstalled
.if ( eax )
invoke StdOut64,CStr("Running under VMWare")
print " ",13,10
.else
invoke StdOut64,CStr("Not Running under VMWare")
print " ",13,10
.endif
invoke GetPhysicallyInstalledSystemMemory, ADDR totalMem
mov ecx,sizeof(MEMORYSTATUSEX)
xor eax,eax
lea rdi,memStatus
rep stosb
lea rdi,memStatus
mov dword ptr (MEMORYSTATUSEX PTR [rdi]).dwLength,sizeof(MEMORYSTATUSEX)
invoke GlobalMemoryStatusEx, ADDR memStatus
invoke GetProcessMemoryInfo,rv(GetCurrentProcess),ADDR procMem,sizeof(PROCESS_MEMORY_COUNTERS)
print "Physically Installed Ram (KB): "
mov rax,totalMem
print ustr$(eax)
print " ",13,10
print "Memory Load: "
lea rdi,memStatus
mov eax,dword ptr (MEMORYSTATUSEX PTR [rdi]).dwMemoryLoad
print ustr$(eax)
print "%",13,10
print "Total OS Visible Ram (KB): "
lea rdi,memStatus
mov eax,dword ptr (MEMORYSTATUSEX PTR [rdi]).ullTotalPhys
mov edx,dword ptr (MEMORYSTATUSEX PTR [rdi]).ullTotalPhys+4
mov ebx,1024
div ebx
print ustr$(eax)
print " ",13,10
print "Total Available Physical Ram (KB): "
lea rdi,memStatus
mov eax,dword ptr (MEMORYSTATUSEX PTR [rdi]).ullAvailPhys
xor edx,edx
mov ebx,1024
div ebx
print ustr$(eax)
print " ",13,10
print "Page Fault Count: "
lea rdi,procMem
mov eax,dword ptr (PROCESS_MEMORY_COUNTERS PTR [rdi]).PageFaultCount
print ustr$(eax)
print " ",13,10
ret
main endp
mainCRTStartup proc FRAME
invoke main
invoke ExitProcess, eax
mainCRTStartup endp
END mainCRTStartup
In addition the updated assemble/link details at the top allow VS2010 to debug the app perfectly with devenv.exe win64_5.exe /debugexe ...
Small bug fix..
;--- Win64 console application with exception handler, uses WinInc v2+
;--- assemble: jwasm -c -win64 -Zp8 Win64_5.asm
;--- link: link /subsystem:console /Libpath:\WinInc\Lib64 Win64_5.obj
;--- UPDATE (Must ensure you have latest WinInc, PellesC, run POLIB as per details to generate Lib64 in WinInc):
;--- assemble: jwasm -c -Zi -Zd -Zf -win64 -Zp8 Win64_5.asm
;--- link: link /subsystem:console /debug /pdb:win64_5.pdb /Libpath:"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\x64" /Libpath:"c:\jwasm\wininc\lib64" /Libpath:"c:\masm32\lib" win64_5.obj
option win64:1
option casemap:none
option frame:auto
.mmx
.xmm
.nolist
.nocref
WIN32_LEAN_AND_MEAN equ 1
include ..\WinInc\Include\windows.inc
.list
.cref
include ..\WinInc\Include\shellapi.inc
includelib msvcrt.lib
externdef printf : near
externdef kbhit : near
externdef strlen : near
includelib <kernel32.lib>
includelib <gdi32.lib>
includelib <user32.lib>
includelib <shell32.lib>
PROCESS_MEMORY_COUNTERS STRUCT
dwLength DWORD ?
PageFaultCount DWORD ?
PeakWorkingSetSize dq ?
WorkingSetSize dq ?
QuotaPeakPagedPoolUsage dq ?
QuotaPagedPoolUsage dq ?
QuotaPeakNonPagedPoolUsage dq ?
QuotaNonPagedPoolUsage dq ?
PagefileUsage dq ?
PeakPagefileUsage dq ?
PROCESS_MEMORY_COUNTERS ENDS
StdOut64 proto lpszText:QWORD
dwtoa proto :DWORD, :QWORD
GetPhysicallyInstalledSystemMemory PROTO :QWORD
K32GetProcessMemoryInfo PROTO :DWORD, :DWORD, :DWORD
GetProcessMemoryInfo EQU <K32GetProcessMemoryInfo>
; -----------------------------------------------------------
; This macro replaces quoted text with a DATA section OFFSET
; and returns it in ADDR "name" format. It is used by other
; macros that handle optional quoted text as a parameter.
; -----------------------------------------------------------
reparg MACRO arg
LOCAL nustr
quot SUBSTR <arg>,1,1
IFIDN quot,<"> ;; if 1st char = "
.data
nustr db arg,0 ;; write arg to .DATA section
.code
EXITM <ADDR nustr> ;; append name to ADDR operator
ELSE
EXITM <ADDR arg> ;; else return arg
ENDIF
ENDM
print MACRO arg1:REQ,varname:VARARG ;; display zero terminated string
invoke StdOut64,reparg(arg1)
IFNB <varname>
invoke StdOut64,CStr(varname)
ENDIF
ENDM
ustr$ MACRO DDvalue ;; unsigned integer from string
LOCAL rvstring
.data
rvstring db 20 dup (0)
align 4
.code
invoke dwtoa,DDvalue,ADDR rvstring
; invoke crt__ultoa,DDvalue,ADDR rvstring,10
EXITM <OFFSET rvstring>
ENDM
.data?
memStatus MEMORYSTATUSEX <?>
procMem PROCESS_MEMORY_COUNTERS <?>
totalMem dq ?
;--- CStr(): macro function to simplify defining a string
CStr macro Text:VARARG
local szText
.const
szText db Text,0
.code
exitm <offset szText>
endm
; ------------------------------------------------
; Function return value version of the above macro
; ------------------------------------------------
rv MACRO FuncName:REQ,args:VARARG
arg equ <invoke FuncName> ;; construct invoke and function name
FOR var,<args> ;; loop through all arguments
arg CATSTR arg,<,reparg(var)> ;; replace quotes and append arg
ENDM
arg ;; write the invoke macro
EXITM <eax> ;; EAX as the return value
ENDM
.CODE
align 4
dwtoa proc dwValue:DWORD, lpBuffer:QWORD
; -------------------------------------------------------------
; convert DWORD to ascii string
; dwValue is value to be converted
; lpBuffer is the address of the receiving buffer
; EXAMPLE:
; invoke dwtoa,edx,ADDR buffer
;
; Uses: eax, ecx, edx.
; -------------------------------------------------------------
push rbx
push rsi
push rdi
mov eax, dwValue
mov rdi, [lpBuffer]
or eax,eax
jnz sign
zero:
mov word ptr [rdi],30h
ret
sign:
jns pos
mov byte ptr [rdi],'-'
neg eax
inc rdi
pos:
mov ecx, 3435973837
mov rsi, rdi
.while (eax > 0)
mov ebx,eax
mul ecx
shr edx, 3
mov eax,edx
lea edx,[edx*4+edx]
add edx,edx
sub ebx,edx
add bl,'0'
mov [rdi],bl
inc rdi
.endw
mov byte ptr [rdi], 0 ; terminate the string
; We now have all the digits, but in reverse order.
.while (rsi < rdi)
dec rdi
mov al, [rsi]
mov ah, [rdi]
mov [rdi], al
mov [rsi], ah
inc rsi
.endw
pop rdi
pop rsi
pop rbx
ret
dwtoa endp
StdOut64 proc FRAME lpszText:QWORD
LOCAL hOutPut :QWORD
LOCAL bWritten :DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut,rax
mov rsi,lpszText
invoke lstrlen,rsi
mov edi,eax
invoke WriteConsole,hOutPut,rsi,edi,ADDR bWritten,NULL
mov eax, bWritten
ret
StdOut64 endp
exchdl proc pRecord:ptr, ulframe:qword, pContext:ptr, x4:ptr
add qword ptr [r8].CONTEXT.Rip_, 1 ;1=size of "in EAX, DX" opcode
mov eax, 0 ;0=continue execution?
ret
exchdl endp
VMwareInstalled proc FRAME:exchdl
mov eax, 0564D5868h
mov ebx, 08685D465h
mov ecx, 10
mov dx, 05658h
in eax, dx
cmp ebx, 564D5868h
setz al
movzx eax,al
ret
VMwareInstalled endp
main proc FRAME uses rbx rsi rdi
local dwWritten:DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov rbx,rax
invoke VMwareInstalled
.if ( eax )
invoke StdOut64,CStr("Running under VMWare")
print " ",13,10
.else
invoke StdOut64,CStr("Not Running under VMWare")
print " ",13,10
.endif
invoke GetPhysicallyInstalledSystemMemory, ADDR totalMem
mov ecx,sizeof(MEMORYSTATUSEX)
xor eax,eax
lea rdi,memStatus
rep stosb
lea rdi,memStatus
mov dword ptr (MEMORYSTATUSEX PTR [rdi]).dwLength,sizeof(MEMORYSTATUSEX)
invoke GlobalMemoryStatusEx, ADDR memStatus
invoke GetProcessMemoryInfo,rv(GetCurrentProcess),ADDR procMem,sizeof(PROCESS_MEMORY_COUNTERS)
print "Physically Installed Ram (KB): "
mov rax,totalMem
print ustr$(eax)
print " ",13,10
print "Memory Load: "
lea rdi,memStatus
mov eax,dword ptr (MEMORYSTATUSEX PTR [rdi]).dwMemoryLoad
print ustr$(eax)
print "%",13,10
print "Total OS Visible Ram (KB): "
lea rdi,memStatus
mov rax,(MEMORYSTATUSEX PTR [rdi]).ullTotalPhys
xor rdx,rdx
mov rbx,1024
div rbx
print ustr$(eax)
print " ",13,10
print "Total Available Physical Ram (KB): "
lea rdi,memStatus
mov rax,(MEMORYSTATUSEX PTR [rdi]).ullAvailPhys
xor rdx,rdx
mov rbx,1024
div rbx
print ustr$(eax)
print " ",13,10
print "Page Fault Count: "
lea rdi,procMem
mov eax,dword ptr (PROCESS_MEMORY_COUNTERS PTR [rdi]).PageFaultCount
print ustr$(eax)
print " ",13,10
ret
main endp
mainCRTStartup proc FRAME
invoke main
invoke ExitProcess, eax
mainCRTStartup endp
END mainCRTStartup