C# 在汇编中创建Hello World库函数并从C调用它#
假设我们使用NASM,就像他们在这个答案中所做的那样: 关于汇编与c#或任何其他.net语言的结合,我有一些想法和问题 首先,我希望能够创建一个库,该库具有以下函数C# 在汇编中创建Hello World库函数并从C调用它#,c#,.net,vb.net,assembly,inline-assembly,C#,.net,Vb.net,Assembly,Inline Assembly,假设我们使用NASM,就像他们在这个答案中所做的那样: 关于汇编与c#或任何其他.net语言的结合,我有一些想法和问题 首先,我希望能够创建一个库,该库具有以下函数HelloWorld,该函数接受此参数: 名字 在C#中,方法签名看起来是这样的:void HelloWorld(字符串名),它会打印出如下内容 你好,世界从名字开始 我已经搜索了一些,但找不到那么多好的和干净的材料,让我开始。不过,我以前知道一些基本组件,主要是气体 因此,任何指向正确方向的指针都是非常正确的 总而言之 在AS
HelloWorld
,该函数接受此参数:
- 名字
void HelloWorld(字符串名)
,它会打印出如下内容
你好,世界从名字开始
我已经搜索了一些,但找不到那么多好的和干净的材料,让我开始。不过,我以前知道一些基本组件,主要是气体
因此,任何指向正确方向的指针都是非常正确的
总而言之
- 在ASM(NASM)中创建接受一个或多个参数的例程
- 编译并创建上述功能的库
- 包括任何.net语言的库
- 调用包含的库函数
- 如何处理返回的值
- 是否可以内联编写ASM方法
在汇编或c中创建库时,确实要遵循某种“预定义”的方式,即c调用转换,对吗?类似这样的操作应该会为您提供一个工作DLL:
extern _printf
section .text
global _hello
_hello:
push ebp
mov ebp, esp
mov eax, [ebp+12]
push eax
push helloWorld
call _printf
add esp, 8
pop ebp
ret
export _hello
helloWorld: db 'Hello world from %s', 10, 0
然后只需要使用p/Invoke调用“hello”函数。它本身不会清理,所以需要将CallingConvention设置为Cdecl;您还需要告诉它您正在使用ANSI字符串。未经测试,但应该可以正常工作
using System.Runtime.InteropServices;
namespace Test {
public class Test {
public static Main() {
Hello("C#");
}
[DllImport("test.dll", EntryPoint="hello", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
public static extern Hello(string from_);
}
}
在我看来,你的问题有两个方面:
2的答案是使用p/Invoke。关于这个主题有很多文档和教程,例如,我将首先介绍做你想做的事情的基本指南。。然后,我将尝试解释如何执行Hello World示例 第一步是编写一个函数,并用它生成dll。汇编中的函数应遵循其中一种调用标准,stdcall是最常见的标准(您可以阅读有关stdcall和其他调用标准的更多信息)。可以找到使用asm创建dll的示例 第二步是使用p/Invoke以托管语言导入方法。你可以阅读更多关于它的内容 就这样 现在,对于前面提到的示例,您需要创建一个asm函数,该函数接受所有输入参数,并将其传递给其他知道如何打印到stdout的函数(如上所述,printf来自标准c库,或者使用类似winapi的调用) 之后,您需要将dll导入到C#,如上所述。您应该特别注意的是字符串的字符编码和数据清理。它们都在我提供的第三个链接(封送文本部分)中提到 奖金部分:
- 返回值的处理取决于 关于使用的调用约定
- 无法使用C#编写内联程序集。但是,你可以用C++编写它们。
- 这是一个非常好的问题,值得我投票表决。关于你的问题,正如Cody所指出的那样,唯一可以做到这一点的方法是基于此构建一个DLL,然后使用互操作使用p/Invoke,比如
[DllImport("mylib.dll")]
[DllImport(“mylib.dll”)]
然而,不幸的是,由于C#或任何其他语言的性质,CLR运行时环境正在使用托管代码。如果让CLR或汇编程序设置堆栈框架、寄存器,然后从本机世界交叉跳转到托管世界,那将很尴尬。这将是一项艰巨的工作,但如果有人看到过这种情况,请在我的答案末尾留下评论,我将相应地修改这个答案
因此,据我所知,汇编程序无法使用系统寄存器(如eax、ebx、堆栈帧等)将汇编程序例程内联到CLR代码中,就像上面Cody在回答中提供的代码示例一样。在这种情况下,C/C++也适用:
void foo(void){
_asm{
xor ecx, ecx
mov eax, 1
....
}
}
无效foo(无效){
_asm{
异或ecx,ecx
mov-eax,1
....
}
}
从CLR的角度来看,这样做是很好的,以便进一步优化代码,至少在理论上是这样的,但对于CLR来说,这将是一项不可克服的工作,以实际承载类似这样的事情,有一个例外。。。它可以通过管理C++编译器来完成,但是可以从VB.NET/C中得到<强> > > >:
私有void mycsfunction(字符串s){
//托管代码
StringBuilder sb=新的StringBuilder;
......
_asm{
推ebp
电动汽车
lea edx,offset某人
....
mov-eax,1
流行ebp
}
}
然而,在这个主题上,可以为本机汇编程序生成IL代码,现在,在我写这篇文章的时候,我不能100%确定是否可以反过来生成IL代码,有关如何实现的详细描述,请参阅
但是,处理CLR汇编的唯一方法是手写IL代码并编译它,即直接使用CLR运行时的汇编程序,就像本机可以调用本机汇编程序一样(读取非CLR二进制文件),关于如何实现这一点,请参阅本文。Cdecl将返回值存储在
中,对吗?因此,调整ASM以返回字符串而不是(作弊;))调用printf是相当容易的?当然,您只需要为字符串分配内存,将传递的值与静态字符串连接起来,然后在eax.interest中返回该值。。我想知道,在管理C++中,内联ASM是否有可能? private void mycsfunction(string s){ // Managed code ahoy StringBuilder sb = new StringBuilder(s); ...... _asm{ push ebp mov ebp, esp lea edx, offset sb .... mov eax, 1 pop ebp } }eax