views:

140

answers:

4

Let's say we use NASM as they do in this answer: how to write hellow world in assembly under windows.

I got a couple of thoughts and questions regarding assembly combined with c# or any other .net languages for that matter.

First of all I want to be able to create a library that has the following function HelloWorld that takes this parameter:

  • Name

In C# the method signature would looke like this: void HelloWorld(string name) and it would print out something like

Hello World from name

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 gasthough.

So any pointers in the right direction is very much apprechiated.

To sum it up

  • Create a routine in ASM ( NASM ) that takes one or more parameters
  • Compile and create a library of the above functionality
  • Include the library in any .net language
  • Call the included library function

Bonus features

  • How does one handle returned values?
  • Is it possible to write the ASM-method inline?

When creating libraries in assembly or c, you do follow a certain "pre defined" way, the c calling convetion, correct?

+9  A: 

Something like this should get you a working 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. It doesn't clean up after itself, so you need to set CallingConvention to Cdecl; you also need to tell it you're using ANSI strings. 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_);
    }
}
Cody Brocious
Cdecl stores the return value in `eax` right? So it would be fairly easy to adjust the ASM to return the string instead of (cheating ;) ) calling printf?
Filip Ekberg
Sure, you just need to allocate memory for the string, concatenate the passed value with the static string, and return that value in eax.
Cody Brocious
A: 

As I see it, your question is two-fold:

  1. How do I write a function using assembly and put it in a DLL?
  2. How do I call a function in an unmanaged DLL from managed C#?

The answer to 2 is to use P/Invoke. Lots of documentation and tutorials are available on that topic, e.g. http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

MEMark
I am asking for a step-by-step example on how to solve this.
Filip Ekberg
+3  A: 

I will first cover basic guidelines for doing what you want.. then I will try to explain how to do the Hello World example.

The first step would be writing a function, and making dll out of it. 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

The second step would be to import the method in a managed language using 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)

After that you'll need to import the dll to C#, as described above. 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).

Bonus part:

  • Handling of returned values depends on the calling conventions used
  • It is not possible to write inline assembly with C#. However you can write them with Managed C++.
Ivan
+1  A: 

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

[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. 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. 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. It would have held true with C/C++ in this case:

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:

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

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.

tommieb75
Interesting.. I wonder if that inline-asm is somewhat possible in managed c++ ?
Filip Ekberg
You can indeed use inline assembler in C++/CLI, although /when/ you can use it is complicated. I use it to patch several functions in a binary I inject into using EasyHook, but mixing inline assembly and managed code is difficult. I'd strongly suggest against it unless you have no other choice.On another note, there is a library to allow you to embed native code into the JITC'd code for MS.NET, but I can't recall the name.
Cody Brocious