上次谈的64位的调用约定,然后谈谈UASM这汇编语言这一块。
uasm是一个改编过的汇编语言,来自watcom的汇编语言,翻版过来的。很多新功能。是个教学语言。
那本《x64汇编语言:从新手到AVX专家》这本书有介绍下载的地方,整合了一个独立的编辑器,有编程的三种方式和语言。
内含新手汇编。nasm,,uasm,gnuas,fasm四种编译语言,有些没有被补充进来。
对与64位的汇编编程,这些汇编语言都可以实现。每一段时间都会有更新。可以手动升级。
另外,这些汇编编译器都有源代码,可以修补和更正,一般是指令上的增补和增加命令行参数。
uasm的前身是jasm,来源于watcom c这个程序包。32位的版本是免费的,有64位的版本并没有公开。
;--- Win32/64 console application, uses WinInc v2+. ;--- It can be used to generate both Win32 and Win64 binaries: ;--- 32bit: ;--- uwasm64 -coff -IInc WinXX_1.asm ;--- link /subsystem:console /Libpath:\WinInc\Lib WinXX_1.obj ;--- 64bit: ;--- uwasm64 -win64 -Zp8 -I\WinInc\Include WinXX_1.asm ;--- link /subsystem:console /Libpath:\WinInc\Lib64 WinXX_1.obj ; 注意: 在64位编译器中,当参数高于等于5个参数以后,那地址会有转换问题 if (type near) eq 0ff02h ;no -win64 switch? .386 .model flat, stdcall option casemap:none FRAME equ <> rax equ <eax> rbx equ <ebx> rcx equ <ecx> rdx equ <edx> rsp equ <esp> rbp equ <ebp> rsi equ <esi> rdi equ <edi> .list .cref else .X64 .MODEL FLAT,FASTCALL option language:fastcall option win64:1 ;enable autosaving of register params to shadow space option frame:auto .nolist .nocref endif WIN32_LEAN_AND_MEAN equ 1 include windows.inc include kernel32.inc ; 从masm 中复制过来的汇编头 include msvcrt.inc ; 从masm 中复制过来的汇编头 ; includelib <kernel32.lib> ; 这个用 golink 可以链接动态DLL链接库 lstrlen proto :dword GetStdHandle proto :dword WriteConsole proto :dword,:dword,:dword,:dword,:dword ExitProcess proto :dword ;--- CStr(): 宏函数简单定义为一个字符串 ;CStr macro Text:VARARG ;local szText ; .const ;szText db Text,0 ; .code ; exitm <offset szText> ;endm .CODE align 32 main proc FRAME uses r9 r8 rcx rdx rsi rdi local dwWritten:DWORD ; 这个值没有为 NULL invoke GetStdHandle,STD_OUTPUT_HANDLE mov rbx,rax lea ecx, CStr("世界你好!",13,10) invoke lstrlen,ecx mov edi, eax invoke WriteConsole, ebx, esi, edi, addr dwWritten, 0 ; 转换为 addr 地址模式,第4-6个参数地址未识别 ret main endp mainCRTStartup proc FRAME or rbx,rbx invoke main invoke ExitProcess, eax mainCRTStartup endp END mainCRTStartup
说实在的,这个程序并没有错,是一个windows的程序64位实例。
说起来是参数问题。这个伪指令 invoke 是一个宏汇编。进入函数的方式不同,很多人会认为程序有问题,只是说,invoke并不适合64位编程。
当程序压入参数 addr dwWritten时,这里的指令在机器指令伪码中表示的是 lea ss:[dwWritten],dwWritten这个值是一个堆栈间接指针,没有赋值。
在这个函数中还有同步函数,所以这个值要填上才对。lea ss:[xxxxxx]正是传址的指令。所以识别在windows中有错误。ss是堆栈寄存器,使用其它段就没太多问题。
也就是uasm编译程序中,那个指令在64位中判断有问题。
这是调试软件跟踪的指令图,那个R9被 lea r9d,qword ptr ss[rbp-4],这个指令执行后,数值是一个堆栈数,那椎栈数在函数中是一个局部变量dwWritten。
实际上使用32位编程之后,程序运行是正常的。