JWASM x64语法

来源:互联网 发布:ruby编程语言 pdf 编辑:程序博客网 时间:2024/06/05 19:03

写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:1option frame:autooption casemap:none.nolist.nocref.NOLISTMACROinclude ..\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.crefMB_OK equ 0NULL equ 0TRUE equ 1HINSTANCE typedef QWORDLPSTR     typedef QWORDGetModuleHandleW proto :qwordGetCommandLineW  protoMessageBoxW      proto :qword, :qword, :qword, :qwordExitProcess     proto :qwordGetModuleHandle equ <GetModuleHandleW>GetCommandLine  equ <GetCommandLineW>MessageBox      equ <MessageBoxW>.dataUCCSTR  szMsgTitle,"x64",0UCCSTR  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 endpend _start

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

option casemap:none.nolist.nocref.NOLISTMACROinclude macros.inc.list.crefMB_OK equ 0NULL equ 0HINSTANCE typedef QWORDLPSTR     typedef QWORDGetModuleHandleW proto :qwordGetCommandLineW  protoMessageBoxW      proto :qword, :qword, :qword, :qwordExitProcess     proto :qwordGetModuleHandle equ <GetModuleHandleW>GetCommandLine  equ <GetCommandLineW>MessageBox      equ <MessageBoxW>.dataUCCSTR  szMsgTitle,"x64",0UCCSTR  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 endpend

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.dlllink.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的帮助文件吧