[英]Creating a Hello World library function in assembly and calling it from C#
Let's say we use NASM as they do in this answer: how to write hellow world in assembly under windows . 假设我们在这个答案中使用NASM: 如何在windows下的汇编中编写hellow world 。
I got a couple of thoughts and questions regarding assembly combined with c# or any other .net languages for that matter. 关于汇编,我得到了一些关于c#或任何其他.net语言的想法和问题。
First of all I want to be able to create a library that has the following function HelloWorld
that takes this parameter: 首先,我希望能够创建一个具有以下函数
HelloWorld
的库,该函数接受以下参数:
In C# the method signature would looke like this: void HelloWorld(string name)
and it would print out something like 在C#中,方法签名会像这样解释:
void HelloWorld(string name)
,它会打印出类似的东西
Hello World from name
Hello World来自名字
I've searched around a bit but can't find that much good and clean material for this to get me started. 我已经搜索了一下但是找不到那么好的和干净的材料让我开始。 I know some basic assembly from before mostly
gas
though. 我知道一些基本的装配,然后大多是
gas
。
So any pointers in the right direction is very much apprechiated. 因此,正确方向的任何指针都非常适用。
To sum it up 把它们加起来
Bonus features 奖金功能
When creating libraries in assembly or c, you do follow a certain "pre defined" way, the c calling convetion, correct? 在程序集或c中创建库时,您确实遵循某种“预定义”方式,即c调用对话,是否正确?
Something like this should get you a working DLL: 像这样的东西应该让你一个工作的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
You then just need to call the 'hello' function using P/Invoke. 然后你只需要使用P / Invoke调用'hello'函数。 It doesn't clean up after itself, so you need to set CallingConvention to Cdecl;
它不会自行清理,所以你需要将CallingConvention设置为Cdecl; you also need to tell it you're using ANSI strings.
你还需要告诉它你正在使用ANSI字符串。 Untested, but it should work fine.
未经测试,但它应该工作正常。
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_);
}
}
I will first cover basic guidelines for doing what you want.. then I will try to explain how to do the Hello World example. 我将首先介绍做你想做的基本指导。然后我将尝试解释如何做Hello World示例。
The first step would be writing a function, and making dll out of it. 第一步是编写一个函数,并从中创建dll。 Function in assembly should adhere to one of calling standards, stdcall is the most common one (you can read more about stdcall and other calling standards here ) An example of creating an dll with asm can be found here
程序集中的函数应该遵循一个调用标准,stdcall是最常见的一个(你可以在这里阅读更多关于stdcall和其他调用标准的内容)在这里可以找到用asm创建一个dll的例子
The second step would be to import the method in a managed language using P/Invoke. 第二步是使用P / Invoke以托管语言导入方法。 You can read more about it here
你可以在这里阅读更多相关信息
And that's it.. 就是这样......
Now for your mentioned example, you will need to make an asm function that takes all the input parameters and passes it to some other function that knows how to print to stdout (printf from standard c lib as mentioned above, or using winapi calls like here ) 现在,对于您提到的示例,您需要创建一个asm函数,它接受所有输入参数并将其传递给知道如何打印到stdout的其他函数(如上所述,从标准c lib中打印printf,或者使用像这里的 winapi调用)
After that you'll need to import the dll to C#, as described above. 之后,您需要将dll导入C#,如上所述。 Things you should take special care about are, character encoding for strings and clean up of data.
您应该特别注意的事项是字符串的字符编码和数据清理。 They are all mentioned in the 3rd link I provided (marshaling text section).
它们都在我提供的第3个链接中提到(编组文本部分)。
Bonus part: 奖金部分:
This is a very good question and deserves a vote from me. 这是一个非常好的问题,值得我投票。 In relation to your question, the only way this can be done as Cody has pointed out his assembler routine, is to build a DLL based on that, and from there to use p/Invoke using interops such as
关于你的问题,Cody指出他的汇编程序例程的唯一方法是基于它构建一个DLL,并从那里使用p / Invoke使用interops如
[DllImport("mylib.dll")]
etc. However, unfortunately, due to the nature of the C# or any other language for that matter, the CLR runtime environment is using the managed code. 但是,遗憾的是,由于C#或任何其他语言的性质,CLR运行时环境正在使用托管代码。 It would be awkward in having the CLR or the assembler to set up the stack frame, registers, then cross jumping from native world to the managed world.
让CLR或汇编程序设置堆栈框架,注册,然后从本地世界交叉跳转到托管世界会很尴尬。 That would be a hairy job to do, but if anyone has seen that kind of thing, please leave a comment at the end of my answer and I will amend this answer accordingly.
这将是一件毛茸茸的工作,但如果有人见过这样的事情,请在我的答案结尾留下评论,我会相应地修改这个答案。
And therefore, to my knowledge, there is no way to inline an assembler routine, by assembler, in that context, using system registers such as eax, ebx, stack frames etc, into a CLR code, just like the sample of code that Cody above has supplied in his answer. 因此,据我所知,没有办法通过汇编程序在汇编程序中内联汇编程序,使用系统寄存器(如eax,ebx,堆栈帧等)转换为CLR代码,就像Cody的代码示例一样以上提供了他的答案。 It would have held true with C/C++ in this case:
在这种情况下,它将适用于C / C ++:
void foo(void){ _asm{ xor ecx, ecx mov eax, 1 .... } }
It would be nice to do that from the CLR perspective like this in order to optimize code further, in theory at least but that would be an insurmountable job for the CLR to actually host that kind of thing like this, there is one exception... it can be done with Managed C++ compiler which can do this, but NOT from VB.NET/C# anyway: 从CLR的角度来看这样做会很好,以便进一步优化代码,至少在理论上这对于CLR实际托管这类事情是一个不可逾越的工作,有一个例外。它可以使用Managed C ++编译器来完成,但不能从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 } }
However, while on the subject, it can be done to generate IL code to native assembler, now, as I write this, I am not 100% sure if this can be done in the reverse, See here for a detailed description of how this can happen 然而,在这个主题上,可以完成生成IL代码到本地汇编程序,现在,正如我写的那样,我不是100%确定是否可以反向完成,请参阅此处以获取详细说明可以发生
But however, the only way of working on CLR assembly is handwriting the IL code and compiling it instead, that is, the assembler of the CLR runtime, directly, in very much the same way as native assembler can be called by native (read NON-CLR binaries), see this article here on how to accomplish this also. 但是 ,处理CLR程序集的唯一方法是手写IL代码并改为编译它,即直接编译CLR运行时的汇编程序,与本机汇编程序可以被本机调用的方式非常相似(读取NON)二进制-CLR),看到这个文章在这里就如何也做到这一点。
As I see it, your question is two-fold: 在我看来,你的问题是双重的:
The answer to 2 is to use P/Invoke. 2的答案是使用P / Invoke。 Lots of documentation and tutorials are available on that topic, eg http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
有关该主题的大量文档和教程,例如http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.