I was adapting the Win32_5.asm of the Samples folder for 64-bit, which makes an .exe using the BIN output format.
Although, in the end I managed to do it using raw assembly language, there are a few shortcomings in the way UASM deals with the 64-bit case, namely:
1) Prototypes require a Language Specifier. If I enter FASTCALL it assumes it is 32-bit FASTCALL.
2) Default Prologues and Epilogues do not exist.
3) LOCAL is not recognized although does not produce error.
4) INVOKES work as if 32-bit FASTCALL was in force.
Please have a look at the comments in the source for further clarification.
Updated to allow importing from 2 DLLs and use the MessageBoxA as well. Required a few fixes in the macros.
Hi,
Please try the following:
www.terraspace.co.uk/uasm242.zip (http://www.terraspace.co.uk/uasm242.zip)
BIN output now supports use of OPTION stackbase and win64. When this is used the assumption then is that the language type and ABIs conform to win64 and as such prologue/default langtype/locals should all work as expected for a 64bit windows app.
; uasm64 -bin -Fo bin64.exe bin64.asm
.x64
option casemap:none
option stackbase:rbp
option win64:7
.nolist
include winnt64.inc ; Modification for 64-bit of winnt.inc from Sample folder of UASM.
.list
STD_OUTPUT_HANDLE equ -11
HANDLE typedef ptr
HWND typedef ptr
NULL equ 0
IMAGEBASE equ 140000000h
_IMAGE equ 0
PEHDR segment dword FLAT
;--- define the DOS "MZ" header
ORG _IMAGE
IMAGE_DOS_HEADER <"ZM", 80h, 1, 0,4,0,-1,0,200h,0,0,0,0,0,<0>,0,0,<0>,IMAGEREL PEHdr>
db 0Eh ;push cs
db 1Fh ;pop ds
db 0BAh,0Eh,0 ;mov dx,text
db 0B4h,09h ;mov ah,9
db 0CDh,21h ;int 21h
db 0B8h,01h,4Ch;mov ax,4c01h
db 0CDh,21h ;int 21h
db "This program cannot be run in DOS mode",13,10,'$'
ORG _IMAGE+80h
;--- define the Win32 "PE" header
PEHdr label byte
db "PE",0,0
IMAGE_FILE_HEADER <IMAGE_FILE_MACHINE_AMD64, num_sections, 0, 0, 0, sizeof IMAGE_OPTIONAL_HEADER64,\
IMAGE_FILE_RELOCS_STRIPPED or IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_LARGE_ADDRESS_AWARE or IMAGE_FILE_LOCAL_SYMS_STRIPPED>
IMAGE_OPTIONAL_HEADER64 { 20Bh, ;magic
0Eh,0Ah, ;linker major, minor
1000h,1000h,0, ;sizeof code, initialized data, uninitialized data
IMAGEREL startapp, ;entry point
IMAGEREL start_text, ;baseof code
IMAGEBASE, ;imagebase
1000h,200h, ;section alignment, file alignment
6,0, ;OS major, minor
0,0, ;Image major, minor
6,0, ;Subsys major, minor
0, ;win32 version
3000h, ;sizeof image
1000h, ;sizeof header
0, ;checksum
IMAGE_SUBSYSTEM_WINDOWS_CUI,
0, ;dll characteristics
100000h,1000h,;stack res,com
100000h,1000h,;heap res, com
0, ;loader flags
16, ;number of directories
< <0,0>,\ ;0 exports
< IMAGEREL start_idata, SECTIONREL endof_idata >,\ ;1 imports
<0,0>,<0,0>,\ ;2 resource, 3 exception
<>,<>,<>,<>,\ ;4 security, 5 baserelocs, 6 debug, 7 architecture
<>,<>,<>,<>,\ ;8 globalptr, 9 tls, 10 load_config, 11 bound_import
<>,<>,<>,<> >} ;12 iat, 13 delay_import, 14 com descriptor, 15 reserved
;--- define the section table
sectiontable label byte
IMAGE_SECTION_HEADER <".text", <sizeof_text>, IMAGEREL start_text, sizeof_text,\
200h, 0, 0, 0, 0, 060000020h >
IMAGE_SECTION_HEADER <".rdata", <SECTIONREL endof_idata+ sizeof_const>, IMAGEREL start_rdata, SECTIONREL endof_idata+ sizeof_const,\
400h, 0, 0, 0, 0, 040000040h >
num_sections equ ( $ - sectiontable ) / sizeof IMAGE_SECTION_HEADER
ORG _IMAGE+200h ;forces physical size of header to 200h and sets VA to 400200h
PEHDR ends
ALIGN1 segment dword public FLAT 'DATA'
ORG 0E00h ; change pc to RVA 1000h
ALIGN1 ends
_TEXT segment dword public FLAT 'CODE'
_TEXT ends
ALIGN2 segment dword public FLAT 'DATA'
ORG 0E00h ; change pc to RVA 2000h
ALIGN2 ends
_IDATA segment dword public FLAT 'DATA'
start_rdata label byte
start_idata label byte
;--- import descriptors go here
_IDATA ends
_IDATA$1 segment dword public FLAT 'DATA'
IMAGE_IMPORT_DESCRIPTOR <<0>,0,0,0,0>
;--- ILT entries go here
_IDATA$1 ends
_IDATA$2 segment dword public FLAT 'DATA'
dq 0 ;--- end of last ILT
;--- IAT entries go here
_IDATA$2 ends
_IDATA$3 segment dword public FLAT 'DATA'
dd 0 ;--- end of last IAT
;--- import name strings go here
_IDATA$3 ends
_IDATA$4 segment dword public FLAT 'DATA'
endof_idata equ $
_IDATA$4 ends
CONST segment dword public FLAT 'DATA'
start_const label byte
CONST ends
DefineImpDll macro name
_IDATA segment
IMAGE_IMPORT_DESCRIPTOR <<IMAGEREL name&ILT>,0,0,IMAGEREL name, IMAGEREL name&IAT>
_IDATA ends
_IDATA$1 segment
ifdef ImportDefined
dq 0 ;terminate previous ILT
endif
name&ILT label dword
_IDATA$1 ends
_IDATA$2 segment
ifdef ImportDefined
dq 0 ;terminate previous IAT
endif
name&IAT label dword
_IDATA$2 ends
_IDATA$3 segment
name db @CatStr(!",name, !"),0
align 4
_IDATA$3 ends
ImportDefined equ 1
endm
DefineImport macro name
_IDATA$1 segment
dq IMAGEREL n&name
_IDATA$1 ends
_IDATA$2 segment
lp&name typedef ptr pr&name
name lp&name IMAGEREL n&name
_IDATA$2 ends
_IDATA$3 segment
n&name dw 0
db @CatStr(!",name, !"),0
align 4
_IDATA$3 ends
endm
; When the FASTCALL specifier is not there it reports error LANGUAGE specifier is not there.
; If FASTCALL is there, as is now, it assumes 32-bit FASTCALL not the 64-bit ABI
; I placed FASTCALL just to make it assemble because it will not be possible to use INVOKE correctly.
prWriteConsoleA typedef proto :HANDLE, :ptr, :dword, :ptr, :ptr
prGetStdHandle typedef proto :dword
prExitProcess typedef proto :dword
DefineImpDll kernel32
DefineImport ExitProcess
DefineImport WriteConsoleA
DefineImport GetStdHandle
;if 0 ;if further dlls are to be imported
prMessageBoxA typedef proto :HWND, :ptr, :ptr, :dword
DefineImpDll user32
DefineImport MessageBoxA
;endif
CONST segment
string1 db 13,10,"hello, Console World.",13,10
string2 db "hello, Windows World.",0
caption db "Hello",0
sizeof_const equ $ - start_const
CONST ends
_TEXT segment
start_text label near
;--- start of program
; ***Procedures build without PROLOGUEs or EPILOGUEs***
main proc
LOCAL dwWritten:dword
LOCAL hConsole:HANDLE
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov hConsole, rax
invoke WriteConsoleA, hConsole, addr string1, sizeof string1, addr dwWritten, NULL
ret
main endp
;--- entry
startapp proc
call main
mov rcx,0
lea rdx, string2
lea r8, caption
mov r9, 0
sub rsp, 20h
call MessageBoxA
add rsp 20h
xor rcx, rcx
call ExitProcess
startapp endp
sizeof_text equ $ - start_text
ORG 200h ;align size of _TEXT to next 512 byte boundary
_TEXT ends
end
It works! :t