@zoand
2017-04-12T15:55:05.000000Z
字数 2814
阅读 1461
asm
在 windows 上使用汇编, 不外乎两种方式:
在 windows 平台下, 没必要整个软件都使用汇编来编写。将某个部分 c/c++无法实现的代码或者需要更高效的代码用汇编来编写作为库函数, 链接到 c/c++ 代码里就足够了! 有一种所谓的 win32 masm 汇编形式, 只不过利用一些宏将 c 语言伪装成汇编的语法而已, 既然这样为何不用 c, 而用不伦不类的伪汇编!
你可以使用微软的 masm (宏汇编) 语言, 也可以使用开源免费的 nasm语言。在这里我将它们定性为语言,虽然它们都是 x86/x64平台上的汇编语言编译器,但语法上有些出入,因此区分为不同的语言更为合适。
若使用 masm 语法, 需要使用 ml.exe (32位) 或者 ml64.exe (64位) 进行编译, 它们都是集成在 visual studio 软件里, 在 vc 的 bin 及 bin\amd64 目录里, 例如: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin 以及 C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64。
下面是一个用于 masm 的简单示例模版:
;;;; 这是一个 masm 示例代码 libm.asm;; (1) x86 下编译: ml /c libm.asm;; (2) x64 下编译: ml64 /c /D_M_AMD64 libm.asm;;IFDEF _M_AMD64 ; 假如定义了 _M_AMD64(x64);; empty for x64 ML ; x64 下不需要ELSE.586p ; x86 下需要定义 target 体系ENDIF; ###### 下面导出函数 #######IFDEF _M_AMD64;; 在 x64 下导出的函数PUBLIC ReadTsc ; 在 x64 下无须定义参数ELSE;; 在 x86 下导出的函数PUBLIC _ReadTsc@0 ; 在 x86 下符号前加 "_" 前缀,后缀:"@+参数字节"ENDIF;; ###### 定义代码段 #######_TEXT SEGMENT;---------------------------------------------; ULONG64 ReadTsc();; 参数:; 无; 返回:; 64 位的 TSC 值;---------------------------------------------ReadTsc:_ReadTsc@0:rdtscIFDEF _M_AMD64;;;; x64 版本;;shl rdx, 32or rax, rdxENDIFret
假设源文件名为 libm.asm
在 x64 下使用 ml64.exe /c /D_M_AMD64 libm.asm 进行编译
/c 命令选项指示只编译并不链接,
/D 命令选项是定义一个宏。编译后生成 libm.obj 文件,
然后在 vc 里设置 project 属性。
如果 c/c++ 项目, 同时支持 win32 与 x64 平台, 那么每个平台都需要设置, 这样才能被链接到 c/c++ 代码里 (这里的汇编代码将被静态链接到 c/c++ 里)。
在 c/c++ 代码引用 ReadTsc() 这个函数前, 需要作出声明:
#ifdef __cplusplusextern "C" {#endifextern ULONG64 __stdcall ReadTsc(); // 声明引用 libm 库的 ReadTsc 函数#ifdef __cplusplus}#endif
最好是将 libm 库所有导出的函数声明,单独放在一个头文件里。在 c/c++ 代码放 include 这个头文件即可。
使用 nasm 更简些, 下面以 QueryCpuidInfo 函数实现为例:
;;;; 这是一个 nasm 示例代码 libs.asm;; (1) x86 下编译: nasm -fwin32 libs.asm;; (2) x64 下编译: nasm -fwin64 libs.asm;;%if __BITS__ == 64;; #### 导出 x64 函数global QueryCpuidInfo%else;; #### 导出 x86 函数global _QueryCpuidInfo@12 ; x86 下符号前加 "_" 前缀, 后缀: "@ + 参数字节数"%endifSECTION .text align=8 execute;--------------------------------------------------------------------------; VOID QueryCpuidInfo(ULONG Leaf, ULONG SubLeaf, PCPUID_BLOCK CpuidBlock);; 参数:; Leaf - CPUID 编号; SubLeaf - CPUID 辅助编号; CpuidBlock - 接收 cpuid info;--------------------------------------------------------------------------QueryCpuidInfo:_QueryCpuidInfo@12:%if __BITS__ == 64;;;; x64 版本;;mov eax, ecx ; leafmov ecx, edx ; sub-leafcpuidmov [r8], eaxmov [r8+4], ecxmov [r8+8], edxmov [r8+12], ebxret%else;;;; win32 版本;;push esimov eax, [esp+8] ; leafmov ecx, [esp+12] ; sub-leafmov esi, [esp+16] ; CpuidBlockcpuidmov [esi], eaxmov [esi+4], ecxmov [esi+8], edxmov [esi+12], ebxpop esiret 12%endif
假设源文件名为 libs.asm, 使用下面的命令进行编译:
win32:
nasm -fwin32 libs.asm
amd64:nasm -fwin64 libs.asm
同样需要配置 c/c++ 项目设置, 才能链接到汇编代码,方法和 masm 是一样的。
@邓志:windows 上使用汇编