在程序集中创建Hello World库函数并从C#调用它

时间:2010-05-18 11:10:46

标签: c# .net vb.net assembly inline-assembly

假设我们在答案中使用NASM:how to write hellow world in assembly under windows

关于汇编和c#或任何其他.net语言,我得到了一些想法和问题。

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

  • 名称

在C#中,方法签名会像这样:void HelloWorld(string name),它会打印出类似

的内容
  

Hello World来自 name

我已经搜索了一下但是找不到那么好的和干净的材料让我开始。我之前知道一些基本的程序集gas

所以任何指向正确方向的指针都非常适用。

总结

  • 在ASM(NASM)中创建一个带有一个或多个参数的例程
  • 编译并创建上述功能的库
  • 以任何.net语言包含库
  • 调用附带的库函数

奖金功能

  • 如何处理返回的值?
  • 是否可以内联编写ASM方法?

在程序集或c中创建库时,您是否遵循某种“预定义”方式,即c调用对话,是否正确?

4 个答案:

答案 0 :(得分:11)

这样的事情会让你找到一个可用的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_);
    }
}

答案 1 :(得分:3)

我将首先介绍做你想做的事情的基本指导原则。然后我将尝试解释如何做Hello World示例。

第一步是编写一个函数,并从中创建dll。汇编中的函数应该遵循一个调用标准,stdcall是最常见的一个(你可以阅读更多关于stdcall和其他调用标准的here)可以找到用asm创建一个dll的例子here

第二步是使用P / Invoke以托管语言导入方法。您可以阅读更多相关信息here

就是这样......

现在,对于您提到的示例,您需要创建一个asm函数,该函数接受所有输入参数并将其传递给知道如何打印到stdout的其他函数(如上所述,从标准c lib中打印printf,或使用winapi)调用here

之后,您需要将dll导入C#,如上所述。您应该特别注意的事项是字符串的字符编码和数据清理。它们都在我提供的第3个链接中提到(编组文本部分)。

奖金部分:

  • 返回值的处理取决于 关于使用的调用约定
  • 无法使用C#编写内联汇编。但是,您可以使用Managed C ++编写它们。

答案 2 :(得分:1)

这是一个非常好的问题,值得我投票。关于你的问题,Cody指出他的汇编程序例程的唯一方法就是基于它构建DLL,并从那里使用p / Invoke使用诸如

之类的interop
[DllImport("mylib.dll")]

等。但是,遗憾的是,由于C#或任何其他语言的性质,CLR运行时环境正在使用托管代码。让CLR或汇编程序设置堆栈框架,注册,然后从本地世界交叉跳​​转到托管世界会很尴尬。这将是一件毛茸茸的工作,但如果有人见过这样的事情,请在我的答案结束时发表评论,我会相应地修改这个答案。

因此,据我所知,没有办法通过汇编程序在汇编程序中使用系统寄存器(如eax,ebx,堆栈帧等)将一个汇编程序内联到CLR代码中,就像样本一样。 Cody上面提供的代码在他的回答中提供。在这种情况下,它将适用于C / C ++:

void foo(void){
   _asm{
     xor ecx, ecx
     mov eax, 1
     ....
   }
}

从CLR的角度来看这样做会很好,以便进一步优化代码,至少在理论上这对CLR实际托管这样的事情是一个不可逾越的工作,有一个异常......可以使用Managed C ++编译器完成此操作,但无论如何 NOT 来自VB.NET / C#:

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
    }
}

然而,在这个主题上,可以将IL代码生成到本机汇编程序,现在,正如我写的那样,我不能100%确定是否可以反过来这样做,请参阅here有关如何发生这种情况的详细说明

但是然而,处理CLR程序集的唯一方法是手写IL代码并改为编译它,即直接编译CLR运行时的汇编程序,其方式与本机汇编程序可以由本机调用(读取NON-CLR二进制文件),请参阅本文here,了解如何完成此操作。

答案 3 :(得分:0)

在我看来,你的问题是双重的:

  1. 如何使用程序集编写函数并将其放入DLL?
  2. 如何从托管C#中调用非托管DLL中的函数?
  3. 2的答案是使用P / Invoke。有关该主题的大量文档和教程可用,例如: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx