Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在汇编中创建Hello World库函数并从C调用它#_C#_.net_Vb.net_Assembly_Inline Assembly - Fatal编程技术网

C# 在汇编中创建Hello World库函数并从C调用它#

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

假设我们使用NASM,就像他们在这个答案中所做的那样:

关于汇编与c#或任何其他.net语言的结合,我有一些想法和问题

首先,我希望能够创建一个库,该库具有以下函数
HelloWorld
,该函数接受此参数:

  • 名字
在C#中,方法签名看起来是这样的:
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_);
    }
}

在我看来,你的问题有两个方面:

  • 如何使用汇编编写函数并将其放入DLL中
  • 如何从托管C#调用非托管DLL中的函数

  • 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将返回值存储在
        eax
        中,对吗?因此,调整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 } }