[关闭]
@zoand 2017-04-12T15:55:05.000000Z 字数 2814 阅读 1364

windows上使用汇编

asm


在 windows 上使用汇编, 不外乎两种方式:

在 windows 平台下, 没必要整个软件都使用汇编来编写。将某个部分 c/c++无法实现的代码或者需要更高效的代码用汇编来编写作为库函数, 链接到 c/c++ 代码里就足够了! 有一种所谓的 win32 masm 汇编形式, 只不过利用一些宏将 c 语言伪装成汇编的语法而已, 既然这样为何不用 c, 而用不伦不类的伪汇编!

你可以使用微软的 masm (宏汇编) 语言, 也可以使用开源免费的 nasm语言。在这里我将它们定性为语言,虽然它们都是 x86/x64平台上的汇编语言编译器,但语法上有些出入,因此区分为不同的语言更为合适。

1. 使用 masm

若使用 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 的简单示例模版:

  1. ;;
  2. ;; 这是一个 masm 示例代码 libm.asm
  3. ;; (1) x86 下编译: ml /c libm.asm
  4. ;; (2) x64 下编译: ml64 /c /D_M_AMD64 libm.asm
  5. ;;
  6. IFDEF _M_AMD64 ; 假如定义了 _M_AMD64x64
  7. ;; empty for x64 ML ; x64 下不需要
  8. ELSE
  9. .586p ; x86 下需要定义 target 体系
  10. ENDIF
  11. ; ###### 下面导出函数 #######
  12. IFDEF _M_AMD64
  13. ;; x64 下导出的函数
  14. PUBLIC ReadTsc ; x64 下无须定义参数
  15. ELSE
  16. ;; x86 下导出的函数
  17. PUBLIC _ReadTsc@0 ; x86 下符号前加 "_" 前缀,后缀:"@+参数字节"
  18. ENDIF
  19. ;; ###### 定义代码段 #######
  20. _TEXT SEGMENT
  21. ;---------------------------------------------
  22. ; ULONG64 ReadTsc();
  23. ; 参数:
  24. ;
  25. ; 返回:
  26. ; 64 位的 TSC
  27. ;---------------------------------------------
  28. ReadTsc:
  29. _ReadTsc@0:
  30. rdtsc
  31. IFDEF _M_AMD64
  32. ;;
  33. ;; x64 版本
  34. ;;
  35. shl rdx, 32
  36. or rax, rdx
  37. ENDIF
  38. ret

假设源文件名为 libm.asm

如果 c/c++ 项目, 同时支持 win32 与 x64 平台, 那么每个平台都需要设置, 这样才能被链接到 c/c++ 代码里 (这里的汇编代码将被静态链接到 c/c++ 里)。
在 c/c++ 代码引用 ReadTsc() 这个函数前, 需要作出声明:

  1. #ifdef __cplusplus
  2. extern "C" {
  3. #endif
  4. extern ULONG64 __stdcall ReadTsc(); // 声明引用 libm 库的 ReadTsc 函数
  5. #ifdef __cplusplus
  6. }
  7. #endif

最好是将 libm 库所有导出的函数声明,单独放在一个头文件里。在 c/c++ 代码放 include 这个头文件即可。

2. 使用 nasm

使用 nasm 更简些, 下面以 QueryCpuidInfo 函数实现为例:

  1. ;;
  2. ;; 这是一个 nasm 示例代码 libs.asm
  3. ;; (1) x86 下编译: nasm -fwin32 libs.asm
  4. ;; (2) x64 下编译: nasm -fwin64 libs.asm
  5. ;;
  6. %if __BITS__ == 64
  7. ;; #### 导出 x64 函数
  8. global QueryCpuidInfo
  9. %else
  10. ;; #### 导出 x86 函数
  11. global _QueryCpuidInfo@12 ; x86 下符号前加 "_" 前缀, 后缀: "@ + 参数字节数"
  12. %endif
  13. SECTION .text align=8 execute
  14. ;--------------------------------------------------------------------------
  15. ; VOID QueryCpuidInfo(ULONG Leaf, ULONG SubLeaf, PCPUID_BLOCK CpuidBlock)
  16. ;
  17. ; 参数:
  18. ; Leaf - CPUID 编号
  19. ; SubLeaf - CPUID 辅助编号
  20. ; CpuidBlock - 接收 cpuid info
  21. ;--------------------------------------------------------------------------
  22. QueryCpuidInfo:
  23. _QueryCpuidInfo@12:
  24. %if __BITS__ == 64
  25. ;;
  26. ;; x64 版本
  27. ;;
  28. mov eax, ecx ; leaf
  29. mov ecx, edx ; sub-leaf
  30. cpuid
  31. mov [r8], eax
  32. mov [r8+4], ecx
  33. mov [r8+8], edx
  34. mov [r8+12], ebx
  35. ret
  36. %else
  37. ;;
  38. ;; win32 版本
  39. ;;
  40. push esi
  41. mov eax, [esp+8] ; leaf
  42. mov ecx, [esp+12] ; sub-leaf
  43. mov esi, [esp+16] ; CpuidBlock
  44. cpuid
  45. mov [esi], eax
  46. mov [esi+4], ecx
  47. mov [esi+8], edx
  48. mov [esi+12], ebx
  49. pop esi
  50. ret 12
  51. %endif

假设源文件名为 libs.asm, 使用下面的命令进行编译:

win32: nasm -fwin32 libs.asm
amd64: nasm -fwin64 libs.asm

同样需要配置 c/c++ 项目设置, 才能链接到汇编代码,方法和 masm 是一样的。

3. 资料

@邓志:windows 上使用汇编

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注