内联汇编

什么是内联汇编

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

x86 内联汇编

使用内联汇编要用到 __asm 关键字,它可以出现在任何允许 C/C++ 语句出现的地方。对 __asm 关键字的使用有两种方式:

// 1.
__asm
 {
   // 汇编代码
 }

// 2.
__asm // 汇编代码

显然,第一种方法与 C/C++ 的风格很一致,并且把汇编代码和 C/C++ 代码清楚地分开,还避免了重复输入 __asm 关键字,因此推荐使用第一种方法。

不像在 C/C++ 中的“{ }”,__asm 块的“{ }”不会影响 C/C++ 变量的作用范围。同时,__asm 块可以嵌套,而且嵌套也不会影响变量的作用范围。

为了与低版本的 Visual C++ 兼容,_asm 和 __asm 具有相同的意义。另外,Visual C++ 支持标准 C++ 的 asm 关键字,但是它不会生成任何指令,它的作用仅限于使编译器不会出现编译错误。要使用内联汇编,必须使用 __asm 而不是 asm 关键字。

例子:

void MyFunc(char *pszText)
{
    printf("%s\n", pszText);
}
int _tmain(int argc, _TCHAR* argv[])
{
    char str1[] = "__asm{ }";
    char str2[] = "__asm";
    
    // 32位程序内联汇编 第一种方式
    __asm
    {
        	lea       eax, str1
            push      eax
            mov       eax, MyFunc
            call      eax
    }
    
    // 32位程序内联汇编 第二种方式
    __asm lea     eax, str2
    __asm push    eax
    __asm mov     eax, MyFunc
    __asm call    eax

    system("pause");
    return 0;
}

效果图:
在这里插入图片描述


x64 内联汇编

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

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

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

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

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

在这里插入图片描述

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


对于 64 位程序在 .asm 中写代码,需要遵循以下几个规则:
会变文件 .asm 文件必须以关键字 .CODE 开始,关键字 END 结束,大小写都可以。

.code
    ; 此处写汇编指令代码
end

所有的汇编代码以函数方式组织在一起。也就是说,我们要将汇编代码封装成一个个汇编函数。要注意 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

(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;
}

效果图:
在这里插入图片描述

展开阅读全文
©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值