0%

汇编语言与C语言混合编程(1)

前言

有时候某些特殊的功能,需要我们使用汇编语言来实现,但是又没必要整个项目都用汇编语言,
所以使用汇编语言与C语言混合编程就成了最佳选择。

代码嵌入

在32位环境下,我们可以直接在C语言代码中嵌入汇编代码进行编程,这里不再专门说明。

1
2
3
4
5
6
7
8
int myadd(int a, int b)
{
int c = 0;
_asm mov eax, a;
_asm add eax, b;
_asm mov c, eax;
return c;
} // 在C中直接嵌入ASM

合并文件

由于在64位环境下,无法直接在C语言代码中嵌入汇编代码,所以需要单独编写汇编文件,
编译成obj文件再与C语言进行合并。

在VS中,我们使用 ml.exe 和 ml64.exe 来单独编译 .asm 汇编代码文件。

在VS的 解决方案管理器 里,直接在 asm 文件上 右键 选择 属性 项

asm文件属性

通常情况下 配置属性 里只有一个 常规 选项,在其中的 项类型 里修改为 自定义生成工具

自定义生成工具

点击 应用 之后,在 配置属性 里会多出 自定义生成工具 选项,我们在 命令行 和 输出 里添加指令

指令

在32位环境下的命令行(asm文件在i386asm目录下):

1
ml /Fo $(IntDir)%(fileName).obj /c i386asm\%(fileName).asm

在64位环境下的命令行(asm文件在amd64asm目录下):

1
ml64 /Fo $(IntDir)%(fileName).obj /c amd64asm\%(fileName).asm

输出项对应的指令:

1
$(IntDir)%(fileName).obj;%(Outputs)

示例代码

在32位环境下的asm示例代码,以及对应的函数声明

1
2
extern "C" int _cdecl mysub(int x, int y);
extern "C" int _stdcall myadd(int x, int y);
1
2
3
4
5
6
7
8
9
10
11
12
13
;flat(平坦模式) c(C调用) stdcall(STD调用)
.model flat, c
.code
mysub proc
push ebp
mov ebp, esp
mov eax, [ebp + 8]
sub eax, [ebp + 12]
mov esp, ebp
pop ebp
ret
mysub endp
end
1
2
3
4
5
6
7
8
9
10
11
12
13
;flat(平坦模式) c(C调用) stdcall(STD调用)
.model flat, stdcall
.code
;stdcall需要标明参数来确定调用名(_myadd@8)
myadd proc, x:dword, y:dword
;编译器自动添加push ebp
;编译器自动添加mov ebp, esp
mov eax, x
add eax, y
;编译器自动添加leave
ret 8
myadd endp
end

在64位环境下的asm示例代码,以及对应的函数声明

1
2
// x64汇编只有fastcall方式,并且与x86的fastcall不同
extern "C" long long myadd64(long long a, long long b);
1
2
3
4
5
6
7
.code
myadd64 proc
mov rax, rcx
add rax, rdx
ret
myadd64 endp
end

DDK环境

在VS中无论编译应用程序,还是编译驱动程序,统一都是使用上述方法。

在DDK环境中编译驱动时,则是在source文件中增加文件包含:

1
2
3
4
I386_SOURCES=\
test32.asm ;编译32位驱动文件
AMD64_SOURCES=\
test64.asm ;编译64位驱动文件