在 Visual C++ 中使用汇编例程






3.04/5 (29投票s)
一篇关于混合语言编程的文章。
引言
混合语言编程允许您将 Visual C++ 的独特优势与您的汇编语言例程相结合。 在某些情况下,您希望使用内联汇编来实现某些目标,例如提高速度、减少内存需求和提高效率。 然而,内联汇编程序不如 MASM 强大,它不支持宏或指令。 本文介绍了如何编写可以从 Visual C++ 模块调用的汇编例程。 但在继续之前,您需要熟悉两个术语
命名约定
它指定编译器如何在将名称放入.OBJ 文件时更改符号名称。 例如,一个 C 函数 “void func(void)
” 在.OBJ 文件中被放入为 “_func@0”,而在 C++ 中,它在.OBJ 文件中被修饰为 “?func@@YAXXZ”。
调用约定
它决定了一种语言如何实现对过程的调用以及过程如何返回到调用者。 在C 调用约定 (__cdecl
) 中,参数从右到左被压入堆栈,被调用的过程返回而不从堆栈中删除参数。 调用者有责任在调用后清理堆栈。
在标准调用约定 (__stdcall
) 中,参数从右到左被压入堆栈,如果被调用的过程不接受可变数量的参数,它会清理堆栈。 在快速调用约定 (__fastcall
) 中,前两个参数分别加载到 ecx
, edx
寄存器中。 其他参数从右到左被压入堆栈。 相同的函数负责清理堆栈。
这是一个包含一些调用和命名约定的示例的摘要表
语言, 调用约定 | .OBJ 文件中的名称 | void func (void) |
---|---|---|
C, cdecl |
_name | _func |
C, __stdcall |
_name@nn | _func@0 |
C, __fastcall |
@name@nn | @func@0 |
C++, cdecl |
?name@@decoration | ?func@@YAXXZ |
C++, __stdcall |
?name@@decoration | ?func@@YGXXZ |
C++, __fastcall |
?name@@decoration | ?func@@YIXXZ |
如何在 Visual C++ 模块中使用 MASM 例程
以下汇编函数 (Addup
) 接受三个 DWORD
(32 位)值作为参数,然后返回它们的总和。 无论何时编写例程,请确保不要将其选择为入口点(即 END Addup)。
;============================================
; Addup.asm file
;============================================
.486
.model flat, stdcall
option casemap :none
.code
;--------------------------------------------
Addup PROC, Arg1:DWORD, Arg2:DWORD, Arg3:DWORD
mov eax, Arg1
add eax, Arg2
add eax, Arg3
ret
Addup ENDP
;----------------------------------------------
END
;----------------------------------------------
; To compile this file use:
; ml.exe Addup.asm /c /coff
- 现在将生成的.obj 文件 (Addup.obj) 复制到您的 VC++ 应用程序的项目文件夹中。
- 将以下原型添加到将使用此例程的 C++ 源文件 (.cpp) 中
extern “C” int __stdcall Addup (int, int, int);
或者您可以将此原型放入新的头文件中,然后将其添加到您的项目中。
extern “C”
指示 C 命名约定,因为您处于 C++ 环境中。 当您指定STDCALL
时,MASM 使用 C 命名约定。 最后,__stdcall
指示该例程使用标准调用约定。 - 现在将.OBJ 文件名 (Addup.obj) 添加到您的链接器命令窗口中。 或者您可以手动将文件添加到您的项目中。 否则,您将收到“unresolved external”错误。
- 现在你应该可以正常编译项目而不会出现任何错误。