JWASM x64语法

写32位汇编时,JWASM基本与MASM相同,写64位汇编时,JWASM与MASM区别较大,因JWASM支持高级语法,如.if,.while,invoke等等,且支持自动控制堆栈(和写32位汇编一样)。

我们依旧以经典的HelloWorld来做为例子


注:关于Win64调用约定详细参考Win64调用约定

        简单说一下Win64的调用约定吧,即函数的前4个参数通过寄存器传递,分别为rcx, rdx, r8, r9,其余参数通过堆栈(即push)传递。但64位下堆栈由Caller(调用者)分配,所以调用函数前都要先预留堆栈空间,至少要【 8 * 参数个数】个byte,MSDN堆栈分配

        Win64与Win32数据类型区别:int与long依旧为32 bits(Linux64下long类型为64 bits),Pointer为64 bits,用64 bits类型用int64或longlong,MSDN说这是为了节约内存。详细见MSDN标量类型


先看一下Jwasm_HelloWorld.asm

option win64:1
option frame:auto
option casemap:none

.nolist
.nocref
.NOLISTMACRO
include ..\macros.inc   ;;此文件为MASM SDK中的macros.inc,里面的UCCSTR宏,定义Unicode字符串
;include windows.inc    ;;这些inc文件全来自MASM SDK,不过里面的一些定义被我手动修改了
                        ;;如HINSTANCE定义,改为qword了,为了代码可直接使用,
                        ;;我将用到的定义写出来了
;include kernel32.inc
;include user32.inc

;includelib kernel32.lib
;includelib kernel32.lib
.list
.cref
MB_OK equ 0
NULL equ 0
TRUE equ 1
HINSTANCE typedef QWORD
LPSTR     typedef QWORD

GetModuleHandleW proto :qword
GetCommandLineW  proto
MessageBoxW      proto :qword, :qword, :qword, :qword
ExitProcess     proto :qword

GetModuleHandle equ <GetModuleHandleW>
GetCommandLine  equ <GetCommandLineW>
MessageBox      equ <MessageBoxW>


.data
UCCSTR  szMsgTitle,"x64",0
UCCSTR  szMsgContent, "Hello World",0


.code
_start proc frame
    local hInstance:HINSTANCE, lpCommandLine:LPSTR  ;;为了测试语法,所以将这2个变量保存在堆栈上了

    invoke GetModuleHandle, NULL
    mov hInstance, rax
    invoke GetCommandLine
    mov lpCommandLine, rax

    invoke MessageBox, NULL, addr szMsgContent, addr szMsgTitle, MB_OK
    invoke ExitProcess, NULL
    ret
_start endp

@Test proc frame numb1:qword, numb2:qword, numb3:qword  ;;此函数为JWASM语法示范
    mov rax, TRUE
    ret
@Test endp

end _start

下面是用MASM x64(即ML64)写Masm_HelloWorld.asm

option casemap:none

.nolist
.nocref
.NOLISTMACRO
include macros.inc
.list
.cref
MB_OK equ 0
NULL equ 0
HINSTANCE typedef QWORD
LPSTR     typedef QWORD

GetModuleHandleW proto :qword
GetCommandLineW  proto
MessageBoxW      proto :qword, :qword, :qword, :qword
ExitProcess     proto :qword

GetModuleHandle equ <GetModuleHandleW>
GetCommandLine  equ <GetCommandLineW>
MessageBox      equ <MessageBoxW>


.data
UCCSTR  szMsgTitle,"x64",0
UCCSTR  szMsgContent, "Hello World",0


.code
_start proc FRAME
    local hInstance:HINSTANCE, lpCommandLine:LPSTR

    push rbp
    .pushreg rbp
    mov rbp, rsp
    .setframe rbp, 0
    sub rsp, 16            ;分配堆栈,2个64 bits变量,即hInstance, lpCommandLine
    .allocstack 16
    .endprolog

    sub rsp, 1 * 8         ;分配堆栈,1个参数
    mov rcx, NULL
    call GetModuleHandle   ;invoke GetModuleHandle, NULL
    add rsp, 1 * 8         ;收回堆栈空间
    mov hInstance, rax
    sub rsp, 0             ;无参数,这个指令只是为说明堆栈分配,实际中可以省略
    call GetCommandLine    ;invoke GetCommandLine
    add rsp, 0             ;收回堆栈空间
    mov lpCommandLine, rax

    sub rsp, 4 * 8         ;分配堆栈,MessageBox函数有4个参数
    mov rcx, NULL
    lea rdx, szMsgContent
    lea r8, szMsgTitle
    mov r9, MB_OK
    call MessageBox        ;invoke MessageBox, NULL, addr lpMsgContent, addr lpMsgTitle, MB_OK
    add rsp, 5 * 8         ;收回堆栈

    sub rsp, 1 * 8         ;分配堆栈
    mov rcx, NULL
    call ExitProcess       ;invoke ExitProcess, NULL
    add rsp, 1 * 8         ;收回堆栈
    add rsp, 16
    pop rbp
    ret    
_start endp

_start_Op proc FRAME      ;;此函数为_start函数优化后的样子,
    local hInstance:HINSTANCE, lpCommandLine:LPSTR

    push rbp
    .pushreg rbp
    mov rbp, rsp
    .setframe rbp, 0
    sub rsp, 16
    .allocstack 16
    .endprolog

    sub rsp, 4 * 8          ;;只在开始处为【call函数】时分配一次堆栈空间
    mov rcx, NULL
    call GetModuleHandle    ;invoke GetModuleHandle, NULL
    mov hInstance, rax

    call GetCommandLine     ;invoke GetCommandLine
    mov lpCommandLine, rax

    mov rcx, NULL
    lea rdx, szMsgContent
    lea r8, szMsgTitle
    mov r9, MB_OK
    call MessageBox         ;invoke MessageBoxW, NULL, addr lpMsgContent, addr lpMsgTitle, MB_OK

    mov rcx, NULL
    call ExitProcess        ;invoke ExitProcess, NULL

    add rsp, 4 * 8          ;;收回为【call函数】时分配的空间
    add rsp, 16
    pop rbp
    ret
_start_Op endp

end

Masm_HelloWorld.asm可用ML64或JWASM编译,而Jwasm_HelloWorld.asm只能用JWASM编译,因里面用到高级语法与JWASM特有的指令(option win64, option frame)


Ml64的编译命令:

ml64.exe /c /WX /Zi /Fl"Masm_HelloWorld.lst"/Zd  "Masm_HelloWorld.asm"
JWASM编译命令:

jwasm.exe -Fl"Masm_HelloWorld.lst"  -c -win64 -Zi -Zd "Masm_HelloWorld.asm"
jwasm.exe -Fl"Jwasm_HelloWorld.lst" -c -win64 -Zi -Zd "Jwasm_HelloWorld.asm"
JWASM的-c必须存在,因JWASM不支持调用Link程序,-c只是为兼容MASM-Fl同MASM,可以看出,编译命令几乎都没变,只是将“/”转为“-”


以下是链接命令,一种是用GoLink链接,一种是微软的Link链接

GoLink.exe /entry _Start /debug dbg /mix /fo HelloWorld.exe HelloWorld.obj kernel32.dll user32.dll
link.exe HelloWorld.obj /entry:_Start /debug /machine:x64 /out:HelloWorld.exe /subsystem:windows /defaultlib:kernel32.lib user32.lib

编译完成后,查看List清单文件,Jwasm_HelloWorld.list中的_start函数几乎与Masm_HelloWorld.list的相同,唯一不同在于sub rsp,Number中的Number,因Masm_HelloWorld.asm中的堆栈分配为人工,为了示范Win64堆栈分配我只是分配了刚好的空间,没有富余。而Jwasm_HelloWorld.asm中,因使用了option win64 指令,所以Jwasm自动帮我们分配了4*8 byte堆栈空间。

下图为Jwasm_HelloWorld.list中_start函数内容

JWASM_HelloWold_start.list

下图为Jwasm_HelloWorld.list中@Test函数内容

JWASM_HelloWold_@Test

Masm_HelloWorld.list就不再贴图了,其指令与Masm_HelloWorld.asm相同



option win64:number 用为允许Jwasm自动分配堆栈的方法和是否自动保存寄存器数据(即函数的前4个参数)至堆栈上。

当number的第1 bit为0时(option win64:2),在函数中,Jwasm不会自动保存寄存器中的参数至堆栈上

当number的第1 bit为1时(option win64:1),JWASM会自动将寄存器中的参数保存至堆栈上,如Jwasm_HelloWorld.list中@Test函数

当number的第2 bit为0时(option win64:1),遇到invoke时,每次都会自动分配堆栈,且最少分配4 * 8 byte(即rcx, rdx, r8, r9),如Jwasm_HelloWorld.list中_start函数中每次遇到invoke指令都会分配4 * 8byte的空间,即sub rsp, 32

当number的第2 bit为1时(option win64:3),只在函数入口处分配一次堆栈(8 * 此函数内invoke参数的最大个数),如MASM_HellowWorld.asm中_start_Op函数一样

OPTION FRAME:<AUTO | NOAUTO>  默认为noauto。此指令影响64位汇编,

当此指令设置为auto且函数声明中带有frame指令时(_start proc frame),JWASM自动生成ML64的Prolog指令(.pushreg,.setframe,.endprolog等等),

当此指令设置为noauto时,需要手动写prolog代码, 如Jwasm_HelloWold.list中_start函数


JWASM中新增的指令还有很多,如option FieldAlign,option elg,option mz,option DLLImport,option codeview等等,但在HelloWold中没有用到,所以有时间了再翻译下JWASM的帮助文件吧


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值