有时候在写C语言项目的时候会需要用到汇编代码直接操作寄存器、栈之类更加底层的东西,所以在这里写一下C和汇编混合编程的几种方法(Windows和Linux需要分开讨论)
Windows
Visual Studio
Windows下常用的开发环境是Visual Studio,对于x86来说vs默认支持内联汇编,直接通过__asm
关键词即可在函数体内嵌入汇编,例如
int add(int a, int b) {
__asm {
mov eax, a
mov ebx, b
add eax, ebx
}
}
int main() {
add(1, 2);
return 0;
}
直接编译是没有错误的,而且x86还支持通过__declspec(naked)
指定裸函数,正常的函数都是有函数序言和函数尾声的(即push ebp、pop ebp之类的),有时候我们并不需要这些东西,就可以声明裸函数,有我们自己来操控栈平衡
int __declspec(naked) add(int a, int b) {
__asm {
mov eax, a
mov ebx, b
add eax, ebx
ret
}
}
int main() {
add(1, 2);
return 0;
}
直接编译也没有任何问题
而且反编译来看确实没有乱七八糟的东西存在了。
但是从x64开始,VS就不再支持内联汇编了,而且也不支持naked关键字了。这里就可以切换项目的Platform Toolset为clang,clang默认支持x64内联汇编。Platform Toolset默认情况下是VS
点开来找到LLVM clang-cl
如果没有这个选项,可以打开vs安装工具,直接在单个组件里搜索LLVM,将两个组件都安装即可
然后直接切换为x64编译,是没有问题的
但是不支持裸函数。这里只能采取另一种方法,即额外创建一个asm,然后将asm文件链接到项目里。首先创建一个asm文件
extern mySub : PROC ; 引入C文件中的函数和全局变量
extern num : dw
.code
myAdd PROC
call mySub
mov ecx, dword ptr [num]
add eax, ecx
ret
myAdd ENDP
end
再创建一个C文件
extern int myAdd(int a, int b); // 引入汇编文件中的函数
int num = 0;
int mySub(int a, int b) {
return a - b;
}
int main() {
myAdd(1, 2);
return 0;
}
可以看到两者之间互相引用是通过extern关键字来实现的。然后设置汇编文件的属性
再General中设置Item Type为自定义构建工具,点击应用后再去自定构建工具的General中设置如下两个东西
一个是命令行,一个是输出路径
ml64 $(InDir)%(fileName).obj /c %(fileName).asm
$(InDir)%(fileName).obj;$(Outputs)
注意这里Platform Toolset设置为默认的vs或者clang-cl都可以,直接编译可以看到没有报错
同时在反汇编中可以看到我们用汇编编写的函数
这种混合编程x86也适用,只不过需要将ml64改为ml
Clion
我个人更喜欢用Clion来编写C项目,这里Toolchains用的是VS的。x86内联汇编不说了,默认支持,主要来看x64的配置。如果要实现内联汇编,需要设置Toolchains为clang
这里clang-cl可以是vs的,也可以是另外安装的,然后添加CMake的选项让cmake用clang-cl编译
编译是没有问题的
如果要用混合编程,即创建一个asm文件链接到项目里,首先在CMakeLists.txt添加以下内容
主要是为了让cmake开启ASM_MASM支持,然后在Cmake设置选项,指定CMAKE_ASM_MASM_COMPILE为ml64
然后编译就没有任何问题
标签:汇编,int,clang,混合,编译,add,asm From: https://www.cnblogs.com/musing/p/17920246.html