目录
频道首页
内联汇编(二)——内联汇编之64位程序
收藏
0
YUNZAI 最近修改于 2023-05-11 15:25:31

一、背景

内联汇编是指在 C/C++ 代码中嵌入的汇编代码,与全部是汇编的汇编源文件不同,它们被嵌入到 C/C++ 的大环境中。内联汇编方式两个作用,一是程序的某些关键代码直接用汇编语言编写,可提高代码的执行效率;二是有些操作无法通过高级语言实现,或者实现起来很困难,必须借助汇编语言达到目的。

32 位程序和 64 位程序下使用内联汇编的方式,有很大的差别。现在,我们对此分别进行介绍。本篇文章主要介绍的是在 64 位程序中使用内联汇编。

二、VS2013中添加并编译 .asm 文件步骤

在 64 位程序中,已经不能使用关键字 __asm 来添加汇编代码,而应把汇编代码全部写在 .asm 文件中,然后,再将 .asm 包含到项目中编译链接。现在,我们就先来讲解如何使用 VS2013 添加并编译 .asm 文件的步骤。

注意,以下演示实现从 x86 模式,即 Win32 模式下开始,如果从 x64 模式开始,在设置 .asm 文件的“自定义生成工具”的时候会卡死或者无反应。从 Win32 模式开始设置后,再新建 x64 模式,并从 Win32 模式复制设置,这样就可以成功对 .asm 文件设置“自定义生成工具”。

  • 首先,我们在本地上新建一个 .asm 格式的文件 “myasm.asm”之后,右击项目工程并选择“添加” --> “现有项”,然后选择我们新创建的“myasm.asm”文件,添加到工程中:

1.jpg

  • 然后,我们选中“myasm.asm”文件,并右击选择“属性”:

2.jpg

  • 在“myasm.asm属性页”中,设置 从生成中排除 为“否”,设置 项类型 为“自定义生成工具”,然后,点击“应用”。这时,在窗口左侧就会生成“自定义生成工具”的扩展栏。如果是从 x64 模式下设置的,在一步,会没有反应或者卡死。所以,一定要从 Win32 模式开始,再创建 x64 模式,并把 Win32 的设置复制到 x64 模式中,便可以解决这个问题。

3.jpg

  • 接着,我们开始新建 x64 模式,因为我们要开发的是 64 位程序。我们选中项目工程,以此选择 “属性” --> “配置属性” --> “配置管理器” --> “活动解决方案平台”选择“新建”。这时,就会来到“新建解决方案平台”页面。我们选择“x64”,并从 Win32 中复制设置,创建新的项目平台,点击“确定”。这时,就可以使用 x64 模式编译 64 位程序了。

4.jpg

  • 然后,我们继续对 .asm 文件进行设置,将其包含到项目工程中来编译链接。选中“myasm.asm”文件,右击选择“属性”,来到“myasm.asm”属性页进行设置。在 命令行 中输入“ml64 /c %(fileName).asm”,在 输出 中输入“%(fileName).obj”,其它保持默认即可,点击“确定”即可完成设置。

5.jpg

经过上述 5 个步骤,我们成功为 x64 程序添加 .asm 文件并设置包含到项目工程中编译链接。接下来,我们就开始讲解如何在 .asm 文件中写汇编代码了。

实现原理

对于 64 位程序在 .asm 中写代码,需要遵循以下几个规则:

  • 1.会变文件 .asm 文件必须以关键字 .CODE 开始,关键字 END 结束,大小写都可以。
.code
    ; 此处写汇编指令代码
end
  • 2.所有的汇编代码以函数方式组织在一起。也就是说,我们要将汇编代码封装成一个个汇编函数。要注意 64 位汇编中的函数声明以及调用约定:
.code

; _MyAdd是汇编函数
_MyAdd    proc
    ; 此处写汇编函数的代码
_MyAdd    endp

end

其中, _MyAsm 是汇编函数的名称,proc 是汇编函数的关键字,endp 是汇编函数的结尾关键字。

要注意和 32 位汇编函数的区别:32 位汇编函数调用约定 __stdcall,所有参数从右到左依次入栈,通过压栈传递参数。64 位汇编函数的调用约定 __fastcall,前 4 个参数是从左至右依次存放于RCX、RDX、R8、R9寄存器里面,剩下的参数从左至右顺序入栈。

编码实现

myasm.asm

.code

_MyAdd    proc
    xor     rax, rax
    mov     rax, rcx
    add     rax, rdx
    add     rax, r8
    add     rax, r9
    ret
_MyAdd    endp

end

ASM_64_Test.cpp

extern "C" ULONGLONG _MyAdd(ULONGLONG a1, ULONGLONG a2, ULONGLONG a3, ULONGLONG a4);

int _tmain(int argc, _TCHAR* argv[])
{
    ULONGLONG a1 = 1;
    ULONGLONG a2 = 2;
    ULONGLONG a3 = 3;
    ULONGLONG a4 = 4;

    ULONGLONG b = _MyAdd(a1, a2, a3, a4);

    printf("b=%d\n", b);
    system("pause");
    return 0;
}

程序测试

我们直接运行程序,成功显示正确的计算结果:

6.jpg

然后,我们查看 RAX、RCX、RDX、R8、R9 这 5 个寄存器里的值,和上述我们讲解的相一致:

7.jpg

总结

要特别注意一点就是,如果你使用 VS2013 开发环境,或者你使用其它的开发环境也遇到这样一个问题就是:在 x64 模式下,添加 .asm 文件,并设置在 .asm 属性页 中设置“自定义生成工具”后,界面出现卡死、无反应现象。可以尝试下面的解决方法:

首先,不要在 x64 模式下面进行设置 .asm 属性页。更换到 x86 模式,即 Win32 模式下,然后再在 .asm 属性页 中设置“自定义生成工具”,这时可以正常设置。

然后,在在 .asm 属性页 中设置“自定义生成工具”,这时,我们再“新建” x64 的解决方案平台,从 Win32 中复制设置。

那么,这时,我们就可以在 x64 下正常对“自定义生成工具”进行设置了。

同时,也要要注意和 32 位汇编函数的区别:32 位汇编函数调用约定 __stdcall,所有参数从右到左依次入栈,通过压栈传递参数。64 位汇编函数的调用约定 __fastcall,前 4 个参数是从左至右依次存放于RCX、RDX、R8、R9寄存器里面,剩下的参数从左至右顺序入栈。

内容大纲
批注笔记
内联汇编(二)——内联汇编之64位程序
ArticleBot
z
z
z
z
主页
会议室
Git管理
文章
看板
留言墙