5

假设我们像在这个答案中那样使用 NASM:how to write hello world in assembly under windows

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

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

  • 姓名

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

来自名字的你好世界

我搜索了一下,但找不到那么多好的和干净的材料让我开始。不过,我主要知道以前的一些基本组装gas

因此,任何指向正确方向的指针都非常受欢迎。

把它们加起来

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

奖励功能

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

在汇编或 c 中创建库时,您确实遵循某种“预定义”方式,即 c 调用对流,对吗?

4

4 回答 4

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_);
    }
}
于 2010-05-18T11:24:09.677 回答
3

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

第一步是编写一个函数,并从中制作 dll。汇编中的函数应遵守其中一种调用标准,stdcall 是最常见的一种(您可以在此处阅读有关 stdcall 和其他调用标准的更多信息)使用 asm 创建 dll 的示例可以在此处找到

第二步是使用 P/Invoke 以托管语言导入方法。你可以在这里阅读更多关于它的信息

就是这样。。

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

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

奖金部分:

  • 返回值的处理取决于使用的调用约定
  • 用 C# 编写内联汇编是不可能的。但是,您可以使用托管 C++ 编写它们。
于 2010-05-18T11:38:44.140 回答
1

这是一个非常好的问题,值得我投票。关于您的问题,正如 Cody 指出他的汇编程序例程那样,这样做的唯一方法是在此基础上构建一个 DLL,然后从那里使用 p/Invoke 使用互操作,例如

[DllImport("mylib.dll")]

等等。然而,不幸的是,由于 C# 或任何其他语言的性质,CLR 运行时环境正在使用托管代码。让 CLR 或汇编器设置堆栈帧、寄存器,然后从本地世界交叉跳​​转到托管世界会很尴尬。那将是一项艰巨的工作,但是如果有人看到过这种事情,请在我的答案末尾发表评论,我会相应地修改此答案。

因此,据我所知,没有办法通过汇编程序在这种情况下使用 eax、ebx、堆栈帧等系统寄存器将汇编程序例程内联到 CLR 代码中,就像 Cody 的代码示例一样上面已经在他的回答中提供了。在这种情况下,对于 C/C++ 来说也是如此:

无效富(无效){
   _asm{
     异或 ecx, ecx
     移动 eax, 1
     ……
   }
}

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

私人无效mycsfunction(字符串s){
    // 托管代码
    StringBuilder sb = new StringBuilder(s);
    ……
    _asm{
        推送ebp
        mov ebp, esp
        lea edx, offset sb
        ……
        移动 eax, 1
        流行音乐
    }
}

然而,在这个主题上,可以将 IL 代码生成到本地汇编程序,现在,当我写这篇文章时,我不能 100% 确定这是否可以反过来完成,请参阅此处以获取有关如何执行此操作的详细说明可以发生

但是,处理 CLR 汇编的唯一方法是手写 IL 代码并对其进行编译,即直接使用 CLR 运行时的汇编程序,与本机汇编程序可以被本机调用非常相似(阅读 NON -CLR 二进制文件),请参阅此处的这篇文章,了解如何完成此操作。

于 2010-05-18T11:46:05.603 回答
0

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

  1. 如何使用程序集编写函数并将其放入 DLL 中?
  2. 如何从托管 C# 调用非托管 DLL 中的函数?

2 的答案是使用 P/Invoke。有很多关于该主题的文档和教程,例如http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

于 2010-05-18T11:28:32.380 回答