如何在 C# 中调用 x64 汇编过程
How to call a x64 Assembly procedure in C#
我正在做一个项目,目前有以下结构:
- 包含用户界面以及对外部方法的调用的 C# WPF 项目。
- 包含算法的 C++ DLL 项目。
- 包含算法的 ASM DLL 项目。
为简单起见,我们假设算法不使用任何参数,returns两个预定义数字的总和。
C++(第二个)项目中的函数签名和实现如下:
int Add(int x, int y)
{
return x + y;
}
extern "C" __declspec(dllexport) int RunCpp()
{
int x = 1, y = 2;
int z = Add(x, y);
return z;
}
下面是我在 C# 中调用该函数的方式:
[DllImport("Algorithm.Cpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int RunCpp();
这工作得很好 - 在 C# 中调用函数 returns 值 3,一切正常,没有抛出异常。
但是,我现在正在努力用 C# 代码调用 ASM 过程。
我已经看到(并在一定程度上测试了自己)不可能在 C# 代码中直接调用 MASM DLL。但是,我听说可以在 C++ 中调用 ASM 并在 C# 中调用该函数。
1. 我的第一个问题是 - 在 C# 中是否可以直接调用 ASM 代码?当我尝试这样做时,我得到一个异常,基本上说二进制代码不兼容。
2.我试过用C++间接调用ASM DLL,虽然没有异常,但是返回值是“随机的”,感觉像是剩下的余数内存,例如:-7514271。这是我做错了什么,还是有其他方法可以做到这一点?
C++中调用ASM的代码如下:
typedef int(__stdcall* f_MyProc1)(DWORD, DWORD);
extern "C" __declspec(dllexport) int RunAsm()
{
HINSTANCE hGetProcIDDLL = LoadLibrary(L"Algorithm.Asm.dll");
if (hGetProcIDDLL == NULL)
{
return 0;
}
f_MyProc1 MyProc1 = (f_MyProc1)GetProcAddress(hGetProcIDDLL, "MyProc1");
if (!MyProc1)
{
return 0;
}
int x = 1, y = 2;
int z = MyProc1(x, y);
FreeLibrary(hGetProcIDDLL);
return z;
}
这里是C#中调用C++的代码:
[DllImport("Algorithm.Cpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int RunAsm();
如果需要,这里是 MyProc1
的 ASM 代码:
Main.asm:
MyProc1 proc x: DWORD, y: DWORD
mov EAX, x
mov ECX, y
add EAX, ECX
ret
MyProc1 endp
Main.def:
LIBRARY Main
EXPORTS MyProc1
is calling ASM code actually possible directly in C#?
此示例有两个项目,C# 和基于程序集的 DLL。看起来您已经知道如何使基于 C++ 的 DLL 正常工作。项目名称与目录名称相同,C# 为 xcs,dll 为 xcadll。我从空目录开始并创建空项目,然后将源文件移动到目录中,然后将现有项目添加到每个项目。
xcadll 属性:
Configuration Type: Dynamic Library (.dll)
Linker | Input: xcadll.def
xcadll\xcadll.def:
LIBRARY xcadll
EXPORTS DllMain
EXPORTS Example
xcadll\xa.asm 属性(对于发布版本,不需要 /Zi):
General | Excluded From Build: No
General | Item Type: Custom Build Tool
Custom Build Tool | General | Command Line: ml64 /c /Zi /Fo$(OutDir)\xa.obj xa.asm
Custom Build Tool | General | Outputs: $(OutDir)\xa.obj
xcadll\xa.asm:
includelib msvcrtd
includelib oldnames ;optional
.data
.data?
.code
public DllMain
public Example
DllMain proc ;return true
mov rax, 1
ret 0
DllMain endp
Example proc ;[rcx] = 0123456789abcdefh
mov rax, 0123456789abcdefh
mov [rcx],rax
ret 0
Example endp
end
xcs\Program.cs:
using System;
using System.Runtime.InteropServices;
namespace xcadll
{
class Program
{
[DllImport("c:\xcadll\x64\release\xcadll.dll")]
static extern void Example(ulong[] data);
static void Main(string[] args)
{
ulong[] data = new ulong[4] {0,0,0,0};
Console.WriteLine("{0:X16}", data[0]);
Example(data);
Console.WriteLine("{0:X16}", data[0]);
return;
}
}
}
对于调试,使用
[DllImport("c:\xcadll\x64\debug\xcadll.dll")]
xcs 属性 |调试 |启用本机模式调试(选中复选框)
我正在做一个项目,目前有以下结构:
- 包含用户界面以及对外部方法的调用的 C# WPF 项目。
- 包含算法的 C++ DLL 项目。
- 包含算法的 ASM DLL 项目。
为简单起见,我们假设算法不使用任何参数,returns两个预定义数字的总和。
C++(第二个)项目中的函数签名和实现如下:
int Add(int x, int y)
{
return x + y;
}
extern "C" __declspec(dllexport) int RunCpp()
{
int x = 1, y = 2;
int z = Add(x, y);
return z;
}
下面是我在 C# 中调用该函数的方式:
[DllImport("Algorithm.Cpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int RunCpp();
这工作得很好 - 在 C# 中调用函数 returns 值 3,一切正常,没有抛出异常。
但是,我现在正在努力用 C# 代码调用 ASM 过程。 我已经看到(并在一定程度上测试了自己)不可能在 C# 代码中直接调用 MASM DLL。但是,我听说可以在 C++ 中调用 ASM 并在 C# 中调用该函数。
1. 我的第一个问题是 - 在 C# 中是否可以直接调用 ASM 代码?当我尝试这样做时,我得到一个异常,基本上说二进制代码不兼容。
2.我试过用C++间接调用ASM DLL,虽然没有异常,但是返回值是“随机的”,感觉像是剩下的余数内存,例如:-7514271。这是我做错了什么,还是有其他方法可以做到这一点?
C++中调用ASM的代码如下:
typedef int(__stdcall* f_MyProc1)(DWORD, DWORD);
extern "C" __declspec(dllexport) int RunAsm()
{
HINSTANCE hGetProcIDDLL = LoadLibrary(L"Algorithm.Asm.dll");
if (hGetProcIDDLL == NULL)
{
return 0;
}
f_MyProc1 MyProc1 = (f_MyProc1)GetProcAddress(hGetProcIDDLL, "MyProc1");
if (!MyProc1)
{
return 0;
}
int x = 1, y = 2;
int z = MyProc1(x, y);
FreeLibrary(hGetProcIDDLL);
return z;
}
这里是C#中调用C++的代码:
[DllImport("Algorithm.Cpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int RunAsm();
如果需要,这里是 MyProc1
的 ASM 代码:
Main.asm:
MyProc1 proc x: DWORD, y: DWORD
mov EAX, x
mov ECX, y
add EAX, ECX
ret
MyProc1 endp
Main.def:
LIBRARY Main
EXPORTS MyProc1
is calling ASM code actually possible directly in C#?
此示例有两个项目,C# 和基于程序集的 DLL。看起来您已经知道如何使基于 C++ 的 DLL 正常工作。项目名称与目录名称相同,C# 为 xcs,dll 为 xcadll。我从空目录开始并创建空项目,然后将源文件移动到目录中,然后将现有项目添加到每个项目。
xcadll 属性:
Configuration Type: Dynamic Library (.dll)
Linker | Input: xcadll.def
xcadll\xcadll.def:
LIBRARY xcadll
EXPORTS DllMain
EXPORTS Example
xcadll\xa.asm 属性(对于发布版本,不需要 /Zi):
General | Excluded From Build: No
General | Item Type: Custom Build Tool
Custom Build Tool | General | Command Line: ml64 /c /Zi /Fo$(OutDir)\xa.obj xa.asm
Custom Build Tool | General | Outputs: $(OutDir)\xa.obj
xcadll\xa.asm:
includelib msvcrtd
includelib oldnames ;optional
.data
.data?
.code
public DllMain
public Example
DllMain proc ;return true
mov rax, 1
ret 0
DllMain endp
Example proc ;[rcx] = 0123456789abcdefh
mov rax, 0123456789abcdefh
mov [rcx],rax
ret 0
Example endp
end
xcs\Program.cs:
using System;
using System.Runtime.InteropServices;
namespace xcadll
{
class Program
{
[DllImport("c:\xcadll\x64\release\xcadll.dll")]
static extern void Example(ulong[] data);
static void Main(string[] args)
{
ulong[] data = new ulong[4] {0,0,0,0};
Console.WriteLine("{0:X16}", data[0]);
Example(data);
Console.WriteLine("{0:X16}", data[0]);
return;
}
}
}
对于调试,使用
[DllImport("c:\xcadll\x64\debug\xcadll.dll")]
xcs 属性 |调试 |启用本机模式调试(选中复选框)